From 9309e10eb5044ba9c06c9c622b15a168a063d2f9 Mon Sep 17 00:00:00 2001 From: Pursche Date: Sun, 18 Aug 2024 21:28:58 +0200 Subject: [PATCH 01/11] Add UI reference size and fix Font issues --- Source/Renderer/Renderer.lua | 2 +- .../Renderer/Renderer/Descriptors/FontDesc.h | 4 +-- Source/Renderer/Renderer/Font.cpp | 35 ++++++++++++++++++- Source/Renderer/Renderer/Font.h | 10 ++++-- Source/Renderer/Renderer/RenderSettings.h | 4 +++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Source/Renderer/Renderer.lua b/Source/Renderer/Renderer.lua index ea973070..ca8b9d67 100644 --- a/Source/Renderer/Renderer.lua +++ b/Source/Renderer/Renderer.lua @@ -1,4 +1,4 @@ -local mod = Solution.Util.CreateModuleTable("Renderer", { "base", "shadercooker", "tracyprofiler", "imgui", "gli", "typesafe" }) +local mod = Solution.Util.CreateModuleTable("Renderer", { "base", "shadercooker", "tracyprofiler", "imgui", "gli", "typesafe", "utfcpp" }) Solution.Util.CreateStaticLib(mod.Name, Solution.Projects.Current.BinDir, mod.Dependencies, function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } diff --git a/Source/Renderer/Renderer/Descriptors/FontDesc.h b/Source/Renderer/Renderer/Descriptors/FontDesc.h index b9b9c47b..d2b77126 100644 --- a/Source/Renderer/Renderer/Descriptors/FontDesc.h +++ b/Source/Renderer/Renderer/Descriptors/FontDesc.h @@ -8,7 +8,7 @@ namespace Renderer struct FontDesc { std::string path = ""; - float size = 0.0f; - int padding = 3; + f32 size = 0.0f; + i32 padding = 5; }; } \ No newline at end of file diff --git a/Source/Renderer/Renderer/Font.cpp b/Source/Renderer/Renderer/Font.cpp index 82c233c4..39dcce7d 100644 --- a/Source/Renderer/Renderer/Font.cpp +++ b/Source/Renderer/Renderer/Font.cpp @@ -9,6 +9,7 @@ #include #include +#include #undef CreateFont @@ -84,7 +85,7 @@ namespace Renderer bool Font::InitChar(u32 character, FontChar& fontChar) { - fontChar.data = stbtt_GetCodepointSDF(fontInfo, scale, character, desc.padding, 128, 64.0f, &fontChar.width, &fontChar.height, &fontChar.xOffset, &fontChar.yOffset); + fontChar.data = stbtt_GetCodepointSDF(fontInfo, scale, character, desc.padding, 180, 36.0f, &fontChar.width, &fontChar.height, &fontChar.xOffset, &fontChar.yOffset); if (fontChar.width == 0 && fontChar.height == 0) return false; @@ -117,6 +118,8 @@ namespace Renderer font->scale = stbtt_ScaleForPixelHeight(font->fontInfo, fontSize); + stbtt_GetFontVMetrics(font->fontInfo, &font->ascent, &font->descent, &font->lineGap); + // Create texture array TextureArrayDesc desc; desc.size = 4096; @@ -133,6 +136,11 @@ namespace Renderer } } + // Get the space gap + int advance; + stbtt_GetCodepointHMetrics(font->fontInfo, ' ', &advance, NULL); + font->spaceGap = advance * font->scale; + return font; } @@ -140,4 +148,29 @@ namespace Renderer { return _textureArray; } + + vec2 Font::CalculateTextSize(const std::string& text) + { + utf8::iterator it(text.begin(), text.begin(), text.end()); + utf8::iterator endIt(text.end(), text.begin(), text.end()); + + vec2 size = vec2(0, 0); + for (; it != endIt; it++) + { + u32 c = *it; + + if (c == ' ') + { + size.x += spaceGap; + continue; + } + + FontChar& fontChar = GetChar(c); + + size.x += fontChar.advance; + size.y = std::max(size.y, static_cast(fontChar.height)); + } + + return size; + } } \ No newline at end of file diff --git a/Source/Renderer/Renderer/Font.h b/Source/Renderer/Renderer/Font.h index 9d03c412..947b48b3 100644 --- a/Source/Renderer/Renderer/Font.h +++ b/Source/Renderer/Renderer/Font.h @@ -26,15 +26,21 @@ namespace Renderer struct Font { - static constexpr char* FALLBACK_FONT_PATH = (char*)"Data/fonts/Ubuntu/Ubuntu-Regular.ttf"; + static constexpr char* FALLBACK_FONT_PATH = (char*)"Data/Fonts/Ubuntu-Regular.ttf"; FontDesc desc; stbtt_fontinfo* fontInfo; - float scale; + + f32 scale; + i32 ascent; + i32 descent; + i32 lineGap; + f32 spaceGap; FontChar& GetChar(u32 character); TextureArrayID GetTextureArray(); + vec2 CalculateTextSize(const std::string& text); static Font* GetDefaultFont(Renderer* renderer, f32 fontSize); static Font* GetFont(Renderer* renderer, const std::string& fontPath, f32 fontSize); diff --git a/Source/Renderer/Renderer/RenderSettings.h b/Source/Renderer/Renderer/RenderSettings.h index 2ee10a65..f84aea3e 100644 --- a/Source/Renderer/Renderer/RenderSettings.h +++ b/Source/Renderer/Renderer/RenderSettings.h @@ -10,6 +10,10 @@ namespace Renderer public: static const u32 SCREEN_WIDTH = 1920; static const u32 SCREEN_HEIGHT = 1080; + + static const u32 UI_REFERENCE_WIDTH = 1920; + static const u32 UI_REFERENCE_HEIGHT = 1080; + static const size_t STAGING_BUFFER_SIZE = 32 * 1024 * 1024; // 32 MB static const u32 MAX_SHADOW_CASCADES = 8; From 2c0f7ea2f1e00d40d5ed2455df6c3a11ec85a155 Mon Sep 17 00:00:00 2001 From: Pursche Date: Thu, 12 Sep 2024 09:16:33 +0200 Subject: [PATCH 02/11] Add leftSideBearing and improve SDF font settings --- Source/Renderer/Renderer/Font.cpp | 7 +++++-- Source/Renderer/Renderer/Font.h | 1 + .../Renderer/Renderers/Vulkan/Backend/SwapChainVK.h | 2 +- Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/Renderer/Renderer/Font.cpp b/Source/Renderer/Renderer/Font.cpp index 39dcce7d..36b6b975 100644 --- a/Source/Renderer/Renderer/Font.cpp +++ b/Source/Renderer/Renderer/Font.cpp @@ -85,14 +85,17 @@ namespace Renderer bool Font::InitChar(u32 character, FontChar& fontChar) { - fontChar.data = stbtt_GetCodepointSDF(fontInfo, scale, character, desc.padding, 180, 36.0f, &fontChar.width, &fontChar.height, &fontChar.xOffset, &fontChar.yOffset); + // We need to investigate the on edge value (192) and the pixel distance scale (32.0f) further + fontChar.data = stbtt_GetCodepointSDF(fontInfo, scale, character, desc.padding, 192, 32.0f, &fontChar.width, &fontChar.height, &fontChar.xOffset, &fontChar.yOffset); if (fontChar.width == 0 && fontChar.height == 0) return false; int advance; - stbtt_GetCodepointHMetrics(fontInfo, character, &advance, NULL); + int leftSideBearing; + stbtt_GetCodepointHMetrics(fontInfo, character, &advance, &leftSideBearing); fontChar.advance = advance * scale; + fontChar.leftSideBearing = leftSideBearing * scale; DataTextureDesc textureDesc; textureDesc.width = fontChar.width; diff --git a/Source/Renderer/Renderer/Font.h b/Source/Renderer/Renderer/Font.h index 947b48b3..497d8194 100644 --- a/Source/Renderer/Renderer/Font.h +++ b/Source/Renderer/Renderer/Font.h @@ -15,6 +15,7 @@ namespace Renderer struct FontChar { f32 advance; + f32 leftSideBearing; i32 xOffset; i32 yOffset; i32 width = 0; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h index 393e02a6..71695b53 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h +++ b/Source/Renderer/Renderer/Renderers/Vulkan/Backend/SwapChainVK.h @@ -126,7 +126,7 @@ namespace Renderer VkSurfaceKHR surface; VkSwapchainKHR swapChain; - inline static const u32 FRAME_BUFFER_COUNT = 2; + static const u32 FRAME_BUFFER_COUNT = 2; FrameResource imageIDs; FrameResource imageAvailableSemaphores; FrameResource blitFinishedSemaphores; diff --git a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp index c5529ccd..b5904f48 100644 --- a/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp +++ b/Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp @@ -1152,12 +1152,12 @@ namespace Renderer { VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer(commandListID); tracy::VkCtxManualScope*& tracyScope = _commandListHandler->GetTracyScope(commandListID); - + if (tracyScope != nullptr) { NC_LOG_CRITICAL("Tried to begin GPU trace on a commandlist that already had a begun GPU trace"); } - + tracyScope = new tracy::VkCtxManualScope(_device->_tracyContext, sourceLocation, true); tracyScope->Start(commandBuffer); #endif @@ -1171,12 +1171,12 @@ namespace Renderer { VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer(commandListID); tracy::VkCtxManualScope*& tracyScope = _commandListHandler->GetTracyScope(commandListID); - + if (tracyScope == nullptr) { NC_LOG_CRITICAL("Tried to end GPU trace on a commandlist that didn't have a running trace"); } - + tracyScope->End(); delete tracyScope; tracyScope = nullptr; From dee0bdb2c7fd96710d1c194f6e5adfec52e21be7 Mon Sep 17 00:00:00 2001 From: Pursche Date: Thu, 12 Sep 2024 09:16:50 +0200 Subject: [PATCH 03/11] Update Luau --- .../Analysis/include/Luau/AnyTypeSummary.h | 5 +- .../Analysis/include/Luau/DataFlowGraph.h | 6 +- .../Luau/Analysis/include/Luau/Subtyping.h | 1 + .../luau/Luau/Analysis/include/Luau/Type.h | 13 +- .../Luau/Analysis/include/Luau/TypeFunction.h | 5 + .../luau/Luau/Analysis/src/AnyTypeSummary.cpp | 19 +- .../luau/Luau/Analysis/src/AstJsonEncoder.cpp | 33 +- .../Luau/Analysis/src/BuiltinDefinitions.cpp | 22 +- .../Luau/Analysis/src/ConstraintGenerator.cpp | 203 ++++++--- .../Luau/Analysis/src/ConstraintSolver.cpp | 21 +- .../luau/Luau/Analysis/src/DataFlowGraph.cpp | 35 +- .../luau/Luau/Analysis/src/Frontend.cpp | 12 +- .../luau/Luau/Analysis/src/Instantiation.cpp | 30 +- .../luau/Luau/Analysis/src/Normalize.cpp | 40 +- .../Luau/Analysis/src/OverloadResolution.cpp | 11 +- .../luau/Luau/Analysis/src/Simplify.cpp | 12 +- .../luau/Luau/Analysis/src/Substitution.cpp | 30 +- .../luau/Luau/Analysis/src/Subtyping.cpp | 21 + .../Analysis/src/TableLiteralInference.cpp | 4 + .../luau/Luau/Analysis/src/ToString.cpp | 5 +- .../luau/Luau/Analysis/src/TypeChecker2.cpp | 62 ++- .../luau/Luau/Analysis/src/TypeFunction.cpp | 175 +++++--- .../luau/Luau/Analysis/src/TypeInfer.cpp | 80 +--- Dependencies/luau/Luau/Ast/src/Parser.cpp | 146 +++--- Dependencies/luau/Luau/Ast/src/TimeTrace.cpp | 4 +- Dependencies/luau/Luau/VM/src/ldo.cpp | 18 +- Dependencies/luau/Luau/VM/src/lperf.cpp | 4 +- Dependencies/luau/Luau/VM/src/lstate.h | 2 +- .../luau/Luau/tests/AnyTypeSummary.test.cpp | 105 ++++- .../luau/Luau/tests/AstJsonEncoder.test.cpp | 8 - .../luau/Luau/tests/AstQuery.test.cpp | 2 + Dependencies/luau/Luau/tests/Fixture.h | 1 + Dependencies/luau/Luau/tests/Linter.test.cpp | 4 + .../luau/Luau/tests/Normalize.test.cpp | 24 +- Dependencies/luau/Luau/tests/Parser.test.cpp | 7 - .../luau/Luau/tests/Subtyping.test.cpp | 37 +- Dependencies/luau/Luau/tests/ToDot.test.cpp | 6 +- .../luau/Luau/tests/ToString.test.cpp | 79 +++- .../luau/Luau/tests/TypeFunction.test.cpp | 13 +- .../Luau/tests/TypeInfer.aliases.test.cpp | 76 +++- .../Luau/tests/TypeInfer.builtins.test.cpp | 82 +++- .../Luau/tests/TypeInfer.classes.test.cpp | 96 +++- .../Luau/tests/TypeInfer.definitions.test.cpp | 4 - .../Luau/tests/TypeInfer.functions.test.cpp | 421 +++++++++++++----- .../TypeInfer.intersectionTypes.test.cpp | 143 ++++-- .../luau/Luau/tests/TypeInfer.loops.test.cpp | 118 ++++- .../Luau/tests/TypeInfer.modules.test.cpp | 22 +- .../luau/Luau/tests/TypeInfer.oop.test.cpp | 15 +- .../Luau/tests/TypeInfer.operators.test.cpp | 185 +++++--- .../Luau/tests/TypeInfer.primitives.test.cpp | 25 +- .../Luau/tests/TypeInfer.provisional.test.cpp | 135 ++++-- .../Luau/tests/TypeInfer.refinements.test.cpp | 184 ++++++-- .../Luau/tests/TypeInfer.singletons.test.cpp | 54 ++- .../luau/Luau/tests/TypeInfer.tables.test.cpp | 5 +- .../luau/Luau/tests/TypeInfer.test.cpp | 55 ++- .../Luau/tests/TypeInfer.tryUnify.test.cpp | 8 + .../Luau/tests/TypeInfer.typePacks.test.cpp | 85 +++- .../Luau/tests/TypeInfer.unionTypes.test.cpp | 112 +++-- .../tests/TypeInfer.unknownnever.test.cpp | 24 +- Dependencies/luau/Luau/tools/faillist.txt | 239 ---------- .../luau/{Version-0.638 => Version-0.639} | 0 Dependencies/luau/luau.lua | 21 +- 62 files changed, 2173 insertions(+), 1241 deletions(-) rename Dependencies/luau/{Version-0.638 => Version-0.639} (100%) diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/AnyTypeSummary.h b/Dependencies/luau/Luau/Analysis/include/Luau/AnyTypeSummary.h index 73d6f851..d99eea84 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/AnyTypeSummary.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/AnyTypeSummary.h @@ -72,7 +72,7 @@ struct AnyTypeSummary std::optional lookupPackAnnotation(AstTypePack* annotation, const Module* module); TypeId checkForTypeFunctionInhabitance(const TypeId instance, const Location location); - enum Pattern: uint64_t + enum Pattern : uint64_t { Casts, FuncArg, @@ -82,7 +82,8 @@ struct AnyTypeSummary VarAny, TableProp, Alias, - Assign + Assign, + TypePk }; struct TypeInfo diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/DataFlowGraph.h b/Dependencies/luau/Luau/Analysis/include/Luau/DataFlowGraph.h index 2a894bc9..a84561dd 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/DataFlowGraph.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/DataFlowGraph.h @@ -184,9 +184,9 @@ struct DataFlowGraphBuilder DataFlowResult visitExpr(DfgScope* scope, AstExprInterpString* i); DataFlowResult visitExpr(DfgScope* scope, AstExprError* error); - void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment = false); - DefId visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment); - DefId visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment); + void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef); + DefId visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef); + DefId visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef); diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h b/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h index a3f199f3..01f1a7ab 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h @@ -207,6 +207,7 @@ struct Subtyping SubtypingResult isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass); SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const ClassType* subClass, TypeId superTy, const TableType* superTable); SubtypingResult isCovariantWith(SubtypingEnvironment& env, const FunctionType* subFunction, const FunctionType* superFunction); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim); SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable); SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable); diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Type.h b/Dependencies/luau/Luau/Analysis/include/Luau/Type.h index 585c2493..2b2cb960 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Type.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Type.h @@ -594,10 +594,21 @@ struct TypeFunctionInstanceType std::vector typeArguments; std::vector packArguments; - TypeFunctionInstanceType(NotNull function, std::vector typeArguments, std::vector packArguments) + std::optional userFuncName; // Name of the user-defined type function; only available for UDTFs + std::optional userFuncBody; // Body of the user-defined type function; only available for UDTFs + + TypeFunctionInstanceType( + NotNull function, + std::vector typeArguments, + std::vector packArguments, + std::optional userFuncName = std::nullopt, + std::optional userFuncBody = std::nullopt + ) : function(function) , typeArguments(typeArguments) , packArguments(packArguments) + , userFuncName(userFuncName) + , userFuncBody(userFuncBody) { } diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/TypeFunction.h b/Dependencies/luau/Luau/Analysis/include/Luau/TypeFunction.h index ad7b92ef..c686f482 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/TypeFunction.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/TypeFunction.h @@ -32,6 +32,9 @@ struct TypeFunctionContext // The constraint being reduced in this run of the reduction const Constraint* constraint; + std::optional userFuncName; // Name of the user-defined type function; only available for UDTFs + std::optional userFuncBody; // Body of the user-defined type function; only available for UDTFs + TypeFunctionContext(NotNull cs, NotNull scope, NotNull constraint) : arena(cs->arena) , builtins(cs->builtinTypes) @@ -156,6 +159,8 @@ struct BuiltinTypeFunctions { BuiltinTypeFunctions(); + TypeFunction userFunc; + TypeFunction notFunc; TypeFunction lenFunc; TypeFunction unmFunc; diff --git a/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp b/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp index c5e8e8c6..4ff2051b 100644 --- a/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp +++ b/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp @@ -136,6 +136,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module* const Scope* retScope = findInnerMostScope(ret->location, module); auto ctxNode = getNode(rootSrc, ret); + bool seenTP = false; for (auto val : ret->list) { @@ -160,7 +161,23 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module* typeInfo.push_back(ti); } } + + if (ret->list.size > 1 && !seenTP) + { + if (containsAny(retScope->returnType)) + { + seenTP = true; + + TelemetryTypePair types; + + types.inferredType = toString(retScope->returnType); + + TypeInfo ti{Pattern::TypePk, toString(ctxNode), types}; + typeInfo.push_back(ti); + } + } } + } void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module* module, NotNull builtinTypes) @@ -189,7 +206,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module typeInfo.push_back(ti); } } - + const AstExprTypeAssertion* maybeRequire = local->values.data[posn]->as(); if (!maybeRequire) continue; diff --git a/Dependencies/luau/Luau/Analysis/src/AstJsonEncoder.cpp b/Dependencies/luau/Luau/Analysis/src/AstJsonEncoder.cpp index ceeee73c..fd90a6ee 100644 --- a/Dependencies/luau/Luau/Analysis/src/AstJsonEncoder.cpp +++ b/Dependencies/luau/Luau/Analysis/src/AstJsonEncoder.cpp @@ -8,8 +8,6 @@ #include -LUAU_FASTFLAG(LuauDeclarationExtraPropData) - namespace Luau { @@ -898,19 +896,11 @@ struct AstJsonEncoder : public AstVisitor { // TODO: attributes PROP(name); - - if (FFlag::LuauDeclarationExtraPropData) - PROP(nameLocation); - + PROP(nameLocation); PROP(params); - - if (FFlag::LuauDeclarationExtraPropData) - { - PROP(paramNames); - PROP(vararg); - PROP(varargLocation); - } - + PROP(paramNames); + PROP(vararg); + PROP(varargLocation); PROP(retTypes); PROP(generics); PROP(genericPacks); @@ -926,10 +916,7 @@ struct AstJsonEncoder : public AstVisitor [&]() { PROP(name); - - if (FFlag::LuauDeclarationExtraPropData) - PROP(nameLocation); - + PROP(nameLocation); PROP(type); } ); @@ -940,16 +927,10 @@ struct AstJsonEncoder : public AstVisitor writeRaw("{"); bool c = pushComma(); write("name", prop.name); - - if (FFlag::LuauDeclarationExtraPropData) - write("nameLocation", prop.nameLocation); - + write("nameLocation", prop.nameLocation); writeType("AstDeclaredClassProp"); write("luauType", prop.ty); - - if (FFlag::LuauDeclarationExtraPropData) - write("location", prop.location); - + write("location", prop.location); popComma(c); writeRaw("}"); } diff --git a/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp b/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp index 082d79e8..e565f6bf 100644 --- a/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp +++ b/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp @@ -374,9 +374,25 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC if (TableType* ttv = getMutable(getGlobalBinding(globals, "table"))) { - // tabTy is a generic table type which we can't express via declaration syntax yet - ttv->props["freeze"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.freeze"); - ttv->props["clone"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.clone"); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // CLI-114044 - The new solver does not yet support generic tables, + // which act, in an odd way, like generics that are constrained to + // the top table type. We do the best we can by modelling these + // functions using unconstrained generics. It's not quite right, + // but it'll be ok for now. + TypeId genericTy = arena.addType(GenericType{"T"}); + TypePackId thePack = arena.addTypePack({genericTy}); + TypeId idTy = arena.addType(FunctionType{{genericTy}, {}, thePack, thePack}); + ttv->props["freeze"] = makeProperty(idTy, "@luau/global/table.freeze"); + ttv->props["clone"] = makeProperty(idTy, "@luau/global/table.clone"); + } + else + { + // tabTy is a generic table type which we can't express via declaration syntax yet + ttv->props["freeze"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.freeze"); + ttv->props["clone"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.clone"); + } ttv->props["getn"].deprecated = true; ttv->props["getn"].deprecatedSuggestion = "#"; diff --git a/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp b/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp index 036f4313..ba2d1beb 100644 --- a/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp @@ -29,7 +29,6 @@ LUAU_FASTINT(LuauCheckRecursionLimit); LUAU_FASTFLAG(DebugLuauLogSolverToJson); LUAU_FASTFLAG(DebugLuauMagicTypes); -LUAU_FASTFLAG(LuauDeclarationExtraPropData); namespace Luau { @@ -271,6 +270,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block) TypeId domainTy = builtinTypes->neverType; for (TypeId d : domain) { + d = follow(d); if (d == ty) continue; domainTy = simplifyUnion(builtinTypes, arena, domainTy, d).result; @@ -549,6 +549,13 @@ bool mustDeferIntersection(TypeId ty) } } // namespace +enum RefinementsOpKind +{ + Intersect, + Refine, + None +}; + void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement) { if (!refinement) @@ -557,6 +564,23 @@ void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location locat RefinementContext refinements; std::vector constraints; computeRefinement(scope, location, refinement, &refinements, /*sense*/ true, /*eq*/ false, &constraints); + auto flushConstraints = [this, &scope, &location](RefinementsOpKind kind, TypeId ty, std::vector& discriminants) + { + if (discriminants.empty()) + return ty; + if (kind == RefinementsOpKind::None) + { + LUAU_ASSERT(false); + return ty; + } + std::vector args = {ty}; + const TypeFunction& func = kind == RefinementsOpKind::Intersect ? builtinTypeFunctions().intersectFunc : builtinTypeFunctions().refineFunc; + LUAU_ASSERT(!func.name.empty()); + args.insert(args.end(), discriminants.begin(), discriminants.end()); + TypeId resultType = createTypeFunctionInstance(func, args, {}, scope, location); + discriminants.clear(); + return resultType; + }; for (auto& [def, partition] : refinements) { @@ -565,41 +589,52 @@ void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location locat TypeId ty = *defTy; if (partition.shouldAppendNilType) ty = arena->addType(UnionType{{ty, builtinTypes->nilType}}); - // Intersect ty with every discriminant type. If either type is not // sufficiently solved, we queue the intersection up via an // IntersectConstraint. - + // For each discriminant ty, we accumulated it onto ty, creating a longer and longer + // sequence of refine constraints. On every loop of this we called mustDeferIntersection. + // For sufficiently large types, we would blow the stack. + // Instead, we record all the discriminant types in sequence + // and then dispatch a single refine constraint with multiple arguments. This helps us avoid + // the potentially expensive check on mustDeferIntersection + std::vector discriminants; + RefinementsOpKind kind = RefinementsOpKind::None; + bool mustDefer = mustDeferIntersection(ty); for (TypeId dt : partition.discriminantTypes) { - if (mustDeferIntersection(ty) || mustDeferIntersection(dt)) + mustDefer = mustDefer || mustDeferIntersection(dt); + if (mustDefer) { - TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().refineFunc, {ty, dt}, {}, scope, location); + if (kind == RefinementsOpKind::Intersect) + ty = flushConstraints(kind, ty, discriminants); + kind = RefinementsOpKind::Refine; - ty = resultType; + discriminants.push_back(dt); } else { - switch (shouldSuppressErrors(normalizer, ty)) - { - case ErrorSuppression::DoNotSuppress: + ErrorSuppression status = shouldSuppressErrors(normalizer, ty); + if (status == ErrorSuppression::NormalizationFailed) + reportError(location, NormalizationTooComplex{}); + if (kind == RefinementsOpKind::Refine) + ty = flushConstraints(kind, ty, discriminants); + kind = RefinementsOpKind::Intersect; + + discriminants.push_back(dt); + + if (status == ErrorSuppression::Suppress) { - if (!get(follow(ty))) - ty = makeIntersect(scope, location, ty, dt); - break; - } - case ErrorSuppression::Suppress: - ty = makeIntersect(scope, location, ty, dt); + ty = flushConstraints(kind, ty, discriminants); ty = makeUnion(scope, location, ty, builtinTypes->errorType); - break; - case ErrorSuppression::NormalizationFailed: - reportError(location, NormalizationTooComplex{}); - ty = makeIntersect(scope, location, ty, dt); - break; } } } + // Finalize - if there are any discriminants left, make one big constraint for refining them + if (kind != RefinementsOpKind::None) + ty = flushConstraints(kind, ty, discriminants); + scope->rvalueRefinements[def] = ty; } } @@ -663,6 +698,51 @@ ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& sco astTypeAliasDefiningScopes[alias] = defnScope; aliasDefinitionLocations[alias->name.value] = alias->location; } + else if (auto function = stat->as()) + { + // If a type function w/ same name has already been defined, error for having duplicates + if (scope->exportedTypeBindings.count(function->name.value) || scope->privateTypeBindings.count(function->name.value)) + { + auto it = aliasDefinitionLocations.find(function->name.value); + LUAU_ASSERT(it != aliasDefinitionLocations.end()); + reportError(function->location, DuplicateTypeDefinition{function->name.value, it->second}); + continue; + } + + ScopePtr defnScope = childScope(function, scope); + + // Create TypeFunctionInstanceType + + std::vector typeParams; + typeParams.reserve(function->body->args.size); + + std::vector quantifiedTypeParams; + quantifiedTypeParams.reserve(function->body->args.size); + + for (size_t i = 0; i < function->body->args.size; i++) + { + std::string name = format("T%zu", i); + TypeId ty = arena->addType(GenericType{name}); + typeParams.push_back(ty); + + GenericTypeDefinition genericTy{ty}; + quantifiedTypeParams.push_back(genericTy); + } + + TypeId typeFunctionTy = arena->addType(TypeFunctionInstanceType{ + NotNull{&builtinTypeFunctions().userFunc}, + std::move(typeParams), + {}, + function->name, + function->body, + }); + + TypeFun typeFunction{std::move(quantifiedTypeParams), typeFunctionTy}; + + // Set type bindings and definition locations for this user-defined type function + scope->privateTypeBindings[function->name.value] = std::move(typeFunction); + aliasDefinitionLocations[function->name.value] = function->location; + } } std::optional firstControlFlow; @@ -1368,6 +1448,20 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeAlias* ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunction* function) { + // If a type function with the same name was already defined, we skip over + auto bindingIt = scope->privateTypeBindings.find(function->name.value); + if (bindingIt == scope->privateTypeBindings.end()) + return ControlFlow::None; + + TypeFun typeFunction = bindingIt->second; + + // Adding typeAliasExpansionConstraint on user-defined type function for the constraint solver + if (auto typeFunctionTy = get(typeFunction.type)) + { + TypeId expansionTy = arena->addType(PendingExpansionType{{}, function->name, typeFunctionTy->typeArguments, typeFunctionTy->packArguments}); + addConstraint(scope, function->location, TypeAliasExpansionConstraint{/* target */ expansionTy}); + } + return ControlFlow::None; } @@ -1472,17 +1566,14 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas ftv->hasSelf = true; - if (FFlag::LuauDeclarationExtraPropData) - { - FunctionDefinition defn; + FunctionDefinition defn; - defn.definitionModuleName = module->name; - defn.definitionLocation = prop.location; - // No data is preserved for varargLocation - defn.originalNameLocation = prop.nameLocation; + defn.definitionModuleName = module->name; + defn.definitionLocation = prop.location; + // No data is preserved for varargLocation + defn.originalNameLocation = prop.nameLocation; - ftv->definition = defn; - } + ftv->definition = defn; } } @@ -1490,12 +1581,9 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas if (props.count(propName) == 0) { - if (FFlag::LuauDeclarationExtraPropData) - props[propName] = {propTy, /*deprecated*/ false, /*deprecatedSuggestion*/ "", prop.location}; - else - props[propName] = {propTy}; + props[propName] = {propTy, /*deprecated*/ false, /*deprecatedSuggestion*/ "", prop.location}; } - else if (FFlag::LuauDeclarationExtraPropData) + else { Luau::Property& prop = props[propName]; TypeId currentTy = prop.type(); @@ -1523,31 +1611,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas reportError(declaredClass->location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())}); } } - else - { - TypeId currentTy = props[propName].type(); - - // We special-case this logic to keep the intersection flat; otherwise we - // would create a ton of nested intersection types. - if (const IntersectionType* itv = get(currentTy)) - { - std::vector options = itv->parts; - options.push_back(propTy); - TypeId newItv = arena->addType(IntersectionType{std::move(options)}); - - props[propName] = {newItv}; - } - else if (get(currentTy)) - { - TypeId intersection = arena->addType(IntersectionType{{currentTy, propTy}}); - - props[propName] = {intersection}; - } - else - { - reportError(declaredClass->location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())}); - } - } } return ControlFlow::None; @@ -1581,13 +1644,10 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareFunc FunctionDefinition defn; - if (FFlag::LuauDeclarationExtraPropData) - { - defn.definitionModuleName = module->name; - defn.definitionLocation = global->location; - defn.varargLocation = global->vararg ? std::make_optional(global->varargLocation) : std::nullopt; - defn.originalNameLocation = global->nameLocation; - } + defn.definitionModuleName = module->name; + defn.definitionLocation = global->location; + defn.varargLocation = global->vararg ? std::make_optional(global->varargLocation) : std::nullopt; + defn.originalNameLocation = global->nameLocation; TypeId fnType = arena->addType(FunctionType{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack, defn}); FunctionType* ftv = getMutable(fnType); @@ -1929,7 +1989,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExpr* expr, std:: Inference result; if (auto group = expr->as()) - result = check(scope, group->expr, expectedType, forceSingleton); + result = check(scope, group->expr, expectedType, forceSingleton, generalize); else if (auto stringExpr = expr->as()) result = check(scope, stringExpr, expectedType, forceSingleton); else if (expr->is()) @@ -2128,6 +2188,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexExpr* in { if (auto constantString = indexExpr->index->as()) { + module->astTypes[indexExpr->index] = builtinTypes->stringType; const RefinementKey* key = dfg->getRefinementKey(indexExpr); return checkIndexName(scope, key, indexExpr->expr, constantString->value.data, indexExpr->location); } @@ -2945,7 +3006,13 @@ TypeId ConstraintGenerator::resolveType(const ScopePtr& scope, AstType* ty, bool } else if (p.typePack) { - packParameters.push_back(resolveTypePack(scope, p.typePack, /* inTypeArguments */ true)); + TypePackId tp = resolveTypePack(scope, p.typePack, /*inTypeArguments*/ true); + + // If we need more regular types, we can use single element type packs to fill those in + if (parameters.size() < alias->typeParams.size() && size(tp) == 1 && finite(tp) && first(tp)) + parameters.push_back(*first(tp)); + else + packParameters.push_back(tp); } else { diff --git a/Dependencies/luau/Luau/Analysis/src/ConstraintSolver.cpp b/Dependencies/luau/Luau/Analysis/src/ConstraintSolver.cpp index 9cc8ef38..ae02c60a 100644 --- a/Dependencies/luau/Luau/Analysis/src/ConstraintSolver.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ConstraintSolver.cpp @@ -924,6 +924,10 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul return true; } + // Adding ReduceConstraint on type function for the constraint solver + if (auto typeFn = get(follow(tf->type))) + pushConstraint(NotNull(constraint->scope.get()), constraint->location, ReduceConstraint{tf->type}); + // If there are no parameters to the type function we can just use the type // directly. if (tf->typeParams.empty() && tf->typePackParams.empty()) @@ -1051,7 +1055,6 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul // there are e.g. generic saturatedTypeArguments that go unused. const TableType* tfTable = getTableType(tf->type); - //clang-format off bool needsClone = follow(tf->type) == target || (tfTable != nullptr && tfTable == getTableType(target)) || std::any_of( typeArguments.begin(), @@ -1061,7 +1064,6 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul return other == target; } ); - //clang-format on // Only tables have the properties we're trying to set. TableType* ttv = getMutableTableType(target); @@ -1269,6 +1271,8 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNulllocation); InstantiationQueuer queuer{constraint->scope, constraint->location, this}; queuer.traverse(overloadToUse); @@ -1279,6 +1283,14 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNullas()) + expr = group->expr; + + return expr; +} + bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull constraint) { TypeId fn = follow(c.fn); @@ -1352,7 +1364,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNullargs.data[i]; + const AstExpr* expr = unwrapGroup(c.callSite->args.data[i]); (*c.astExpectedTypes)[expr] = expectedArgTy; @@ -1695,7 +1707,10 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNullwriteTy.has_value()) + { + bind(constraint, c.propType, builtinTypes->anyType); return true; + } bind(constraint, c.propType, *prop->writeTy); unify(constraint, rhsType, *prop->writeTy); diff --git a/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp b/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp index 57e45c3e..73c2193c 100644 --- a/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp +++ b/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp @@ -570,15 +570,8 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatAssign* a) ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatCompoundAssign* c) { - // TODO: This needs revisiting because this is incorrect. The `c->var` part is both being read and written to, - // but the `c->var` only has one pointer address, so we need to come up with a way to store both. - // For now, it's not important because we don't have type states, but it is going to be important, e.g. - // - // local a = 5 -- a-1 - // a += 5 -- a-2 = a-1 + 5 - // We can't just visit `c->var` as a rvalue and then separately traverse `c->var` as an lvalue, since that's O(n^2). - DefId def = visitExpr(scope, c->value).def; - visitLValue(scope, c->var, def, /* isCompoundAssignment */ true); + (void) visitExpr(scope, c->value); + (void) visitExpr(scope, c->var); return ControlFlow::None; } @@ -920,14 +913,14 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprError* er return {defArena->freshCell(), nullptr}; } -void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment) +void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef) { auto go = [&]() { if (auto l = e->as()) - return visitLValue(scope, l, incomingDef, isCompoundAssignment); + return visitLValue(scope, l, incomingDef); else if (auto g = e->as()) - return visitLValue(scope, g, incomingDef, isCompoundAssignment); + return visitLValue(scope, g, incomingDef); else if (auto i = e->as()) return visitLValue(scope, i, incomingDef); else if (auto i = e->as()) @@ -941,15 +934,8 @@ void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomi graph.astDefs[e] = go(); } -DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment) +DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef) { - // We need to keep the previous def around for a compound assignment. - if (isCompoundAssignment) - { - DefId def = lookup(scope, l->local); - graph.compoundAssignDefs[l] = def; - } - // In order to avoid alias tracking, we need to clip the reference to the parent def. if (scope->canUpdateDefinition(l->local)) { @@ -962,15 +948,8 @@ DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId return visitExpr(scope, static_cast(l)).def; } -DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment) +DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef) { - // We need to keep the previous def around for a compound assignment. - if (isCompoundAssignment) - { - DefId def = lookup(scope, g->name); - graph.compoundAssignDefs[g] = def; - } - // In order to avoid alias tracking, we need to clip the reference to the parent def. if (scope->canUpdateDefinition(g->name)) { diff --git a/Dependencies/luau/Luau/Analysis/src/Frontend.cpp b/Dependencies/luau/Luau/Analysis/src/Frontend.cpp index a8ae99d5..f40b3e0e 100644 --- a/Dependencies/luau/Luau/Analysis/src/Frontend.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Frontend.cpp @@ -37,7 +37,6 @@ LUAU_FASTINT(LuauTypeInferRecursionLimit) LUAU_FASTINT(LuauTarjanChildLimit) LUAU_FASTFLAG(LuauInferInNoCheckMode) LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false) -LUAU_FASTFLAGVARIABLE(LuauCancelFromProgress, false) LUAU_FASTFLAGVARIABLE(LuauStoreCommentsForDefinitionFiles, false) LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false) @@ -745,15 +744,8 @@ std::vector Frontend::checkQueuedModules( if (progress) { - if (FFlag::LuauCancelFromProgress) - { - if (!progress(buildQueueItems.size() - remaining, buildQueueItems.size())) - cancelled = true; - } - else - { - progress(buildQueueItems.size() - remaining, buildQueueItems.size()); - } + if (!progress(buildQueueItems.size() - remaining, buildQueueItems.size())) + cancelled = true; } // Items cannot be submitted while holding the lock diff --git a/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp b/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp index 8422d8c4..0c610aba 100644 --- a/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp @@ -11,15 +11,12 @@ #include LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) -LUAU_FASTFLAG(LuauReusableSubstitutions) namespace Luau { void Instantiation::resetState(const TxnLog* log, TypeArena* arena, NotNull builtinTypes, TypeLevel level, Scope* scope) { - LUAU_ASSERT(FFlag::LuauReusableSubstitutions); - Substitution::resetState(log, arena); this->builtinTypes = builtinTypes; @@ -71,26 +68,13 @@ TypeId Instantiation::clean(TypeId ty) clone.argNames = ftv->argNames; TypeId result = addType(std::move(clone)); - if (FFlag::LuauReusableSubstitutions) - { - // Annoyingly, we have to do this even if there are no generics, - // to replace any generic tables. - reusableReplaceGenerics.resetState(log, arena, builtinTypes, level, scope, ftv->generics, ftv->genericPacks); - - // TODO: What to do if this returns nullopt? - // We don't have access to the error-reporting machinery - result = reusableReplaceGenerics.substitute(result).value_or(result); - } - else - { - // Annoyingly, we have to do this even if there are no generics, - // to replace any generic tables. - ReplaceGenerics replaceGenerics{log, arena, builtinTypes, level, scope, ftv->generics, ftv->genericPacks}; + // Annoyingly, we have to do this even if there are no generics, + // to replace any generic tables. + reusableReplaceGenerics.resetState(log, arena, builtinTypes, level, scope, ftv->generics, ftv->genericPacks); - // TODO: What to do if this returns nullopt? - // We don't have access to the error-reporting machinery - result = replaceGenerics.substitute(result).value_or(result); - } + // TODO: What to do if this returns nullopt? + // We don't have access to the error-reporting machinery + result = reusableReplaceGenerics.substitute(result).value_or(result); asMutable(result)->documentationSymbol = ty->documentationSymbol; return result; @@ -112,8 +96,6 @@ void ReplaceGenerics::resetState( const std::vector& genericPacks ) { - LUAU_ASSERT(FFlag::LuauReusableSubstitutions); - Substitution::resetState(log, arena); this->builtinTypes = builtinTypes; diff --git a/Dependencies/luau/Luau/Analysis/src/Normalize.cpp b/Dependencies/luau/Luau/Analysis/src/Normalize.cpp index 088b74b1..8935a476 100644 --- a/Dependencies/luau/Luau/Analysis/src/Normalize.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Normalize.cpp @@ -2186,6 +2186,11 @@ void Normalizer::intersectClasses(NormalizedClassType& heres, const NormalizedCl if (isSubclass(thereTy, hereTy)) { + // If thereTy is a subtype of hereTy, we need to replace hereTy + // by thereTy and combine their negation lists. + // + // If any types in the negation list are not subtypes of + // thereTy, they need to be removed from the negation list. TypeIds negations = std::move(hereNegations); for (auto nIt = negations.begin(); nIt != negations.end();) @@ -2209,22 +2214,45 @@ void Normalizer::intersectClasses(NormalizedClassType& heres, const NormalizedCl } else if (isSubclass(hereTy, thereTy)) { + // If thereTy is a supertype of hereTy, we need to extend the + // negation list of hereTy by that of thereTy. + // + // If any of the types of thereTy's negations are not subtypes + // of hereTy, they must not be added to hereTy's negation list. + // + // If any of the types of thereTy's negations are supertypes of + // hereTy, then hereTy must be removed entirely. + // + // If any of the types of thereTy's negations are supertypes of + // the negations of herety, the former must supplant the latter. TypeIds negations = thereNegations; + bool erasedHere = false; + for (auto nIt = negations.begin(); nIt != negations.end();) { - if (!isSubclass(*nIt, hereTy)) + if (isSubclass(hereTy, *nIt)) { - nIt = negations.erase(nIt); + // eg SomeClass & (class & ~SomeClass) + // or SomeClass & (class & ~ParentClass) + heres.classes.erase(hereTy); + it = heres.ordering.erase(it); + erasedHere = true; + break; } + + // eg SomeClass & (class & ~Unrelated) + if (!isSubclass(*nIt, hereTy)) + nIt = negations.erase(nIt); else - { ++nIt; - } } - unionClasses(hereNegations, negations); - break; + if (!erasedHere) + { + unionClasses(hereNegations, negations); + ++it; + } } else if (hereTy == thereTy) { diff --git a/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp b/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp index 9aad142d..612f4ad2 100644 --- a/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp +++ b/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp @@ -230,15 +230,18 @@ std::pair OverloadResolver::checkOverload_ // function arguments are options, then this function call // is ok. - const size_t firstUnsatisfiedArgument = argExprs->size(); - const auto [requiredHead, _requiredTail] = flatten(fn->argTypes); + const size_t firstUnsatisfiedArgument = args->head.size(); + const auto [requiredHead, requiredTail] = flatten(fn->argTypes); + + bool isVariadic = requiredTail && Luau::isVariadic(*requiredTail); // If too many arguments were supplied, this overload // definitely does not match. if (args->head.size() > requiredHead.size()) { auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes); - TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, false}}; + + TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}}; return {Analysis::ArityMismatch, {error}}; } @@ -250,7 +253,7 @@ std::pair OverloadResolver::checkOverload_ if (!subtyping.isSubtype(builtinTypes->nilType, requiredHead[i]).isSubtype) { auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes); - TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, false}}; + TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}}; return {Analysis::ArityMismatch, {error}}; } diff --git a/Dependencies/luau/Luau/Analysis/src/Simplify.cpp b/Dependencies/luau/Luau/Analysis/src/Simplify.cpp index ed953f63..ca9d5898 100644 --- a/Dependencies/luau/Luau/Analysis/src/Simplify.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Simplify.cpp @@ -1144,7 +1144,7 @@ std::optional TypeSimplifier::basicIntersect(TypeId left, TypeId right) return left; bool areDisjoint = true; - for (const auto& [name, leftProp]: lt->props) + for (const auto& [name, leftProp] : lt->props) { if (rt->props.count(name)) { @@ -1156,16 +1156,10 @@ std::optional TypeSimplifier::basicIntersect(TypeId left, TypeId right) if (areDisjoint) { TableType::Props mergedProps = lt->props; - for (const auto& [name, rightProp]: rt->props) + for (const auto& [name, rightProp] : rt->props) mergedProps[name] = rightProp; - return arena->addType(TableType{ - mergedProps, - std::nullopt, - TypeLevel{}, - lt->scope, - TableState::Sealed - }); + return arena->addType(TableType{mergedProps, std::nullopt, TypeLevel{}, lt->scope, TableState::Sealed}); } } diff --git a/Dependencies/luau/Luau/Analysis/src/Substitution.cpp b/Dependencies/luau/Luau/Analysis/src/Substitution.cpp index 8b8f22e8..3eeb2095 100644 --- a/Dependencies/luau/Luau/Analysis/src/Substitution.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Substitution.cpp @@ -11,7 +11,6 @@ LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000) LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256); -LUAU_FASTFLAG(LuauReusableSubstitutions) namespace Luau { @@ -128,7 +127,7 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a return dest.addType(NegationType{a.ty}); else if constexpr (std::is_same_v) { - TypeFunctionInstanceType clone{a.function, a.typeArguments, a.packArguments}; + TypeFunctionInstanceType clone{a.function, a.typeArguments, a.packArguments, a.userFuncName, a.userFuncBody}; return dest.addType(std::move(clone)); } else @@ -148,8 +147,8 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a } Tarjan::Tarjan() - : typeToIndex(nullptr, FFlag::LuauReusableSubstitutions ? FInt::LuauTarjanPreallocationSize : 0) - , packToIndex(nullptr, FFlag::LuauReusableSubstitutions ? FInt::LuauTarjanPreallocationSize : 0) + : typeToIndex(nullptr, FInt::LuauTarjanPreallocationSize) + , packToIndex(nullptr, FInt::LuauTarjanPreallocationSize) { nodes.reserve(FInt::LuauTarjanPreallocationSize); stack.reserve(FInt::LuauTarjanPreallocationSize); @@ -452,28 +451,17 @@ TarjanResult Tarjan::visitRoot(TypePackId tp) void Tarjan::clearTarjan(const TxnLog* log) { - if (FFlag::LuauReusableSubstitutions) - { - typeToIndex.clear(~0u); - packToIndex.clear(~0u); - } - else - { - typeToIndex.clear(); - packToIndex.clear(); - } + typeToIndex.clear(~0u); + packToIndex.clear(~0u); nodes.clear(); stack.clear(); - if (FFlag::LuauReusableSubstitutions) - { - childCount = 0; - // childLimit setting stays the same + childCount = 0; + // childLimit setting stays the same - this->log = log; - } + this->log = log; edgesTy.clear(); edgesTp.clear(); @@ -629,8 +617,6 @@ std::optional Substitution::substitute(TypePackId tp) void Substitution::resetState(const TxnLog* log, TypeArena* arena) { - LUAU_ASSERT(FFlag::LuauReusableSubstitutions); - clearTarjan(log); this->arena = arena; diff --git a/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp b/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp index dc63851f..4bbe2ecd 100644 --- a/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp @@ -627,6 +627,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub result = isCovariantWith(env, p); else if (auto p = get2(subTy, superTy)) result = isCovariantWith(env, p); + else if (auto p = get2(subTy, superTy)) + { + auto [subFunction, superPrimitive] = p; + result.isSubtype = superPrimitive->type == PrimitiveType::Function; + } else if (auto p = get2(subTy, superTy)) result = isCovariantWith(env, p); else if (auto p = get2(subTy, superTy)) @@ -639,6 +644,8 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub result = isCovariantWith(env, p); else if (auto p = get2(subTy, superTy)) result = isCovariantWith(env, subTy, p.first, superTy, p.second); + else if (auto p = get2(subTy, superTy)) + result = isCovariantWith(env, p); else if (auto p = get2(subTy, superTy)) result = isCovariantWith(env, p); else if (auto p = get2(subTy, superTy)) @@ -1368,6 +1375,15 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Func return result; } +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim) +{ + SubtypingResult result{false}; + if (superPrim->type == PrimitiveType::Table) + result.isSubtype = true; + + return result; +} + SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable) { SubtypingResult result{false}; @@ -1387,6 +1403,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prim } } } + else if (subPrim->type == PrimitiveType::Table) + { + const bool isSubtype = superTable->props.empty() && !superTable->indexer.has_value(); + return {isSubtype}; + } return result; } diff --git a/Dependencies/luau/Luau/Analysis/src/TableLiteralInference.cpp b/Dependencies/luau/Luau/Analysis/src/TableLiteralInference.cpp index 630cb441..177396a7 100644 --- a/Dependencies/luau/Luau/Analysis/src/TableLiteralInference.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TableLiteralInference.cpp @@ -389,6 +389,10 @@ TypeId matchLiteralType( TypeId tProp = follow(*propTy); if (get(tProp)) toBlock.push_back(tProp); + + // Populate expected types for non-string keys declared with [] (the code below will handle the case where they are strings) + if (!item.key->as() && expectedTableTy->indexer) + (*astExpectedTypes)[item.key] = expectedTableTy->indexer->indexType; } else LUAU_ASSERT(!"Unexpected"); diff --git a/Dependencies/luau/Luau/Analysis/src/ToString.cpp b/Dependencies/luau/Luau/Analysis/src/ToString.cpp index b5d8a98b..879ddfab 100644 --- a/Dependencies/luau/Luau/Analysis/src/ToString.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ToString.cpp @@ -1036,7 +1036,10 @@ struct TypeStringifier void operator()(TypeId, const TypeFunctionInstanceType& tfitv) { - state.emit(tfitv.function->name); + if (tfitv.userFuncName) // Special stringification for user-defined type functions + state.emit(tfitv.userFuncName->value); + else + state.emit(tfitv.function->name); state.emit("<"); bool comma = false; diff --git a/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp b/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp index f53c994e..5020adc6 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp @@ -1445,37 +1445,40 @@ struct TypeChecker2 else LUAU_ASSERT(!"Generating the best possible error from this function call resolution was inexhaustive?"); - if (resolver.arityMismatches.size() > 1 || resolver.nonviableOverloads.size() > 1) - { - std::string s = "Available overloads: "; + if (resolver.nonviableOverloads.size() <= 1 && resolver.arityMismatches.size() <= 1) + return; - std::vector overloads; - if (resolver.nonviableOverloads.empty()) - { - for (const auto& [ty, p] : resolver.resolution) - { - if (p.first == OverloadResolver::TypeIsNotAFunction) - continue; + std::string s = "Available overloads: "; - overloads.push_back(ty); - } - } - else + std::vector overloads; + if (resolver.nonviableOverloads.empty()) + { + for (const auto& [ty, p] : resolver.resolution) { - for (const auto& [ty, _] : resolver.nonviableOverloads) - overloads.push_back(ty); + if (p.first == OverloadResolver::TypeIsNotAFunction) + continue; + + overloads.push_back(ty); } + } + else + { + for (const auto& [ty, _] : resolver.nonviableOverloads) + overloads.push_back(ty); + } - for (size_t i = 0; i < overloads.size(); ++i) - { - if (i > 0) - s += (i == overloads.size() - 1) ? "; and " : "; "; + if (overloads.size() <= 1) + return; - s += toString(overloads[i]); - } + for (size_t i = 0; i < overloads.size(); ++i) + { + if (i > 0) + s += (i == overloads.size() - 1) ? "; and " : "; "; - reportError(ExtraInformation{std::move(s)}, call->func->location); + s += toString(overloads[i]); } + + reportError(ExtraInformation{std::move(s)}, call->func->location); } void visit(AstExprCall* call) @@ -1756,7 +1759,7 @@ struct TypeChecker2 if (get(follow(retTy))) { TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy); - if (result.shouldRecommendAnnotation) + if (result.shouldRecommendAnnotation && !get(result.guessedReturnType)) reportError( ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType}, fn->location @@ -1838,6 +1841,17 @@ struct TypeChecker2 if (nty && nty->shouldSuppressErrors()) return; + switch (normalizer.isInhabited(nty.get())) + { + case NormalizationResult::True: + break; + case NormalizationResult::False: + return; + case NormalizationResult::HitLimits: + reportError(NormalizationTooComplex{}, expr->location); + return; + } + if (!hasLength(operandType, seen, &recursionCount)) { if (isOptional(operandType)) diff --git a/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp b/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp index 76fa18f6..e8d3764e 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp @@ -358,6 +358,9 @@ struct TypeFunctionReducer if (tryGuessing(subject)) return; + ctx.userFuncName = tfit->userFuncName; + ctx.userFuncBody = tfit->userFuncBody; + TypeFunctionReductionResult result = tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx}); handleTypeFunctionReduction(subject, result); } @@ -567,6 +570,24 @@ static std::optional> tryDistributeTypeFunct return std::nullopt; } +TypeFunctionReductionResult userDefinedTypeFunction( + TypeId instance, + const std::vector& typeParams, + const std::vector& packParams, + NotNull ctx +) +{ + if (!ctx->userFuncName || !ctx->userFuncBody) + { + ctx->ice->ice("all user-defined type functions must have an associated function definition"); + return {std::nullopt, true, {}, {}}; + } + + // TODO: implementation of user-defined type functions goes here + + return {std::nullopt, true, {}, {}}; +} + TypeFunctionReductionResult notTypeFunction( TypeId instance, const std::vector& typeParams, @@ -638,12 +659,9 @@ TypeFunctionReductionResult lenTypeFunction( if (normTy->shouldSuppressErrors()) return {ctx->builtins->numberType, false, {}, {}}; - // if we have an uninhabited type (like `never`), we can never observe that the operator didn't work. - if (inhabited == NormalizationResult::False) - return {ctx->builtins->neverType, false, {}, {}}; - + // # always returns a number, even if its operand is never. // if we're checking the length of a string, that works! - if (normTy->isSubtypeOfString()) + if (inhabited == NormalizationResult::False || normTy->isSubtypeOfString()) return {ctx->builtins->numberType, false, {}, {}}; // we use the normalized operand here in case there was an intersection or union. @@ -1555,86 +1573,116 @@ TypeFunctionReductionResult refineTypeFunction( NotNull ctx ) { - if (typeParams.size() != 2 || !packParams.empty()) + if (typeParams.size() < 2 || !packParams.empty()) { ctx->ice->ice("refine type function: encountered a type function instance without the required argument structure"); LUAU_ASSERT(false); } TypeId targetTy = follow(typeParams.at(0)); - TypeId discriminantTy = follow(typeParams.at(1)); + std::vector discriminantTypes; + for (size_t i = 1; i < typeParams.size(); i++) + discriminantTypes.push_back(follow(typeParams.at(i))); // check to see if both operand types are resolved enough, and wait to reduce if not if (isPending(targetTy, ctx->solver)) return {std::nullopt, false, {targetTy}, {}}; - else if (isPending(discriminantTy, ctx->solver)) - return {std::nullopt, false, {discriminantTy}, {}}; - - // if either type is free but has only one remaining reference, we can generalize it to its upper bound here. - if (ctx->solver) + else { - std::optional targetMaybeGeneralized = ctx->solver->generalizeFreeType(ctx->scope, targetTy); - std::optional discriminantMaybeGeneralized = ctx->solver->generalizeFreeType(ctx->scope, discriminantTy); - - if (!targetMaybeGeneralized) - return {std::nullopt, false, {targetTy}, {}}; - else if (!discriminantMaybeGeneralized) - return {std::nullopt, false, {discriminantTy}, {}}; - - targetTy = *targetMaybeGeneralized; - discriminantTy = *discriminantMaybeGeneralized; + for (auto t : discriminantTypes) + { + if (isPending(t, ctx->solver)) + return {std::nullopt, false, {t}, {}}; + } } + // Refine a target type and a discriminant one at a time. + // Returns result : TypeId, toBlockOn : vector + auto stepRefine = [&ctx](TypeId target, TypeId discriminant) -> std::pair> + { + std::vector toBlock; + if (ctx->solver) + { + std::optional targetMaybeGeneralized = ctx->solver->generalizeFreeType(ctx->scope, target); + std::optional discriminantMaybeGeneralized = ctx->solver->generalizeFreeType(ctx->scope, discriminant); - // we need a more complex check for blocking on the discriminant in particular - FindRefinementBlockers frb; - frb.traverse(discriminantTy); + if (!targetMaybeGeneralized) + return std::pair>{nullptr, {target}}; + else if (!discriminantMaybeGeneralized) + return std::pair>{nullptr, {discriminant}}; - if (!frb.found.empty()) - return {std::nullopt, false, {frb.found.begin(), frb.found.end()}, {}}; + target = *targetMaybeGeneralized; + discriminant = *discriminantMaybeGeneralized; + } + + // we need a more complex check for blocking on the discriminant in particular + FindRefinementBlockers frb; + frb.traverse(discriminant); + + if (!frb.found.empty()) + return {nullptr, {frb.found.begin(), frb.found.end()}}; + + /* HACK: Refinements sometimes produce a type T & ~any under the assumption + * that ~any is the same as any. This is so so weird, but refinements needs + * some way to say "I may refine this, but I'm not sure." + * + * It does this by refining on a blocked type and deferring the decision + * until it is unblocked. + * + * Refinements also get negated, so we wind up with types like T & ~*blocked* + * + * We need to treat T & ~any as T in this case. + */ + if (auto nt = get(discriminant)) + if (get(follow(nt->ty))) + return {target, {}}; + + // If the target type is a table, then simplification already implements the logic to deal with refinements properly since the + // type of the discriminant is guaranteed to only ever be an (arbitrarily-nested) table of a single property type. + if (get(target)) + { + SimplifyResult result = simplifyIntersection(ctx->builtins, ctx->arena, target, discriminant); + if (!result.blockedTypes.empty()) + return {nullptr, {result.blockedTypes.begin(), result.blockedTypes.end()}}; - /* HACK: Refinements sometimes produce a type T & ~any under the assumption - * that ~any is the same as any. This is so so weird, but refinements needs - * some way to say "I may refine this, but I'm not sure." - * - * It does this by refining on a blocked type and deferring the decision - * until it is unblocked. - * - * Refinements also get negated, so we wind up with types like T & ~*blocked* - * - * We need to treat T & ~any as T in this case. - */ + return {result.result, {}}; + } - if (auto nt = get(discriminantTy)) - if (get(follow(nt->ty))) - return {targetTy, false, {}, {}}; + // In the general case, we'll still use normalization though. + TypeId intersection = ctx->arena->addType(IntersectionType{{target, discriminant}}); + std::shared_ptr normIntersection = ctx->normalizer->normalize(intersection); + std::shared_ptr normType = ctx->normalizer->normalize(target); - // If the target type is a table, then simplification already implements the logic to deal with refinements properly since the - // type of the discriminant is guaranteed to only ever be an (arbitrarily-nested) table of a single property type. - if (get(targetTy)) - { - SimplifyResult result = simplifyIntersection(ctx->builtins, ctx->arena, targetTy, discriminantTy); - if (!result.blockedTypes.empty()) - return {std::nullopt, false, {result.blockedTypes.begin(), result.blockedTypes.end()}, {}}; + // if the intersection failed to normalize, we can't reduce, but know nothing about inhabitance. + if (!normIntersection || !normType) + return {nullptr, {}}; - return {result.result, false, {}, {}}; - } + TypeId resultTy = ctx->normalizer->typeFromNormal(*normIntersection); + // include the error type if the target type is error-suppressing and the intersection we computed is not + if (normType->shouldSuppressErrors() && !normIntersection->shouldSuppressErrors()) + resultTy = ctx->arena->addType(UnionType{{resultTy, ctx->builtins->errorType}}); - // In the general case, we'll still use normalization though. - TypeId intersection = ctx->arena->addType(IntersectionType{{targetTy, discriminantTy}}); - std::shared_ptr normIntersection = ctx->normalizer->normalize(intersection); - std::shared_ptr normType = ctx->normalizer->normalize(targetTy); + return {resultTy, {}}; + }; - // if the intersection failed to normalize, we can't reduce, but know nothing about inhabitance. - if (!normIntersection || !normType) - return {std::nullopt, false, {}, {}}; + // refine target with each discriminant type in sequence (reverse of insertion order) + // If we cannot proceed, block. If all discriminant types refine successfully, return + // the result + TypeId target = targetTy; + while (!discriminantTypes.empty()) + { + TypeId discriminant = discriminantTypes.back(); + auto [refined, blocked] = stepRefine(target, discriminant); - TypeId resultTy = ctx->normalizer->typeFromNormal(*normIntersection); + if (blocked.empty() && refined == nullptr) + return {std::nullopt, false, {}, {}}; - // include the error type if the target type is error-suppressing and the intersection we computed is not - if (normType->shouldSuppressErrors() && !normIntersection->shouldSuppressErrors()) - resultTy = ctx->arena->addType(UnionType{{resultTy, ctx->builtins->errorType}}); + if (!blocked.empty()) + return {std::nullopt, false, blocked, {}}; - return {resultTy, false, {}, {}}; + target = refined; + discriminantTypes.pop_back(); + } + return {target, false, {}, {}}; } TypeFunctionReductionResult singletonTypeFunction( @@ -2253,7 +2301,8 @@ TypeFunctionReductionResult rawgetTypeFunction( } BuiltinTypeFunctions::BuiltinTypeFunctions() - : notFunc{"not", notTypeFunction} + : userFunc{"user", userDefinedTypeFunction} + , notFunc{"not", notTypeFunction} , lenFunc{"len", lenTypeFunction} , unmFunc{"unm", unmTypeFunction} , addFunc{"add", addTypeFunction} diff --git a/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp b/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp index 7b7d6fae..c0a43df8 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp @@ -34,8 +34,6 @@ LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false) LUAU_FASTFLAG(LuauInstantiateInSubtyping) LUAU_FASTFLAGVARIABLE(LuauRemoveBadRelationalOperatorWarning, false) LUAU_FASTFLAGVARIABLE(LuauOkWithIteratingOverTableProperties, false) -LUAU_FASTFLAGVARIABLE(LuauReusableSubstitutions, false) -LUAU_FASTFLAG(LuauDeclarationExtraPropData) namespace Luau { @@ -1756,28 +1754,22 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& ftv->argTypes = addTypePack(TypePack{{classTy}, ftv->argTypes}); ftv->hasSelf = true; - if (FFlag::LuauDeclarationExtraPropData) - { - FunctionDefinition defn; + FunctionDefinition defn; - defn.definitionModuleName = currentModule->name; - defn.definitionLocation = prop.location; - // No data is preserved for varargLocation - defn.originalNameLocation = prop.nameLocation; + defn.definitionModuleName = currentModule->name; + defn.definitionLocation = prop.location; + // No data is preserved for varargLocation + defn.originalNameLocation = prop.nameLocation; - ftv->definition = defn; - } + ftv->definition = defn; } } if (assignTo.count(propName) == 0) { - if (FFlag::LuauDeclarationExtraPropData) - assignTo[propName] = {propTy, /*deprecated*/ false, /*deprecatedSuggestion*/ "", prop.location}; - else - assignTo[propName] = {propTy}; + assignTo[propName] = {propTy, /*deprecated*/ false, /*deprecatedSuggestion*/ "", prop.location}; } - else if (FFlag::LuauDeclarationExtraPropData) + else { Luau::Property& prop = assignTo[propName]; TypeId currentTy = prop.type(); @@ -1805,31 +1797,6 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& reportError(declaredClass.location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())}); } } - else - { - TypeId currentTy = assignTo[propName].type(); - - // We special-case this logic to keep the intersection flat; otherwise we - // would create a ton of nested intersection types. - if (const IntersectionType* itv = get(currentTy)) - { - std::vector options = itv->parts; - options.push_back(propTy); - TypeId newItv = addType(IntersectionType{std::move(options)}); - - assignTo[propName] = {newItv}; - } - else if (get(currentTy)) - { - TypeId intersection = addType(IntersectionType{{currentTy, propTy}}); - - assignTo[propName] = {intersection}; - } - else - { - reportError(declaredClass.location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())}); - } - } } return ControlFlow::None; @@ -1870,13 +1837,10 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatDeclareFuncti FunctionDefinition defn; - if (FFlag::LuauDeclarationExtraPropData) - { - defn.definitionModuleName = currentModule->name; - defn.definitionLocation = global.location; - defn.varargLocation = global.vararg ? std::make_optional(global.varargLocation) : std::nullopt; - defn.originalNameLocation = global.nameLocation; - } + defn.definitionModuleName = currentModule->name; + defn.definitionLocation = global.location; + defn.varargLocation = global.vararg ? std::make_optional(global.varargLocation) : std::nullopt; + defn.originalNameLocation = global.nameLocation; TypeId fnType = addType(FunctionType{funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack, defn}); FunctionType* ftv = getMutable(fnType); @@ -4991,24 +4955,12 @@ TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location locat std::optional instantiated; - if (FFlag::LuauReusableSubstitutions) - { - reusableInstantiation.resetState(log, ¤tModule->internalTypes, builtinTypes, scope->level, /*scope*/ nullptr); + reusableInstantiation.resetState(log, ¤tModule->internalTypes, builtinTypes, scope->level, /*scope*/ nullptr); - if (instantiationChildLimit) - reusableInstantiation.childLimit = *instantiationChildLimit; + if (instantiationChildLimit) + reusableInstantiation.childLimit = *instantiationChildLimit; - instantiated = reusableInstantiation.substitute(ty); - } - else - { - Instantiation instantiation{log, ¤tModule->internalTypes, builtinTypes, scope->level, /*scope*/ nullptr}; - - if (instantiationChildLimit) - instantiation.childLimit = *instantiationChildLimit; - - instantiated = instantiation.substitute(ty); - } + instantiated = reusableInstantiation.substitute(ty); if (instantiated.has_value()) return *instantiated; diff --git a/Dependencies/luau/Luau/Ast/src/Parser.cpp b/Dependencies/luau/Luau/Ast/src/Parser.cpp index d58fe1e8..59533bae 100644 --- a/Dependencies/luau/Luau/Ast/src/Parser.cpp +++ b/Dependencies/luau/Luau/Ast/src/Parser.cpp @@ -19,7 +19,6 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100) LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false) LUAU_FASTFLAGVARIABLE(LuauNativeAttribute, false) LUAU_FASTFLAGVARIABLE(LuauAttributeSyntaxFunExpr, false) -LUAU_FASTFLAGVARIABLE(LuauDeclarationExtraPropData, false) LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctions, false) namespace Luau @@ -938,16 +937,10 @@ AstStat* Parser::parseTypeFunction(const Location& start) AstDeclaredClassProp Parser::parseDeclaredClassMethod() { - Location start; - - if (FFlag::LuauDeclarationExtraPropData) - start = lexer.current().location; + Location start = lexer.current().location; nextLexeme(); - if (!FFlag::LuauDeclarationExtraPropData) - start = lexer.current().location; - Name fnName = parseName("function name"); // TODO: generic method declarations CLI-39909 @@ -972,7 +965,7 @@ AstDeclaredClassProp Parser::parseDeclaredClassMethod() expectMatchAndConsume(')', matchParen); AstTypeList retTypes = parseOptionalReturnType().value_or(AstTypeList{copy(nullptr, 0), nullptr}); - Location end = FFlag::LuauDeclarationExtraPropData ? lexer.previousLocation() : lexer.current().location; + Location end = lexer.previousLocation(); TempVector vars(scratchType); TempVector> varNames(scratchOptArgName); @@ -980,10 +973,7 @@ AstDeclaredClassProp Parser::parseDeclaredClassMethod() if (args.size() == 0 || args[0].name.name != "self" || args[0].annotation != nullptr) { return AstDeclaredClassProp{ - fnName.name, - FFlag::LuauDeclarationExtraPropData ? fnName.location : Location{}, - reportTypeError(Location(start, end), {}, "'self' must be present as the unannotated first parameter"), - true + fnName.name, fnName.location, reportTypeError(Location(start, end), {}, "'self' must be present as the unannotated first parameter"), true }; } @@ -1005,13 +995,7 @@ AstDeclaredClassProp Parser::parseDeclaredClassMethod() Location(start, end), generics, genericPacks, AstTypeList{copy(vars), varargAnnotation}, copy(varNames), retTypes ); - return AstDeclaredClassProp{ - fnName.name, - FFlag::LuauDeclarationExtraPropData ? fnName.location : Location{}, - fnType, - true, - FFlag::LuauDeclarationExtraPropData ? Location(start, end) : Location{} - }; + return AstDeclaredClassProp{fnName.name, fnName.location, fnType, true, Location(start, end)}; } AstStat* Parser::parseDeclaration(const Location& start, const AstArray& attributes) @@ -1067,34 +1051,19 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray( - Location(start, end), - attributes, - globalName.name, - globalName.location, - generics, - genericPacks, - AstTypeList{copy(vars), varargAnnotation}, - copy(varNames), - vararg, - varargLocation, - retTypes - ); - else - return allocator.alloc( - Location(start, end), - attributes, - globalName.name, - Location{}, - generics, - genericPacks, - AstTypeList{copy(vars), varargAnnotation}, - copy(varNames), - false, - Location{}, - retTypes - ); + return allocator.alloc( + Location(start, end), + attributes, + globalName.name, + globalName.location, + generics, + genericPacks, + AstTypeList{copy(vars), varargAnnotation}, + copy(varNames), + vararg, + varargLocation, + retTypes + ); } else if (AstName(lexer.current().name) == "class") { @@ -1124,42 +1093,27 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray> chars = parseCharArray(); + const Location nameBegin = lexer.current().location; + std::optional> chars = parseCharArray(); - const Location nameEnd = lexer.previousLocation(); + const Location nameEnd = lexer.previousLocation(); - expectMatchAndConsume(']', begin); - expectAndConsume(':', "property type annotation"); - AstType* type = parseType(); + expectMatchAndConsume(']', begin); + expectAndConsume(':', "property type annotation"); + AstType* type = parseType(); - // since AstName contains a char*, it can't contain null - bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size); + // since AstName contains a char*, it can't contain null + bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size); - if (chars && !containsNull) - props.push_back(AstDeclaredClassProp{ - AstName(chars->data), Location(nameBegin, nameEnd), type, false, Location(begin.location, lexer.previousLocation()) - }); - else - report(begin.location, "String literal contains malformed escape sequence or \\0"); + if (chars && !containsNull) + { + props.push_back(AstDeclaredClassProp{ + AstName(chars->data), Location(nameBegin, nameEnd), type, false, Location(begin.location, lexer.previousLocation()) + }); } else { - std::optional> chars = parseCharArray(); - - expectMatchAndConsume(']', begin); - expectAndConsume(':', "property type annotation"); - AstType* type = parseType(); - - // since AstName contains a char*, it can't contain null - bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size); - - if (chars && !containsNull) - props.push_back(AstDeclaredClassProp{AstName(chars->data), Location{}, type, false}); - else - report(begin.location, "String literal contains malformed escape sequence or \\0"); + report(begin.location, "String literal contains malformed escape sequence or \\0"); } } else if (lexer.current().type == '[') @@ -1178,7 +1132,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray( - Location(start, type->location), globalName->name, FFlag::LuauDeclarationExtraPropData ? globalName->location : Location{}, type - ); + return allocator.alloc(Location(start, type->location), globalName->name, globalName->location, type); } else { @@ -2243,15 +2188,24 @@ std::optional Parser::checkBinaryConfusables(const BinaryOpPr // where `binop' is any binary operator with a priority higher than `limit' AstExpr* Parser::parseExpr(unsigned int limit) { - // clang-format off static const BinaryOpPriority binaryPriority[] = { - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, // `+' `-' `*' `/' `//' `%' - {10, 9}, {5, 4}, // power and concat (right associative) - {3, 3}, {3, 3}, // equality and inequality - {3, 3}, {3, 3}, {3, 3}, {3, 3}, // order - {2, 2}, {1, 1} // logical (and/or) + {6, 6}, // '+' + {6, 6}, // '-' + {7, 7}, // '*' + {7, 7}, // '/' + {7, 7}, // '//' + {7, 7}, // `%' + {10, 9}, // power (right associative) + {5, 4}, // concat (right associative) + {3, 3}, // inequality + {3, 3}, // equality + {3, 3}, // '<' + {3, 3}, // '<=' + {3, 3}, // '>' + {3, 3}, // '>=' + {2, 2}, // logical and + {1, 1} // logical or }; - // clang-format on static_assert(sizeof(binaryPriority) / sizeof(binaryPriority[0]) == size_t(AstExprBinary::Op__Count), "binaryPriority needs an entry per op"); @@ -3507,4 +3461,4 @@ void Parser::nextLexeme() } } -} // namespace Luau \ No newline at end of file +} // namespace Luau diff --git a/Dependencies/luau/Luau/Ast/src/TimeTrace.cpp b/Dependencies/luau/Luau/Ast/src/TimeTrace.cpp index 4782b25c..e8be59eb 100644 --- a/Dependencies/luau/Luau/Ast/src/TimeTrace.cpp +++ b/Dependencies/luau/Luau/Ast/src/TimeTrace.cpp @@ -40,7 +40,7 @@ static double getClockPeriod() mach_timebase_info_data_t result = {}; mach_timebase_info(&result); return double(result.numer) / double(result.denom) * 1e-9; -#elif defined(__linux__) +#elif defined(__linux__) || defined(__FreeBSD__) return 1e-9; #else return 1.0 / double(CLOCKS_PER_SEC); @@ -55,7 +55,7 @@ static double getClockTimestamp() return double(result.QuadPart); #elif defined(__APPLE__) return double(mach_absolute_time()); -#elif defined(__linux__) +#elif defined(__linux__) || defined(__FreeBSD__) timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return now.tv_sec * 1e9 + now.tv_nsec; diff --git a/Dependencies/luau/Luau/VM/src/ldo.cpp b/Dependencies/luau/Luau/VM/src/ldo.cpp index 453fd967..0cffec40 100644 --- a/Dependencies/luau/Luau/VM/src/ldo.cpp +++ b/Dependencies/luau/Luau/VM/src/ldo.cpp @@ -17,6 +17,8 @@ #include +LUAU_FASTFLAGVARIABLE(LuauErrorResumeCleanupArgs, false) + /* ** {====================================================== ** Error-recovery functions @@ -426,9 +428,13 @@ static void resume_handle(lua_State* L, void* ud) resume_continue(L); } -static int resume_error(lua_State* L, const char* msg) +static int resume_error(lua_State* L, const char* msg, int narg) { - L->top = L->ci->base; + if (FFlag::LuauErrorResumeCleanupArgs) + L->top -= narg; + else + L->top = L->ci->base; + setsvalue(L, L->top, luaS_new(L, msg)); incr_top(L); return LUA_ERRRUN; @@ -455,11 +461,11 @@ int lua_resume(lua_State* L, lua_State* from, int nargs) { int status; if (L->status != LUA_YIELD && L->status != LUA_BREAK && (L->status != 0 || L->ci != L->base_ci)) - return resume_error(L, "cannot resume non-suspended coroutine"); + return resume_error(L, "cannot resume non-suspended coroutine", nargs); L->nCcalls = from ? from->nCcalls : 0; if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow"); + return resume_error(L, "C stack overflow", nargs); L->baseCcalls = ++L->nCcalls; L->isactive = true; @@ -484,11 +490,11 @@ int lua_resumeerror(lua_State* L, lua_State* from) { int status; if (L->status != LUA_YIELD && L->status != LUA_BREAK && (L->status != 0 || L->ci != L->base_ci)) - return resume_error(L, "cannot resume non-suspended coroutine"); + return resume_error(L, "cannot resume non-suspended coroutine", 1); L->nCcalls = from ? from->nCcalls : 0; if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow"); + return resume_error(L, "C stack overflow", 1); L->baseCcalls = ++L->nCcalls; L->isactive = true; diff --git a/Dependencies/luau/Luau/VM/src/lperf.cpp b/Dependencies/luau/Luau/VM/src/lperf.cpp index b7293c14..fef70c36 100644 --- a/Dependencies/luau/Luau/VM/src/lperf.cpp +++ b/Dependencies/luau/Luau/VM/src/lperf.cpp @@ -30,7 +30,7 @@ static double clock_period() mach_timebase_info_data_t result = {}; mach_timebase_info(&result); return double(result.numer) / double(result.denom) * 1e-9; -#elif defined(__linux__) +#elif defined(__linux__) || defined(__FreeBSD__) return 1e-9; #else return 1.0 / double(CLOCKS_PER_SEC); @@ -45,7 +45,7 @@ static double clock_timestamp() return double(result.QuadPart); #elif defined(__APPLE__) return double(mach_absolute_time()); -#elif defined(__linux__) +#elif defined(__linux__) || defined(__FreeBSD__) timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return now.tv_sec * 1e9 + now.tv_nsec; diff --git a/Dependencies/luau/Luau/VM/src/lstate.h b/Dependencies/luau/Luau/VM/src/lstate.h index f8caa69b..3f4f9425 100644 --- a/Dependencies/luau/Luau/VM/src/lstate.h +++ b/Dependencies/luau/Luau/VM/src/lstate.h @@ -217,7 +217,7 @@ typedef struct global_State lua_ExecutionCallbacks ecb; void (*udatagc[LUA_UTAG_LIMIT])(lua_State*, void*); // for each userdata tag, a gc callback to be called immediately before freeing memory - Table* udatamt[LUA_LUTAG_LIMIT]; // metatables for tagged userdata + Table* udatamt[LUA_UTAG_LIMIT]; // metatables for tagged userdata TString* lightuserdataname[LUA_LUTAG_LIMIT]; // names for tagged lightuserdata diff --git a/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp b/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp index b737aa71..aed7b7e5 100644 --- a/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp +++ b/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp @@ -70,6 +70,53 @@ export type t8 = t0 &((true | any)->('')) } } +TEST_CASE_FIXTURE(ATSFixture, "typepacks") +{ + fileResolver.source["game/Gui/Modules/A"] = R"( +local function fallible(t: number): ...any + if t > 0 then + return true, t -- should catch this + end + return false, "must be positive" -- should catch this +end +)"; + + CheckResult result1 = frontend.check("game/Gui/Modules/A"); + LUAU_REQUIRE_NO_ERRORS(result1); + + ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); + + if (FFlag::StudioReportLuauAny) + { + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::TypePk); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function fallible(t: number): ...any\n if t > 0 then\n return true, t\n end\n return false, 'must be positive'\nend"); + } +} + +TEST_CASE_FIXTURE(ATSFixture, "typepacks_no_ret") +{ + fileResolver.source["game/Gui/Modules/A"] = R"( +-- TODO: if partially typed, we'd want to know too +local function fallible(t: number) + if t > 0 then + return true, t + end + return false, "must be positive" +end +)"; + + CheckResult result1 = frontend.check("game/Gui/Modules/A"); + LUAU_REQUIRE_ERROR_COUNT(1, result1); + + ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); + + if (FFlag::StudioReportLuauAny) + { + LUAU_ASSERT(module->ats.typeInfo.size() == 0); + } +} + TEST_CASE_FIXTURE(ATSFixture, "var_typepack_any_gen_table") { fileResolver.source["game/Gui/Modules/A"] = R"( @@ -126,7 +173,7 @@ type Pair = (boolean, T) -> ...any if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); LUAU_ASSERT(module->ats.typeInfo[0].node == "type Pair = (boolean, T)->( ...any)"); } } @@ -223,7 +270,10 @@ end { LUAU_ASSERT(module->ats.typeInfo.size() == 1); LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function f(x: any)\nif not x then\nx = {\n y = math.random(0, 2^31-1),\n left = nil,\n right = nil\n}\nelse\n local expected = x * 5\nend\nend"); + LUAU_ASSERT( + module->ats.typeInfo[0].node == "function f(x: any)\nif not x then\nx = {\n y = math.random(0, 2^31-1),\n left = nil,\n right = " + "nil\n}\nelse\n local expected = x * 5\nend\nend" + ); } } @@ -244,7 +294,7 @@ TEST_CASE_FIXTURE(ATSFixture, "variadic_any") if (FFlag::StudioReportLuauAny) { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo.size() == 1); LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(): (number, ...any)\n return 1, 5\n end"); } @@ -267,7 +317,7 @@ TEST_CASE_FIXTURE(ATSFixture, "type_alias_intersection") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[2].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[2].code == Pattern::VarAnnot); LUAU_ASSERT(module->ats.typeInfo[2].node == "local vec2: Vector2 = {x = 1, y = 2}"); } } @@ -293,7 +343,7 @@ TEST_CASE_FIXTURE(ATSFixture, "var_func_arg") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 4); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); } } @@ -315,7 +365,7 @@ TEST_CASE_FIXTURE(ATSFixture, "var_func_apps") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); } } @@ -401,7 +451,7 @@ initialize() if (FFlag::StudioReportLuauAny) { - LUAU_ASSERT(module->ats.typeInfo.size() == 5); + LUAU_ASSERT(module->ats.typeInfo.size() == 5); LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); LUAU_ASSERT(module->ats.typeInfo[0].node == "local function manageRace(raceContainer: Model)\n RaceManager.new(raceContainer)\nend"); } @@ -477,8 +527,14 @@ initialize() if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 11); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function onCharacterAdded(character: Model)\n\n character.DescendantAdded:Connect(function(descendant)\n if descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n end)\n\n\n for _, descendant in character:GetDescendants()do\n if descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n end\nend"); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT( + module->ats.typeInfo[0].node == + "local function onCharacterAdded(character: Model)\n\n character.DescendantAdded:Connect(function(descendant)\n if " + "descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n end)\n\n\n for _, descendant in " + "character:GetDescendants()do\n if descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n " + "end\nend" + ); } } @@ -540,8 +596,15 @@ initialize() if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 7); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function setupKiosk(kiosk: Model)\n local spawnLocation = kiosk:FindFirstChild('SpawnLocation')\n assert(spawnLocation, `{kiosk:GetFullName()} has no SpawnLocation part`)\n local promptPart = kiosk:FindFirstChild('Prompt')\n assert(promptPart, `{kiosk:GetFullName()} has no Prompt part`)\n\n\n spawnLocation.Transparency = 1\n\n\n local spawnPrompt = spawnPromptTemplate:Clone()\n spawnPrompt.Parent = promptPart\n\n spawnPrompt.Triggered:Connect(function(player: Player)\n\n destroyPlayerCars(player)\n\n spawnCar(spawnLocation.CFrame, player)\n end)\nend"); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT( + module->ats.typeInfo[0].node == + "local function setupKiosk(kiosk: Model)\n local spawnLocation = kiosk:FindFirstChild('SpawnLocation')\n assert(spawnLocation, " + "`{kiosk:GetFullName()} has no SpawnLocation part`)\n local promptPart = kiosk:FindFirstChild('Prompt')\n assert(promptPart, " + "`{kiosk:GetFullName()} has no Prompt part`)\n\n\n spawnLocation.Transparency = 1\n\n\n local spawnPrompt = " + "spawnPromptTemplate:Clone()\n spawnPrompt.Parent = promptPart\n\n spawnPrompt.Triggered:Connect(function(player: Player)\n\n " + "destroyPlayerCars(player)\n\n spawnCar(spawnLocation.CFrame, player)\n end)\nend" + ); } } @@ -626,7 +689,7 @@ TEST_CASE_FIXTURE(ATSFixture, "table_uses_any") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: any = 0"); } } @@ -668,8 +731,8 @@ TEST_CASE_FIXTURE(ATSFixture, "table_type_assigned") if (FFlag::StudioReportLuauAny) { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Assign); + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Assign); LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: { x: any?} = {x = 1}"); } } @@ -689,7 +752,7 @@ TEST_CASE_FIXTURE(ATSFixture, "simple_func_wo_ret") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); LUAU_ASSERT(module->ats.typeInfo[0].node == "function some(x: any)\n end"); } } @@ -710,7 +773,7 @@ TEST_CASE_FIXTURE(ATSFixture, "simple_func_w_ret") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); LUAU_ASSERT(module->ats.typeInfo[0].node == "function other(y: number): any\n return 'gotcha!'\n end"); } } @@ -731,7 +794,7 @@ TEST_CASE_FIXTURE(ATSFixture, "nested_local") if (FFlag::StudioReportLuauAny) { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo.size() == 1); LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); LUAU_ASSERT(module->ats.typeInfo[0].node == "function cool(y: number): number\n local g: any = 'gratatataaa'\n return y\n end"); } @@ -753,7 +816,7 @@ TEST_CASE_FIXTURE(ATSFixture, "generic_func") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); LUAU_ASSERT(module->ats.typeInfo[0].node == "function reverse(a: {T}, b: any): {T}\n return a\n end"); } } @@ -773,7 +836,7 @@ TEST_CASE_FIXTURE(ATSFixture, "type_alias_any") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); } } @@ -804,7 +867,7 @@ TEST_CASE_FIXTURE(ATSFixture, "multi_module_any") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); } } @@ -830,7 +893,7 @@ TEST_CASE_FIXTURE(ATSFixture, "cast_on_cyclic_req") if (FFlag::StudioReportLuauAny) { LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Alias); LUAU_ASSERT(module->ats.typeInfo[1].node == "type Clear = any"); } } diff --git a/Dependencies/luau/Luau/tests/AstJsonEncoder.test.cpp b/Dependencies/luau/Luau/tests/AstJsonEncoder.test.cpp index 464eacce..76538cf1 100644 --- a/Dependencies/luau/Luau/tests/AstJsonEncoder.test.cpp +++ b/Dependencies/luau/Luau/tests/AstJsonEncoder.test.cpp @@ -9,8 +9,6 @@ #include #include -LUAU_FASTFLAG(LuauDeclarationExtraPropData) - using namespace Luau; struct JsonEncoderFixture @@ -417,8 +415,6 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatTypeAlias") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareFunction") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - AstStat* statement = expectParseStatement("declare function foo(x: number): string"); std::string_view expected = @@ -429,8 +425,6 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareFunction") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareFunction2") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - AstStat* statement = expectParseStatement("declare function foo(x: number, ...: string): string"); std::string_view expected = @@ -441,8 +435,6 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareFunction2") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareClass") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - AstStatBlock* root = expectParse(R"( declare class Foo prop: number diff --git a/Dependencies/luau/Luau/tests/AstQuery.test.cpp b/Dependencies/luau/Luau/tests/AstQuery.test.cpp index 55b2a132..ec32c5f1 100644 --- a/Dependencies/luau/Luau/tests/AstQuery.test.cpp +++ b/Dependencies/luau/Luau/tests/AstQuery.test.cpp @@ -171,6 +171,8 @@ TEST_SUITE_BEGIN("AstQuery"); TEST_CASE_FIXTURE(Fixture, "last_argument_function_call_type") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + check(R"( local function foo() return 2 end local function bar(a: number) return -a end diff --git a/Dependencies/luau/Luau/tests/Fixture.h b/Dependencies/luau/Luau/tests/Fixture.h index e7aad61c..790e6f41 100644 --- a/Dependencies/luau/Luau/tests/Fixture.h +++ b/Dependencies/luau/Luau/tests/Fixture.h @@ -13,6 +13,7 @@ #include "Luau/Scope.h" #include "Luau/ToString.h" #include "Luau/Type.h" +#include "Luau/TypeFunction.h" #include "IostreamOptional.h" #include "ScopedFlags.h" diff --git a/Dependencies/luau/Luau/tests/Linter.test.cpp b/Dependencies/luau/Luau/tests/Linter.test.cpp index b5cbd26a..6fd70626 100644 --- a/Dependencies/luau/Luau/tests/Linter.test.cpp +++ b/Dependencies/luau/Luau/tests/Linter.test.cpp @@ -1658,6 +1658,10 @@ table.create(42, {} :: {}) TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperationsIndexer") { + // CLI-116824 Linter incorrectly issues false positive when taking the length of a unannotated string function argument + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + LintResult result = lint(R"( local t1 = {} -- ok: empty local t2 = {1, 2} -- ok: array diff --git a/Dependencies/luau/Luau/tests/Normalize.test.cpp b/Dependencies/luau/Luau/tests/Normalize.test.cpp index 19c63b28..407aaf4e 100644 --- a/Dependencies/luau/Luau/tests/Normalize.test.cpp +++ b/Dependencies/luau/Luau/tests/Normalize.test.cpp @@ -440,11 +440,11 @@ struct NormalizeFixture : Fixture registerHiddenTypes(&frontend); } - std::shared_ptr toNormalizedType(const std::string& annotation) + std::shared_ptr toNormalizedType(const std::string& annotation, int expectedErrors = 0) { normalizer.clearCaches(); CheckResult result = check("type _Res = " + annotation); - LUAU_REQUIRE_NO_ERRORS(result); + LUAU_REQUIRE_ERROR_COUNT(expectedErrors, result); if (FFlag::DebugLuauDeferredConstraintResolution) { @@ -662,7 +662,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "negated_function_is_anything_except_a_funct TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated") { - CHECK(nullptr == toNormalizedType("Not<(boolean) -> boolean>")); + CHECK(nullptr == toNormalizedType("Not<(boolean) -> boolean>", FFlag::DebugLuauDeferredConstraintResolution ? 1 : 0)); } TEST_CASE_FIXTURE(NormalizeFixture, "trivial_intersection_inhabited") @@ -847,6 +847,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_classes") "(Parent | Unrelated | boolean | buffer | function | number | string | table | thread)?" == toString(normal("Not & Not & Not>")) ); + + CHECK("Child" == toString(normal("(Child | Unrelated) & Not"))); } TEST_CASE_FIXTURE(NormalizeFixture, "classes_and_unknown") @@ -873,7 +875,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "top_table_type") TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_tables") { - CHECK(nullptr == toNormalizedType("Not<{}>")); + CHECK(nullptr == toNormalizedType("Not<{}>", FFlag::DebugLuauDeferredConstraintResolution ? 1 : 0)); CHECK("(boolean | buffer | class | function | number | string | thread)?" == toString(normal("Not"))); CHECK("table" == toString(normal("Not>"))); } @@ -998,17 +1000,13 @@ TEST_CASE_FIXTURE(NormalizeFixture, "truthy_table_property_and_optional_table_wi ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; // { x: ~(false?) } - TypeId t1 = arena.addType(TableType{ - TableType::Props{{"x", builtinTypes->truthyType}}, std::nullopt, TypeLevel{}, TableState::Sealed - }); + TypeId t1 = arena.addType(TableType{TableType::Props{{"x", builtinTypes->truthyType}}, std::nullopt, TypeLevel{}, TableState::Sealed}); // { x: number? }? - TypeId t2 = arena.addType(UnionType{{ - arena.addType(TableType{ - TableType::Props{{"x", builtinTypes->optionalNumberType}}, std::nullopt, TypeLevel{}, TableState::Sealed - }), - builtinTypes->nilType - }}); + TypeId t2 = arena.addType(UnionType{ + {arena.addType(TableType{TableType::Props{{"x", builtinTypes->optionalNumberType}}, std::nullopt, TypeLevel{}, TableState::Sealed}), + builtinTypes->nilType} + }); TypeId intersection = arena.addType(IntersectionType{{t2, t1}}); diff --git a/Dependencies/luau/Luau/tests/Parser.test.cpp b/Dependencies/luau/Luau/tests/Parser.test.cpp index 1be8024e..b285a318 100644 --- a/Dependencies/luau/Luau/tests/Parser.test.cpp +++ b/Dependencies/luau/Luau/tests/Parser.test.cpp @@ -17,7 +17,6 @@ LUAU_FASTINT(LuauTypeLengthLimit); LUAU_FASTINT(LuauParseErrorLimit); LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); LUAU_FASTFLAG(LuauAttributeSyntaxFunExpr); -LUAU_FASTFLAG(LuauDeclarationExtraPropData); LUAU_FASTFLAG(LuauUserDefinedTypeFunctions); namespace @@ -1918,8 +1917,6 @@ function func():end TEST_CASE_FIXTURE(Fixture, "parse_declarations") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - AstStatBlock* stat = parseEx(R"( declare foo: number declare function bar(x: number): string @@ -1957,8 +1954,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_declarations") TEST_CASE_FIXTURE(Fixture, "parse_class_declarations") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - AstStatBlock* stat = parseEx(R"( declare class Foo prop: number @@ -2085,7 +2080,6 @@ TEST_CASE_FIXTURE(Fixture, "class_indexer") TEST_CASE_FIXTURE(Fixture, "parse_variadics") { - //clang-format off AstStatBlock* stat = parseEx(R"( function foo(bar, ...: number): ...string end @@ -2094,7 +2088,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_variadics") type Bar = () -> (number, ...boolean) )") .root; - //clang-format on REQUIRE(stat); REQUIRE_EQ(stat->body.size, 3); diff --git a/Dependencies/luau/Luau/tests/Subtyping.test.cpp b/Dependencies/luau/Luau/tests/Subtyping.test.cpp index 64aa00ac..01ddac0c 100644 --- a/Dependencies/luau/Luau/tests/Subtyping.test.cpp +++ b/Dependencies/luau/Luau/tests/Subtyping.test.cpp @@ -893,6 +893,9 @@ TEST_CASE_FIXTURE(SubtypeFixture, "{ @metatable { x: number } } numberType}}), tbl({{"x", builtinTypes->numberType}})); } +TEST_IS_SUBTYPE(builtinTypes->tableType, tbl({})); +TEST_IS_SUBTYPE(tbl({}), builtinTypes->tableType); + // Negated subtypes TEST_IS_NOT_SUBTYPE(negate(builtinTypes->neverType), builtinTypes->stringType); TEST_IS_SUBTYPE(negate(builtinTypes->unknownType), builtinTypes->stringType); @@ -1213,7 +1216,8 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...any) -> () <: (T...) -> ()") // See https://github.com/luau-lang/luau/issues/767 TEST_CASE_FIXTURE(SubtypeFixture, "(...unknown) -> () <: (T...) -> ()") { - TypeId unknownsToNothing = arena.addType(FunctionType{arena.addTypePack(VariadicTypePack{builtinTypes->unknownType}), builtinTypes->emptyTypePack}); + TypeId unknownsToNothing = + arena.addType(FunctionType{arena.addTypePack(VariadicTypePack{builtinTypes->unknownType}), builtinTypes->emptyTypePack}); TypeId genericTToAnys = arena.addType(FunctionType{genericAs, builtinTypes->emptyTypePack}); CHECK_MESSAGE(subtyping.isSubtype(unknownsToNothing, genericTToAnys).isSubtype, "(...unknown) -> () <: (T...) -> ()"); @@ -1222,25 +1226,11 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...unknown) -> () <: (T...) -> ()") TEST_CASE_FIXTURE(SubtypeFixture, "bill") { TypeId a = arena.addType(TableType{ - {{"a", builtinTypes->stringType}}, - TableIndexer{ - builtinTypes->stringType, - builtinTypes->numberType - }, - TypeLevel{}, - nullptr, - TableState::Sealed + {{"a", builtinTypes->stringType}}, TableIndexer{builtinTypes->stringType, builtinTypes->numberType}, TypeLevel{}, nullptr, TableState::Sealed }); TypeId b = arena.addType(TableType{ - {{"a", builtinTypes->stringType}}, - TableIndexer{ - builtinTypes->stringType, - builtinTypes->numberType - }, - TypeLevel{}, - nullptr, - TableState::Sealed + {{"a", builtinTypes->stringType}}, TableIndexer{builtinTypes->stringType, builtinTypes->numberType}, TypeLevel{}, nullptr, TableState::Sealed }); CHECK(subtyping.isSubtype(a, b).isSubtype); @@ -1250,22 +1240,17 @@ TEST_CASE_FIXTURE(SubtypeFixture, "bill") // TEST_CASE_FIXTURE(SubtypeFixture, "({[string]: number, a: string}) -> () <: ({[string]: number, a: string}) -> ()") TEST_CASE_FIXTURE(SubtypeFixture, "fred") { - auto makeTheType = [&]() { + auto makeTheType = [&]() + { TypeId argType = arena.addType(TableType{ {{"a", builtinTypes->stringType}}, - TableIndexer{ - builtinTypes->stringType, - builtinTypes->numberType - }, + TableIndexer{builtinTypes->stringType, builtinTypes->numberType}, TypeLevel{}, nullptr, TableState::Sealed }); - return arena.addType(FunctionType { - arena.addTypePack({argType}), - builtinTypes->emptyTypePack - }); + return arena.addType(FunctionType{arena.addTypePack({argType}), builtinTypes->emptyTypePack}); }; TypeId a = makeTheType(); diff --git a/Dependencies/luau/Luau/tests/ToDot.test.cpp b/Dependencies/luau/Luau/tests/ToDot.test.cpp index de7f4e50..4f0ae809 100644 --- a/Dependencies/luau/Luau/tests/ToDot.test.cpp +++ b/Dependencies/luau/Luau/tests/ToDot.test.cpp @@ -159,8 +159,10 @@ n4 [label="VariadicTypePack 4"]; n4 -> n5; n5 [label="string"]; n1 -> n6 [label="ret"]; -n6 [label="TypePack 6"]; -n6 -> n3; +n6 [label="BoundTypePack 6"]; +n6 -> n7; +n7 [label="TypePack 7"]; +n7 -> n3; })", toDot(requireType("f"), opts) ); diff --git a/Dependencies/luau/Luau/tests/ToString.test.cpp b/Dependencies/luau/Luau/tests/ToString.test.cpp index 828045d4..67e247f2 100644 --- a/Dependencies/luau/Luau/tests/ToString.test.cpp +++ b/Dependencies/luau/Luau/tests/ToString.test.cpp @@ -13,6 +13,7 @@ using namespace Luau; LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction); LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); LUAU_FASTFLAG(LuauAttributeSyntax); +LUAU_FASTFLAG(LuauUserDefinedTypeFunctions) TEST_SUITE_BEGIN("ToString"); @@ -21,8 +22,13 @@ TEST_CASE_FIXTURE(Fixture, "primitive") CheckResult result = check("local a = nil local b = 44 local c = 'lalala' local d = true"); LUAU_REQUIRE_NO_ERRORS(result); - // A variable without an annotation and with a nil literal should infer as 'free', not 'nil' - CHECK_NE("nil", toString(requireType("a"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("nil" == toString(requireType("a"))); + else + { + // A variable without an annotation and with a nil literal should infer as 'free', not 'nil' + CHECK_NE("nil", toString(requireType("a"))); + } CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("string", toString(requireType("c"))); @@ -39,6 +45,8 @@ TEST_CASE_FIXTURE(Fixture, "bound_types") TEST_CASE_FIXTURE(Fixture, "free_types") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check("local a"); LUAU_REQUIRE_NO_ERRORS(result); @@ -95,7 +103,6 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break") ToStringOptions opts; opts.useLineBreaks = true; - //clang-format off if (FFlag::DebugLuauDeferredConstraintResolution) CHECK_EQ( "{\n" @@ -114,7 +121,6 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break") "|}", toString(requireType("a"), opts) ); - //clang-format on } TEST_CASE_FIXTURE(Fixture, "nil_or_nil_is_nil_not_question_mark") @@ -160,6 +166,8 @@ TEST_CASE_FIXTURE(Fixture, "named_metatable") TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function createTbl(): NamedMetatable return setmetatable({}, {}) @@ -199,14 +207,24 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table") CHECK_EQ(std::string::npos, a.find("CYCLE")); CHECK_EQ(std::string::npos, a.find("TRUNCATED")); - //clang-format off - CHECK_EQ( - "t2 where " - "t1 = { __index: t1, __mul: ((t2, number) -> t2) & ((t2, t2) -> t2), new: () -> t2 } ; " - "t2 = { @metatable t1, {| x: number, y: number, z: number |} }", - a - ); - //clang-format on + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK( + "t2 where " + "t1 = { __index: t1, __mul: ((t2, number) -> t2) & ((t2, t2) -> t2), new: () -> t2 } ; " + "t2 = { @metatable t1, { x: number, y: number, z: number } }" == + a + ); + } + else + { + CHECK_EQ( + "t2 where " + "t1 = { __index: t1, __mul: ((t2, number) -> t2) & ((t2, t2) -> t2), new: () -> t2 } ; " + "t2 = { @metatable t1, {| x: number, y: number, z: number |} }", + a + ); + } } @@ -263,14 +281,12 @@ TEST_CASE_FIXTURE(Fixture, "complex_intersections_printed_on_multiple_lines") opts.useLineBreaks = true; opts.compositeTypesSingleLineLimit = 2; - //clang-format off CHECK_EQ( "boolean\n" "& number\n" "& string", toString(requireType("a"), opts) ); - //clang-format on } TEST_CASE_FIXTURE(Fixture, "overloaded_functions_always_printed_on_multiple_lines") @@ -282,13 +298,11 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_functions_always_printed_on_multiple_line ToStringOptions opts; opts.useLineBreaks = true; - //clang-format off CHECK_EQ( "((number) -> number)\n" "& ((string) -> string)", toString(requireType("a"), opts) ); - //clang-format on } TEST_CASE_FIXTURE(Fixture, "simple_unions_printed_on_one_line") @@ -313,14 +327,12 @@ TEST_CASE_FIXTURE(Fixture, "complex_unions_printed_on_multiple_lines") opts.compositeTypesSingleLineLimit = 2; opts.useLineBreaks = true; - //clang-format off CHECK_EQ( "boolean\n" "| number\n" "| string", toString(requireType("a"), opts) ); - //clang-format on } TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded") @@ -582,6 +594,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed") TEST_CASE_FIXTURE(Fixture, "toStringErrorPack") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function target(callback: nil) return callback(4, "hello") end )"); @@ -666,7 +680,10 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_inters LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("((number) -> ()) & t1 where t1 = () -> t1", toString(requireType("a"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("(() -> t1) & ((number) -> ()) where t1 = () -> t1" == toString(requireType("a"))); + else + CHECK_EQ("((number) -> ()) & t1 where t1 = () -> t1", toString(requireType("a"))); } TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param") @@ -824,7 +841,12 @@ TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_ function foo(x: a, y) end )"); - CHECK("(a, b) -> ()" == toString(requireType("foo"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK("(a, 'b) -> ()" == toString(requireType("foo"))); + } + else + CHECK("(a, b) -> ()" == toString(requireType("foo"))); } TEST_CASE_FIXTURE(Fixture, "tostring_unsee_ttv_if_array") @@ -934,4 +956,21 @@ TEST_CASE_FIXTURE(Fixture, "cycle_rooted_in_a_pack") CHECK("tp1 where tp1 = {| BaseField: unknown, BaseMethod: (tp1) -> () |}, number" == toString(thePack)); } +TEST_CASE_FIXTURE(Fixture, "correct_stringification_user_defined_type_functions") +{ + TypeFunction user{"user", nullptr}; + TypeFunctionInstanceType tftt{ + NotNull{&user}, + std::vector{builtinTypes->numberType}, // Type Function Arguments + {}, + {AstName{"woohoo"}}, // Type Function Name + std::nullopt + }; + + Type tv{tftt}; + + if (FFlag::DebugLuauDeferredConstraintResolution && FFlag::LuauUserDefinedTypeFunctions) + CHECK_EQ(toString(&tv, {}), "woohoo"); +} + TEST_SUITE_END(); diff --git a/Dependencies/luau/Luau/tests/TypeFunction.test.cpp b/Dependencies/luau/Luau/tests/TypeFunction.test.cpp index 98aa82e8..7b45a69c 100644 --- a/Dependencies/luau/Luau/tests/TypeFunction.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeFunction.test.cpp @@ -217,8 +217,14 @@ TEST_CASE_FIXTURE(Fixture, "add_function_at_work") CHECK(toString(requireType("a")) == "number"); CHECK(toString(requireType("b")) == "add"); CHECK(toString(requireType("c")) == "add"); - CHECK(toString(result.errors[0]) == "Operator '+' could not be applied to operands of types number and string; there is no corresponding overload for __add"); - CHECK(toString(result.errors[1]) == "Operator '+' could not be applied to operands of types string and number; there is no corresponding overload for __add"); + CHECK( + toString(result.errors[0]) == + "Operator '+' could not be applied to operands of types number and string; there is no corresponding overload for __add" + ); + CHECK( + toString(result.errors[1]) == + "Operator '+' could not be applied to operands of types string and number; there is no corresponding overload for __add" + ); } TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_add_function_at_work") @@ -290,7 +296,8 @@ TEST_CASE_FIXTURE(Fixture, "internal_functions_raise_errors") LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK( - toString(result.errors[0]) == "Operator '+' could not be applied to operands of types unknown and unknown; there is no corresponding overload for __add" + toString(result.errors[0]) == + "Operator '+' could not be applied to operands of types unknown and unknown; there is no corresponding overload for __add" ); } diff --git a/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp index fbb0d154..5b689939 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp @@ -104,6 +104,9 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias") TEST_CASE_FIXTURE(Fixture, "mismatched_generic_type_param") { + // We erroneously report an extra error in this case when the new solver is enabled. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type T = (A...) -> () )"); @@ -240,6 +243,9 @@ TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases") { + // CLI-116108 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict type T = { f: a, g: U } @@ -411,6 +417,8 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_function_types") TEST_CASE_FIXTURE(Fixture, "generic_param_remap") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + const std::string code = R"( -- An example of a forwarded use of a type that has different type arguments than parameters type A = {t:T, u:U, next:A?} @@ -535,11 +543,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation") TEST_CASE_FIXTURE(Fixture, "type_alias_local_mutation") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -type Cool = { a: number, b: string } -local c: Cool = { a = 1, b = "s" } -type NotCool = Cool -)"); + type Cool = { a: number, b: string } + local c: Cool = { a = 1, b = "s" } + type NotCool = Cool + )"); LUAU_REQUIRE_NO_ERRORS(result); std::optional ty = requireType("c"); @@ -554,6 +564,8 @@ type NotCool = Cool TEST_CASE_FIXTURE(Fixture, "type_alias_local_rename") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type Cool = { a: number, b: string } type NotCool = Cool @@ -615,16 +627,16 @@ type X = Import.X TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_generic_type") { fileResolver.source["game/A"] = R"( -export type X = { a: T, b: U, C: X? } -return {} + export type X = { a: T, b: U, C: X? } + return {} )"; CheckResult aResult = frontend.check("game/A"); LUAU_REQUIRE_NO_ERRORS(aResult); CheckResult bResult = check(R"( -local Import = require(game.A) -type X = Import.X + local Import = require(game.A) + type X = Import.X )"); LUAU_REQUIRE_NO_ERRORS(bResult); @@ -637,8 +649,8 @@ type X = Import.X CHECK_EQ(toString(*ty1, {true}), toString(*ty2, {true})); bResult = check(R"( -local Import = require(game.A) -type X = Import.X + local Import = require(game.A) + type X = Import.X )"); LUAU_REQUIRE_NO_ERRORS(bResult); @@ -648,8 +660,16 @@ type X = Import.X ty2 = lookupType("X"); REQUIRE(ty2); - CHECK_EQ(toString(*ty1, {true}), "t1 where t1 = {| C: t1?, a: T, b: U |}"); - CHECK_EQ(toString(*ty2, {true}), "{| C: t1, a: U, b: T |} where t1 = {| C: t1, a: U, b: T |}?"); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK(toString(*ty1, {true}) == "t1 where t1 = { C: t1?, a: T, b: U }"); + CHECK(toString(*ty2, {true}) == "t1 where t1 = { C: t1?, a: U, b: T }"); + } + else + { + CHECK_EQ(toString(*ty1, {true}), "t1 where t1 = {| C: t1?, a: T, b: U |}"); + CHECK_EQ(toString(*ty2, {true}), "{| C: t1, a: U, b: T |} where t1 = {| C: t1, a: U, b: T |}?"); + } } TEST_CASE_FIXTURE(Fixture, "module_export_free_type_leak") @@ -691,6 +711,9 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_ok") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1") { + // CLI-116108 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -- OK because forwarded types are used with their parameters. type Tree = { data: T, children: Forest } @@ -702,6 +725,9 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2") { + // CLI-116108 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -- Not OK because forwarded types are used with different types than their parameters. type Forest = {Tree<{T}>} @@ -723,6 +749,9 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok") { + // CLI-116108 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type Tree1 = { data: T, children: {Tree2} } type Tree2 = { data: U, children: {Tree1} } @@ -845,6 +874,9 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok") TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok") { + // CLI-116108 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -- this would be an infinite type if we allowed it type Tree = { data: T, children: {Tree<{T}>} } @@ -855,6 +887,9 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok") TEST_CASE_FIXTURE(Fixture, "report_shadowed_aliases") { + // CLI-116110 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + // We allow a previous type alias to depend on a future type alias. That exact feature enables a confusing example, like the following snippet, // which has the type alias FakeString point to the type alias `string` that which points to `number`. CheckResult result = check(R"( @@ -936,6 +971,9 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_locations") */ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_lose_track_of_PendingExpansionTypes_after_substitution") { + // CLI-114134 - We need egraphs to properly simplify these types. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + fileResolver.source["game/ReactCurrentDispatcher"] = R"( export type BasicStateAction = ((S) -> S) | S export type Dispatch = (A) -> () @@ -1115,6 +1153,20 @@ type Foo = Foo | string REQUIRE(err); } +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_adds_reduce_constraint_for_type_function") +{ + if (!FFlag::DebugLuauDeferredConstraintResolution || !FFlag::LuauUserDefinedTypeFunctions) + return; + + CheckResult result = check(R"( + type plus = add + + local sum: plus = 10 + )"); + + LUAU_CHECK_NO_ERRORS(result); +} + TEST_CASE_FIXTURE(Fixture, "user_defined_type_function_errors") { if (!FFlag::LuauUserDefinedTypeFunctions) diff --git a/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp index d392f43f..d52e6390 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp @@ -132,6 +132,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate") TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict local t = {'one', 'two', 'three'} @@ -510,6 +512,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "buffer_is_a_type") TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function nifty(x, y) print(x, y) @@ -547,6 +551,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes") TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_types") { + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( local string = string @@ -591,6 +598,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_count_mismatch") TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_correctly_ordered_types") { + // CLI-115690 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( --!strict string.format("%s", 123) @@ -687,21 +698,21 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash") local _ = function(l0,...) end local _ = function() - _(_); - _ += select(_()) + _(_); + _ += select(_()) end )"); - LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) { - // The argument count is the same, but the errors are currently cyclic type family instance ones. - // This isn't great, but the desired behavior here was that it didn't cause a crash and that is still true. - // The larger fix for this behavior will likely be integration of egraph-based normalization throughout the new solver. + // Counterintuitively, the parameter l0 is unconstrained and therefore it is valid to pass nil. + // The new solver therefore considers that parameter to be optional. + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK("Argument count mismatch. Function expects at least 1 argument, but none are specified" == toString(result.errors[0])); } else { + LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ("Argument count mismatch. Function '_' expects at least 1 argument, but none are specified", toString(result.errors[0])); CHECK_EQ("Argument count mismatch. Function 'select' expects 1 argument, but none are specified", toString(result.errors[1])); } @@ -709,6 +720,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash") TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range") { + // CLI-115720 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( select(5432598430953240958) )"); @@ -720,6 +735,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range") TEST_CASE_FIXTURE(BuiltinsFixture, "select_slightly_out_of_range") { + // CLI-115720 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( select(3, "a", 1) )"); @@ -750,6 +769,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail") TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_string_head") { + // CLI-115720 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( --!nonstrict local function f(...) @@ -769,6 +792,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_strin TEST_CASE_FIXTURE(Fixture, "string_format_as_method") { + // CLI-115690 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check("local _ = ('%s'):format(5)"); LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -792,6 +819,10 @@ TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument") TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2") { + // CLI-115690 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( local _ = ("%s %d").format("%d %s", "A type error", 2) )"); @@ -850,6 +881,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy") TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format") { + // CLI-115690 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( local fmt = string.format local s = fmt("%d", "oops") @@ -909,6 +944,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic") TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_correct_positions") { + // CLI-115690 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( ("%s%d%s"):format(1, "hello", true) string.format("%s%d%s", 1, "hello", true) @@ -1039,6 +1078,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types3") TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pack_tail_but_only_for_the_first_type") { + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( local function f(...: number?) return assert(...) @@ -1051,6 +1093,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pa TEST_CASE_FIXTURE(BuiltinsFixture, "assert_returns_false_and_string_iff_it_knows_the_first_argument_cannot_be_truthy") { + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // CLI-114134 - egraph simplification + return; + } + CheckResult result = check(R"( local function f(x: nil) return assert(x, "hmm") @@ -1080,7 +1128,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0])); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Key 'b' not found in table '{ a: number }'" == toString(result.errors[0])); + else + CHECK_EQ("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0])); CHECK(Location({13, 18}, {13, 23}) == result.errors[0].location); CHECK_EQ("number", toString(requireType("a"))); @@ -1095,11 +1146,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments") { + // In the new solver, nil can certainly be used where a generic is required, so all generic parameters are optional. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -local a = {b=setmetatable} -a.b() -a:b() -a:b({}) + local a = {b=setmetatable} + a.b() + a:b() + a:b({}) )"); LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function 'a.b' expects 2 arguments, but none are specified"); @@ -1109,8 +1163,8 @@ a:b({}) TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function") { CheckResult result = check(R"( -local function f(a: typeof(f)) end -)"); + local function f(a: typeof(f)) end + )"); LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ("Unknown global 'f'", toString(result.errors[0])); } diff --git a/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp index d5475a05..17b14082 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp @@ -128,6 +128,8 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_infer_that_a_parameter_must_be_a_particu TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function makeClone(o) return BaseClass.Clone(o) @@ -152,6 +154,34 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_t CHECK_EQ("BaseClass", toString(tm->wantedType)); } +TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class_using_new_solver") +{ + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + + CheckResult result = check(R"( + function makeClone(o) + return BaseClass.Clone(o) + end + + type Oopsies = { read BaseMethod: (Oopsies, number) -> ()} + + local oopsies: Oopsies = { + BaseMethod = function (self: Oopsies, i: number) + print('gadzooks!') + end + } + + makeClone(oopsies) + )"); + + LUAU_REQUIRE_ERROR_COUNT(1, result); + TypeMismatch* tm = get(result.errors.at(0)); + REQUIRE(tm != nullptr); + + CHECK_EQ("Oopsies", toString(tm->givenType)); + CHECK_EQ("BaseClass", toString(tm->wantedType)); +} + TEST_CASE_FIXTURE(ClassFixture, "assign_to_prop_of_class") { CheckResult result = check(R"( @@ -204,6 +234,9 @@ TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class_using_string") TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive") { + // This is allowed in the new solver + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local v = Vector2.New(0, 5) v = 444 @@ -364,9 +397,17 @@ TEST_CASE_FIXTURE(ClassFixture, "table_class_unification_reports_sane_errors_for foo(a) )"); - LUAU_REQUIRE_ERROR_COUNT(2, result); - REQUIRE_EQ("Key 'w' not found in class 'Vector2'", toString(result.errors.at(0))); - REQUIRE_EQ("Key 'x' not found in class 'Vector2'. Did you mean 'X'?", toString(result.errors[1])); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK("Type 'Vector2' could not be converted into '{ Y: number, w: number, x: number }'" == toString(result.errors[0])); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + REQUIRE_EQ("Key 'w' not found in class 'Vector2'", toString(result.errors.at(0))); + REQUIRE_EQ("Key 'x' not found in class 'Vector2'. Did you mean 'X'?", toString(result.errors[1])); + } } TEST_CASE_FIXTURE(ClassFixture, "class_unification_type_mismatch_is_correct_order") @@ -412,15 +453,27 @@ b(a) )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type 'Vector2' could not be converted into '{- X: number, Y: string -}' + + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK("Type 'number' could not be converted into 'string'" == toString(result.errors.at(0))); + } + else + { + const std::string expected = R"(Type 'Vector2' could not be converted into '{- X: number, Y: string -}' caused by: Property 'Y' is not compatible. Type 'number' could not be converted into 'string')"; - CHECK_EQ(expected, toString(result.errors.at(0))); + + CHECK_EQ(expected, toString(result.errors.at(0))); + } } TEST_CASE_FIXTURE(ClassFixture, "class_type_mismatch_with_name_conflict") { + // CLI-116433 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local i = ChildClass.New() type ChildClass = { x: number } @@ -611,10 +664,14 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local y = x[true] )"); - - CHECK_EQ( - toString(result.errors.at(0)), "Type 'boolean' could not be converted into 'number | string'; none of the union options are compatible" - ); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK( + "Type 'boolean' could not be converted into 'number | string'" == toString(result.errors.at(0)) + ); + else + CHECK_EQ( + toString(result.errors.at(0)), "Type 'boolean' could not be converted into 'number | string'; none of the union options are compatible" + ); } { CheckResult result = check(R"( @@ -622,9 +679,14 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") x[true] = 42 )"); - CHECK_EQ( - toString(result.errors.at(0)), "Type 'boolean' could not be converted into 'number | string'; none of the union options are compatible" - ); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK( + "Type 'boolean' could not be converted into 'number | string'" == toString(result.errors.at(0)) + ); + else + CHECK_EQ( + toString(result.errors.at(0)), "Type 'boolean' could not be converted into 'number | string'; none of the union options are compatible" + ); } // Test type checking for the return type of the indexer (i.e. a number) @@ -633,7 +695,13 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local x : IndexableClass x.key = "string value" )"); - CHECK_EQ(toString(result.errors.at(0)), "Type 'string' could not be converted into 'number'"); + + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // Disabled for now. CLI-115686 + } + else + CHECK_EQ(toString(result.errors.at(0)), "Type 'string' could not be converted into 'number'"); } { CheckResult result = check(R"( @@ -682,7 +750,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local y = x["key"] )"); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ(toString(result.errors.at(0)), "Key 'key' not found in class 'IndexableNumericKeyClass'"); + CHECK(toString(result.errors.at(0)) == "Key 'key' not found in class 'IndexableNumericKeyClass'"); else CHECK_EQ(toString(result.errors.at(0)), "Type 'string' could not be converted into 'number'"); } diff --git a/Dependencies/luau/Luau/tests/TypeInfer.definitions.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.definitions.test.cpp index 631913dd..e1eaf5e9 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.definitions.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.definitions.test.cpp @@ -7,8 +7,6 @@ #include "doctest.h" -LUAU_FASTFLAG(LuauDeclarationExtraPropData) - using namespace Luau; TEST_SUITE_BEGIN("DefinitionTests"); @@ -346,8 +344,6 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols") TEST_CASE_FIXTURE(Fixture, "definitions_symbols_are_generated_for_recursively_referenced_types") { - ScopedFastFlag luauDeclarationExtraPropData{FFlag::LuauDeclarationExtraPropData, true}; - loadDefinition(R"( declare class MyClass function myMethod(self) diff --git a/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp index 20880565..773636c6 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp @@ -11,6 +11,7 @@ #include "ClassFixture.h" #include "Fixture.h" +#include "ScopedFlags.h" #include "doctest.h" using namespace Luau; @@ -255,7 +256,7 @@ TEST_CASE_FIXTURE(Fixture, "list_only_alternative_overloads_that_match_argument_ REQUIRE(ei); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK("Available overloads: (number) -> number; and (number) -> string" == ei->message); + CHECK("Available overloads: (number) -> number; (number) -> string; and (number, number) -> number" == ei->message); else CHECK_EQ("Other overloads are also not viable: (number) -> string", ei->message); } @@ -310,6 +311,9 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type_from_selected_overload") TEST_CASE_FIXTURE(Fixture, "too_many_arguments") { + // This is not part of the new non-strict specification currently. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!nonstrict @@ -476,13 +480,28 @@ TEST_CASE_FIXTURE(Fixture, "another_higher_order_function") TEST_CASE_FIXTURE(Fixture, "another_other_higher_order_function") { - CheckResult result = check(R"( - local d - d:foo() - d:foo() - )"); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CheckResult result = check(R"( + local function f(d) + d:foo() + d:foo() + end + )"); - LUAU_REQUIRE_NO_ERRORS(result); + LUAU_REQUIRE_NO_ERRORS(result); + + } + else + { + CheckResult result = check(R"( + local d + d:foo() + d:foo() + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + } } TEST_CASE_FIXTURE(Fixture, "local_function") @@ -585,6 +604,9 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_functions_allowed_in_nonstrict") TEST_CASE_FIXTURE(Fixture, "duplicate_functions_with_different_signatures_not_allowed_in_nonstrict") { + // This is not part of the spec for the new non-strict mode currently. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!nonstrict function foo(): number @@ -612,7 +634,7 @@ TEST_CASE_FIXTURE(Fixture, "complicated_return_types_require_an_explicit_annotat local i = 0 function most_of_the_natural_numbers(): number? if i < 10 then - i = i + 1 + i += 1 return i else return nil @@ -737,7 +759,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4") end end - function mergesort(arr, comp) + function mergesort(arr: {T}, comp: (T, T) -> boolean) local work = {} for i = 1, #arr do work[i] = arr[i] @@ -756,7 +778,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4") end )"); - LUAU_REQUIRE_NO_ERRORS(result); + // This function currently has a bug in the new solver reporting `{T} | {T}` is not a table. + if (FFlag::DebugLuauDeferredConstraintResolution) + LUAU_REQUIRE_ERRORS(result); + else + LUAU_REQUIRE_NO_ERRORS(result); /* * mergesort takes two arguments: an array of some type T and a function that takes two Ts. @@ -861,6 +887,9 @@ TEST_CASE_FIXTURE(Fixture, "another_indirect_function_case_where_it_is_ok_to_pro TEST_CASE_FIXTURE(Fixture, "report_exiting_without_return_nonstrict") { + // new non-strict mode spec does not include this error yet. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!nonstrict @@ -985,11 +1014,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_lea opts.exhaustive = true; opts.maxTableLength = 0; - CHECK_EQ("{any}", toString(requireType("tab"), opts)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("{string}", toString(requireType("tab"), opts)); + else + CHECK_EQ("{any}", toString(requireType("tab"), opts)); } TEST_CASE_FIXTURE(Fixture, "too_many_return_values") { + // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict @@ -1011,6 +1046,9 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values") TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses") { + // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict @@ -1032,6 +1070,9 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses") TEST_CASE_FIXTURE(Fixture, "too_many_return_values_no_function") { + // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict @@ -1072,13 +1113,25 @@ TEST_CASE_FIXTURE(Fixture, "function_does_not_return_enough_values") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); - CountMismatch* acm = get(result.errors[0]); - REQUIRE(acm); - CHECK_EQ(acm->context, CountMismatch::Return); - CHECK_EQ(acm->expected, 2); - CHECK_EQ(acm->actual, 1); + auto tpm = get(result.errors[0]); + REQUIRE(tpm); + CHECK("number, string" == toString(tpm->wantedTp)); + CHECK("number" == toString(tpm->givenTp)); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + + CountMismatch* acm = get(result.errors[0]); + REQUIRE(acm); + CHECK_EQ(acm->context, CountMismatch::Return); + CHECK_EQ(acm->expected, 2); + CHECK_EQ(acm->actual, 1); + } } TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language") @@ -1100,13 +1153,19 @@ TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language") REQUIRE(tm1); CHECK_EQ("(string) -> number", toString(tm1->wantedType)); - CHECK_EQ("(string, *error-type*) -> number", toString(tm1->givenType)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("(unknown, unknown) -> number", toString(tm1->givenType)); + else + CHECK_EQ("(string, *error-type*) -> number", toString(tm1->givenType)); auto tm2 = get(result.errors[1]); REQUIRE(tm2); CHECK_EQ("(number, number) -> (number, number)", toString(tm2->wantedType)); - CHECK_EQ("(string, *error-type*) -> number", toString(tm2->givenType)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("(unknown, unknown) -> number", toString(tm1->givenType)); + else + CHECK_EQ("(string, *error-type*) -> number", toString(tm2->givenType)); } TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type") @@ -1123,7 +1182,10 @@ TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type") LUAU_REQUIRE_NO_ERRORS(result); TypeId type = requireTypeAtPosition(Position(6, 14)); - CHECK_EQ("(tbl, number, number) -> number", toString(type)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("(unknown, number, number) -> number", toString(type)); + else + CHECK_EQ("(tbl, number, number) -> number", toString(type)); auto ftv = get(follow(type)); REQUIRE(ftv); CHECK(ftv->hasSelf); @@ -1166,13 +1228,20 @@ TEST_CASE_FIXTURE(Fixture, "return_type_by_overload") LUAU_REQUIRE_ERRORS(result); CHECK_EQ("string", toString(requireType("x"))); - CHECK_EQ("number", toString(requireType("y"))); + // the new solver does not currently "favor" arity-matching overloads when the call itself is ill-typed. + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("string", toString(requireType("y"))); + else + CHECK_EQ("number", toString(requireType("y"))); // Should this be string|number? CHECK_EQ("string", toString(requireType("z"))); } TEST_CASE_FIXTURE(BuiltinsFixture, "infer_anonymous_function_arguments") { + // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + // Simple direct arg to arg propagation CheckResult result = check(R"( type Table = { x: number, y: number } @@ -1289,6 +1358,9 @@ f(function(x) return x * 2 end) TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument") { + // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function sum(x: a, y: a, f: (a, a) -> a) return f(x, y) end return sum(2, 3, function(a, b) return a + b end) @@ -1317,6 +1389,9 @@ local r = foldl(a, {s=0,c=0}, function(a, b) return {s = a.s + b, c = a.c + 1} e TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded") { + // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function g1(a: T, f: (T) -> T) return f(a) end local function g2(a: T, b: T, f: (T, T) -> T) return f(a, b) end @@ -1381,6 +1456,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "variadic_any_is_compatible_with_a_generic_Ty TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments_outside_call") { + // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type Table = { x: number, y: number } local f: (Table) -> number = function(t) return t.x + t.y end @@ -1412,11 +1490,18 @@ local function i(): ...{string|number} end )"); - LUAU_REQUIRE_NO_ERRORS(result); + // `h` regresses in the new solver, the return type is not being pushed into the body. + if (FFlag::DebugLuauDeferredConstraintResolution) + LUAU_REQUIRE_ERROR_COUNT(1, result); + else + LUAU_REQUIRE_NO_ERRORS(result); } TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg_count") { + // FIXME: CLI-116111 test disabled until type path stringification is improved + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type A = (number, number) -> string type B = (number) -> string @@ -1437,6 +1522,9 @@ caused by: TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg") { + // FIXME: CLI-116111 test disabled until type path stringification is improved + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type A = (number, number) -> string type B = (number, string) -> string @@ -1458,6 +1546,9 @@ Type 'string' could not be converted into 'number')"; TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_count") { + // FIXME: CLI-116111 test disabled until type path stringification is improved + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type A = (number, number) -> (number) type B = (number, number) -> (number, boolean) @@ -1478,6 +1569,9 @@ caused by: TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret") { + // FIXME: CLI-116111 test disabled until type path stringification is improved + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type A = (number, number) -> string type B = (number, number) -> number @@ -1499,6 +1593,9 @@ Type 'string' could not be converted into 'number')"; TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_mult") { + // FIXME: CLI-116111 test disabled until type path stringification is improved + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type A = (number, number) -> (number, string) type B = (number, number) -> (number, boolean) @@ -1578,9 +1675,18 @@ t.f = function(x) end )"); - LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), R"(Type 'string' could not be converted into 'number')"); - CHECK_EQ(toString(result.errors[1]), R"(Type 'string' could not be converted into 'number')"); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ(toString(result.errors[0]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); + CHECK_EQ(toString(result.errors[1]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ(toString(result.errors[0]), R"(Type 'string' could not be converted into 'number')"); + CHECK_EQ(toString(result.errors[1]), R"(Type 'string' could not be converted into 'number')"); + } } TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_the_right_time2") @@ -1611,6 +1717,9 @@ TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_th TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_the_right_time3") { + // This test regresses in the new solver, but is sort of nonsensical insofar as `foo` is known to be `nil`, so it's "right" to not be able to call it. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local foo @@ -1637,8 +1746,15 @@ t.f = function(x) end )"); - LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ(toString(result.errors[0]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ(toString(result.errors[0]), R"(Type '(string) -> string' could not be converted into '((number) -> number)?' @@ -1651,7 +1767,8 @@ could not be converted into caused by: Argument #1 type is not compatible. Type 'number' could not be converted into 'string')"); - CHECK_EQ(toString(result.errors[1]), R"(Type 'string' could not be converted into 'number')"); + CHECK_EQ(toString(result.errors[1]), R"(Type 'string' could not be converted into 'number')"); + } } TEST_CASE_FIXTURE(Fixture, "strict_mode_ok_with_missing_arguments") @@ -1666,6 +1783,9 @@ TEST_CASE_FIXTURE(Fixture, "strict_mode_ok_with_missing_arguments") TEST_CASE_FIXTURE(Fixture, "function_statement_sealed_table_assignment_through_indexer") { + // FIXME: CLI-116122 bug where `t:b` does not check against the type from the indexer annotation on `t`. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local t: {[string]: () -> number} = {} @@ -1708,6 +1828,9 @@ TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic") TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic") { + // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function test(a: number, b: string, ...) return 1 @@ -1733,6 +1856,9 @@ wrapper(test) TEST_CASE_FIXTURE(BuiltinsFixture, "too_few_arguments_variadic_generic2") { + // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function test(a: number, b: string, ...) return 1 @@ -1807,7 +1933,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_infer_parameter_types_for_functions_from_their_ CHECK_EQ("(a) -> a", toString(requireType("f"))); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("({+ p: {+ q: a +} +}) -> a & ~false", toString(requireType("g"))); + CHECK_EQ("({ read p: { read q: unknown } }) -> ~(false?)?", toString(requireType("g"))); else CHECK_EQ("({+ p: {+ q: nil +} +}) -> nil", toString(requireType("g"))); } @@ -1854,24 +1980,43 @@ u.b().foo() )"); LUAU_REQUIRE_ERROR_COUNT(9, result); - CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function 'foo1' expects 1 argument, but none are specified"); - CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function 'foo2' expects 1 to 2 arguments, but none are specified"); - CHECK_EQ(toString(result.errors[2]), "Argument count mismatch. Function 'foo3' expects 1 to 3 arguments, but none are specified"); - CHECK_EQ(toString(result.errors[3]), "Argument count mismatch. Function 'string.find' expects 2 to 4 arguments, but none are specified"); - CHECK_EQ(toString(result.errors[4]), "Argument count mismatch. Function 't.foo' expects at least 1 argument, but none are specified"); - CHECK_EQ(toString(result.errors[5]), "Argument count mismatch. Function 't.bar' expects 2 to 3 arguments, but only 1 is specified"); - CHECK_EQ(toString(result.errors[6]), "Argument count mismatch. Function 'u.a.foo' expects at least 1 argument, but none are specified"); - CHECK_EQ(toString(result.errors[7]), "Argument count mismatch. Function 'u.a.foo' expects at least 1 argument, but none are specified"); - CHECK_EQ(toString(result.errors[8]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // These improvements to the error messages are currently regressed in the new type solver. + CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function expects 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function expects 1 to 2 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[2]), "Argument count mismatch. Function expects 1 to 3 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[3]), "Argument count mismatch. Function expects 2 to 4 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[4]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[5]), "Argument count mismatch. Function expects 2 to 3 arguments, but only 1 is specified"); + CHECK_EQ(toString(result.errors[6]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[7]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[8]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + } + else + { + CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function 'foo1' expects 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function 'foo2' expects 1 to 2 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[2]), "Argument count mismatch. Function 'foo3' expects 1 to 3 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[3]), "Argument count mismatch. Function 'string.find' expects 2 to 4 arguments, but none are specified"); + CHECK_EQ(toString(result.errors[4]), "Argument count mismatch. Function 't.foo' expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[5]), "Argument count mismatch. Function 't.bar' expects 2 to 3 arguments, but only 1 is specified"); + CHECK_EQ(toString(result.errors[6]), "Argument count mismatch. Function 'u.a.foo' expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[7]), "Argument count mismatch. Function 'u.a.foo' expects at least 1 argument, but none are specified"); + CHECK_EQ(toString(result.errors[8]), "Argument count mismatch. Function expects at least 1 argument, but none are specified"); + } } // This might be surprising, but since 'any' became optional, unannotated functions in non-strict 'expect' 0 arguments TEST_CASE_FIXTURE(BuiltinsFixture, "improved_function_arg_mismatch_error_nonstrict") { + // This behavior is not part of the current specification of the new type solver. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( ---!nonstrict -local function foo(a, b) end -foo(string.find("hello", "e")) + --!nonstrict + local function foo(a, b) end + foo(string.find("hello", "e")) )"); LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -1880,6 +2025,9 @@ foo(string.find("hello", "e")) TEST_CASE_FIXTURE(Fixture, "luau_subtyping_is_np_hard") { + // The case that _should_ succeed here (`z = x`) does not currently in the new solver. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict @@ -1954,7 +2102,16 @@ TEST_CASE_FIXTURE(Fixture, "concrete_functions_are_not_supertypes_of_function") LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK(6 == result.errors[0].location.begin.line); + auto tm1 = get(result.errors[0]); + REQUIRE(tm1); + CHECK("() -> ()" == toString(tm1->wantedType)); + CHECK("function" == toString(tm1->givenType)); + CHECK(7 == result.errors[1].location.begin.line); + auto tm2 = get(result.errors[1]); + REQUIRE(tm2); + CHECK("(T) -> T" == toString(tm2->wantedType)); + CHECK("function" == toString(tm2->givenType)); } TEST_CASE_FIXTURE(Fixture, "other_things_are_not_related_to_function") @@ -1991,9 +2148,8 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "dont_assert_when_the_tarjan_limit_is_exceeded_during_generalization") { - ScopedFastInt sfi{FInt::LuauTarjanChildLimit, 2}; - if (!FFlag::DebugLuauDeferredConstraintResolution) - return; + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastInt sfi{FInt::LuauTarjanChildLimit, 1}; CheckResult result = check(R"( function f(t) @@ -2003,8 +2159,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_assert_when_the_tarjan_limit_is_exceede LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_MESSAGE(get(result.errors[0]), "Expected CodeTooComplex but got: " << toString(result.errors[0])); - CHECK(Location({1, 17}, {1, 18}) == result.errors[0].location); + CHECK_MESSAGE(get(result.errors[0]), "Expected UnificationTooComplex but got: " << toString(result.errors[0])); } /* We had a bug under DCR where instantiated type packs had a nullptr scope. @@ -2014,7 +2169,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_assert_when_the_tarjan_limit_is_exceede TEST_CASE_FIXTURE(Fixture, "instantiated_type_packs_must_have_a_non_null_scope") { CheckResult result = check(R"( - function pcall(...: A...): R... + function pcall(...: (A...) -> R...): (boolean, R...) + return nil :: any end type Dispatch = (A) -> () @@ -2068,8 +2224,13 @@ TEST_CASE_FIXTURE(Fixture, "function_exprs_are_generalized_at_signature_scope_no )"); LUAU_REQUIRE_NO_ERRORS(result); - // note that b is not in the generic list; it is free, the unconstrained type of `bar`. - CHECK(toString(requireType("foo")) == "(a) -> b"); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK(toString(requireType("foo")) == "((unknown) -> nil)?"); + else + { + // note that b is not in the generic list; it is free, the unconstrained type of `bar`. + CHECK(toString(requireType("foo")) == "(a) -> b"); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_but_their_arguments_are_incompatible") @@ -2082,46 +2243,58 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_bu local ret: number = foo(vec2, { x = 5 }) )"); - // In the old solver, this produces a very strange result: - // - // Here, we instantiate `(x: a, y: a?) -> a` with a fresh type `'a` for `a`. - // In argument #1, we unify `vec2` with `'a`. - // This is ok, so we record an equality constraint `'a` with `vec2`. - // In argument #2, we unify `{ x: number }` with `'a?`. - // This fails because `'a` has equality constraint with `vec2`, - // so `{ x: number } <: vec2?`, which is false. - // - // If the unifications were to be committed, then it'd result in the following type error: - // - // Type '{ x: number }' could not be converted into 'vec2?' - // caused by: - // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' - // - // However, whenever we check the argument list, if there's an error, we don't commit the unifications, so it actually looks like this: - // - // Type '{ x: number }' could not be converted into 'a?' - // caused by: - // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' - // - // Then finally, that generic is left floating free, and since the function returns that generic, - // that free type is then later bound to `number`, which succeeds and mutates the type graph. - // This again changes the type error where `a` becomes bound to `number`. - // - // Type '{ x: number }' could not be converted into 'number?' - // caused by: - // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' - // - // Uh oh, that type error is extremely confusing for people who doesn't know how that went down. - // Really, what should happen is we roll each argument incompatibility into a union type, but that needs local type inference. + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); - LUAU_REQUIRE_ERROR_COUNT(2, result); + auto tm = get(result.errors[0]); + REQUIRE(tm); + CHECK("number" == toString(tm->wantedType)); + CHECK("{ x: number }" == toString(tm->givenType)); + } + else + { + // In the old solver, this produces a very strange result: + // + // Here, we instantiate `(x: a, y: a?) -> a` with a fresh type `'a` for `a`. + // In argument #1, we unify `vec2` with `'a`. + // This is ok, so we record an equality constraint `'a` with `vec2`. + // In argument #2, we unify `{ x: number }` with `'a?`. + // This fails because `'a` has equality constraint with `vec2`, + // so `{ x: number } <: vec2?`, which is false. + // + // If the unifications were to be committed, then it'd result in the following type error: + // + // Type '{ x: number }' could not be converted into 'vec2?' + // caused by: + // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' + // + // However, whenever we check the argument list, if there's an error, we don't commit the unifications, so it actually looks like this: + // + // Type '{ x: number }' could not be converted into 'a?' + // caused by: + // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' + // + // Then finally, that generic is left floating free, and since the function returns that generic, + // that free type is then later bound to `number`, which succeeds and mutates the type graph. + // This again changes the type error where `a` becomes bound to `number`. + // + // Type '{ x: number }' could not be converted into 'number?' + // caused by: + // [...] Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y' + // + // Uh oh, that type error is extremely confusing for people who doesn't know how that went down. + // Really, what should happen is we roll each argument incompatibility into a union type, but that needs local type inference. - const std::string expected = R"(Type '{ x: number }' could not be converted into 'vec2?' + LUAU_REQUIRE_ERROR_COUNT(2, result); + + const std::string expected = R"(Type '{ x: number }' could not be converted into 'vec2?' caused by: None of the union options are compatible. For example: Table type '{ x: number }' not compatible with type 'vec2' because the former is missing field 'y')"; - CHECK_EQ(expected, toString(result.errors[0])); - CHECK_EQ("Type 'vec2' could not be converted into 'number'", toString(result.errors[1])); + CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ("Type 'vec2' could not be converted into 'number'", toString(result.errors[1])); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_but_their_arguments_are_incompatible_2") @@ -2134,10 +2307,22 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_bu local z: boolean = f(5, "five") )"); - LUAU_REQUIRE_ERROR_COUNT(2, result); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + + auto tm = get(result.errors[0]); + REQUIRE(tm); + CHECK("boolean" == toString(tm->wantedType)); + CHECK("number | string" == toString(tm->givenType)); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), "Type 'string' could not be converted into 'number'"); - CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'boolean'"); + CHECK_EQ(toString(result.errors[0]), "Type 'string' could not be converted into 'number'"); + CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'boolean'"); + } } TEST_CASE_FIXTURE(Fixture, "attempt_to_call_an_intersection_of_tables") @@ -2183,10 +2368,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "attempt_to_call_an_intersection_of_tables_wi TEST_CASE_FIXTURE(Fixture, "generic_packs_are_not_variadic") { - // This test is blocking CI until subtyping is complete. - if (!FFlag::DebugLuauDeferredConstraintResolution) - return; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; CheckResult result = check(R"( @@ -2201,7 +2382,9 @@ TEST_CASE_FIXTURE(Fixture, "generic_packs_are_not_variadic") apply(add, 5) )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); + // FIXME: this errored at some point, but doesn't anymore. + // the desired behavior here is erroring. + LUAU_REQUIRE_NO_ERRORS(result); } TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str") @@ -2316,14 +2499,11 @@ end if (FFlag::DebugLuauDeferredConstraintResolution) { - LUAU_REQUIRE_ERROR_COUNT(4, result); - CHECK( - toString(result.errors[0]) == - "Operator '-' could not be applied to operands of types unknown and number; there is no corresponding overload for __sub" - ); + LUAU_REQUIRE_ERROR_COUNT(5, result); + CHECK(get(result.errors[0])); CHECK( toString(result.errors[1]) == - "Operator '-' could not be applied to operands of types unknown and number; there is no corresponding overload for __sub" + "Type pack '*blocked-tp-1*' could not be converted into 'boolean'; type *blocked-tp-1*.tail() (*blocked-tp-1*) is not a subtype of boolean (boolean)" ); CHECK( toString(result.errors[2]) == @@ -2333,6 +2513,10 @@ end toString(result.errors[3]) == "Operator '-' could not be applied to operands of types unknown and number; there is no corresponding overload for __sub" ); + CHECK( + toString(result.errors[4]) == + "Operator '-' could not be applied to operands of types unknown and number; there is no corresponding overload for __sub" + ); } else { @@ -2415,17 +2599,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_arg_type_2") frontend.options.retainFullTypeGraphs = false; CheckResult result = check(R"( -local function escape_fslash(pre) - return (#pre % 2 == 0 and '\\' or '') .. pre .. '.' -end -)"); + local function escape_fslash(pre) + return (#pre % 2 == 0 and '\\' or '') .. pre .. '.' + end + )"); LUAU_REQUIRE_ERRORS(result); - auto err = get(result.errors.back()); - LUAU_ASSERT(err); - CHECK("unknown" == toString(err->recommendedReturn)); - REQUIRE(err->recommendedArgs.size() == 1); - CHECK("a" == toString(err->recommendedArgs[0].second)); + auto err = get(result.errors.back()); + REQUIRE(err); + CHECK("a" == toString(err->ty)); } TEST_CASE_FIXTURE(Fixture, "local_function_fwd_decl_doesnt_crash") @@ -2463,11 +2645,26 @@ TEST_CASE_FIXTURE(Fixture, "bidirectional_checking_of_callback_property") LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_MESSAGE(get(result.errors[0]), "Expected UnknownProperty but got " << result.errors[0]); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + auto tm = get(result.errors[0]); + REQUIRE(tm); - Location location = result.errors[0].location; - CHECK(location.begin.line == 7); - CHECK(location.end.line == 7); + CHECK("((Point) -> ())?" == toString(tm->wantedType)); + CHECK("({ read z: number }) -> ()" == toString(tm->givenType)); + + Location location = result.errors[0].location; + CHECK(location.begin.line == 6); + CHECK(location.end.line == 8); + } + else + { + CHECK_MESSAGE(get(result.errors[0]), "Expected UnknownProperty but got " << result.errors[0]); + + Location location = result.errors[0].location; + CHECK(location.begin.line == 7); + CHECK(location.end.line == 7); + } } TEST_CASE_FIXTURE(ClassFixture, "bidirectional_inference_of_class_methods") @@ -2698,7 +2895,7 @@ TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types") auto tm2 = get(result.errors[1]); REQUIRE(tm2); CHECK(toString(tm2->wantedTp) == "string"); - CHECK(toString(tm2->givenTp) == "~(false?)"); + CHECK(toString(tm2->givenTp) == "buffer | class | function | number | string | table | thread | true"); } else { diff --git a/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp index 7e2b0645..baef9245 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp @@ -4,6 +4,7 @@ #include "Fixture.h" +#include "ScopedFlags.h" #include "doctest.h" using namespace Luau; @@ -331,6 +332,9 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed") TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect") { + ScopedFastFlag dcr{ + FFlag::DebugLuauDeferredConstraintResolution, false + }; // CLI-116476 Subtyping between type alias and an equivalent but not named type isn't working. CheckResult result = check(R"( type X = { x: (number) -> number } type Y = { y: (string) -> string } @@ -368,6 +372,7 @@ caused by: TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect") { + ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, false}; // CLI- // After normalization, previous 'table_intersection_write_sealed_indirect' is identical to this one CheckResult result = check(R"( type XY = { x: (number) -> number, y: (string) -> string } @@ -447,14 +452,17 @@ end LUAU_REQUIRE_ERROR_COUNT(1, result); if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK_EQ(R"(Type pack 'X & Y & Z' could not be converted into 'number'; type X & Y & Z[0][0] (X) is not a subtype of number[0] (number) + CHECK_EQ( + R"(Type pack 'X & Y & Z' could not be converted into 'number'; type X & Y & Z[0][0] (X) is not a subtype of number[0] (number) type X & Y & Z[0][1] (Y) is not a subtype of number[0] (number) type X & Y & Z[0][2] (Z) is not a subtype of number[0] (number))", - toString(result.errors[0])); + toString(result.errors[0]) + ); } else CHECK_EQ( - toString(result.errors[0]), R"(Type 'X & Y & Z' could not be converted into 'number'; none of the intersection parts are compatible)"); + toString(result.errors[0]), R"(Type 'X & Y & Z' could not be converted into 'number'; none of the intersection parts are compatible)" + ); } TEST_CASE_FIXTURE(Fixture, "overload_is_not_a_function") @@ -497,13 +505,16 @@ TEST_CASE_FIXTURE(Fixture, "intersect_bool_and_false") LUAU_REQUIRE_ERROR_COUNT(1, result); if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK_EQ(R"(Type 'boolean & false' could not be converted into 'true'; type boolean & false[0] (boolean) is not a subtype of true (true) + CHECK_EQ( + R"(Type 'boolean & false' could not be converted into 'true'; type boolean & false[0] (boolean) is not a subtype of true (true) type boolean & false[1] (false) is not a subtype of true (true))", - toString(result.errors[0])); + toString(result.errors[0]) + ); } else CHECK_EQ( - toString(result.errors[0]), "Type 'boolean & false' could not be converted into 'true'; none of the intersection parts are compatible"); + toString(result.errors[0]), "Type 'boolean & false' could not be converted into 'true'; none of the intersection parts are compatible" + ); } TEST_CASE_FIXTURE(Fixture, "intersect_false_and_bool_and_false") @@ -522,10 +533,13 @@ TEST_CASE_FIXTURE(Fixture, "intersect_false_and_bool_and_false") R"(Type 'boolean & false & false' could not be converted into 'true'; type boolean & false & false[0] (false) is not a subtype of true (true) type boolean & false & false[1] (boolean) is not a subtype of true (true) type boolean & false & false[2] (false) is not a subtype of true (true))", - toString(result.errors[0])); + toString(result.errors[0]) + ); else - CHECK_EQ(toString(result.errors[0]), - "Type 'boolean & false & false' could not be converted into 'true'; none of the intersection parts are compatible"); + CHECK_EQ( + toString(result.errors[0]), + "Type 'boolean & false & false' could not be converted into 'true'; none of the intersection parts are compatible" + ); } TEST_CASE_FIXTURE(Fixture, "intersect_saturate_overloaded_functions") @@ -567,6 +581,9 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_saturate_overloaded_functions") { + ScopedFastFlag dcr{ + FFlag::DebugLuauDeferredConstraintResolution, false + }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f(x: ((number) -> number) & ((string) -> string)) local y : ((number | string) -> (number | string)) = x -- OK @@ -745,6 +762,9 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_result") { + ScopedFastFlag dcr{ + FFlag::DebugLuauDeferredConstraintResolution, false + }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f() function g(x : ((number) -> number) & ((nil) -> unknown)) @@ -764,6 +784,9 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_arguments") { + ScopedFastFlag dcr{ + FFlag::DebugLuauDeferredConstraintResolution, false + }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f() function g(x : ((number) -> number?) & ((unknown) -> string?)) @@ -792,12 +815,36 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_never_result") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ( + R"(Type + '((nil) -> never) & ((number) -> number)' +could not be converted into + '(number?) -> number'; type ((nil) -> never) & ((number) -> number)[0].arguments()[0] (number) is not a supertype of (number?) -> number.arguments()[0][1] (nil) + type ((nil) -> never) & ((number) -> number)[1].arguments()[0] (nil) is not a supertype of (number?) -> number.arguments()[0][0] (number))", + toString(result.errors[0]) + ); + CHECK_EQ( + R"(Type + '((nil) -> never) & ((number) -> number)' +could not be converted into + '(number?) -> never'; type ((nil) -> never) & ((number) -> number)[0].arguments()[0] (number) is not a supertype of (number?) -> never.arguments()[0][1] (nil) + type ((nil) -> never) & ((number) -> number)[0].returns()[0] (number) is not a subtype of (number?) -> never.returns()[0] (never) + type ((nil) -> never) & ((number) -> number)[1].arguments()[0] (nil) is not a supertype of (number?) -> never.arguments()[0][0] (number))", + toString(result.errors[1]) + ); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '((nil) -> never) & ((number) -> number)' could not be converted into '(number?) -> never'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_never_arguments") @@ -821,6 +868,9 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_overlapping_results_and_variadics") { + ScopedFastFlag dcr{ + FFlag::DebugLuauDeferredConstraintResolution, false + }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f(x : ((string?) -> (string | number)) & ((number?) -> ...number)) local y : ((nil) -> (number, number?)) = x -- OK @@ -847,11 +897,18 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_1") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ( - toString(result.errors[0]), - "Type '(() -> (a...)) & (() -> (b...))' could not be converted into '() -> ()'; none of the intersection parts are compatible" - ); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ( + toString(result.errors[0]), + "Type '(() -> (a...)) & (() -> (b...))' could not be converted into '() -> ()'; none of the intersection parts are compatible" + ); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_2") @@ -865,11 +922,18 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_2") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ( - toString(result.errors[0]), - "Type '((a...) -> ()) & ((b...) -> ())' could not be converted into '() -> ()'; none of the intersection parts are compatible" - ); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ( + toString(result.errors[0]), + "Type '((a...) -> ()) & ((b...) -> ())' could not be converted into '() -> ()'; none of the intersection parts are compatible" + ); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_3") @@ -883,12 +947,19 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_3") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '(() -> (a...)) & (() -> (number?, a...))' could not be converted into '() -> number'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4") @@ -903,11 +974,27 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK_EQ( + R"(Type '((a...) -> ()) & ((number, a...) -> number)' could not be converted into - '(number?) -> ()'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + '((a...) -> ()) & ((number, a...) -> number)'; at [0].returns(), is not a subtype of number + type ((a...) -> ()) & ((number, a...) -> number)[1].arguments().tail() (a...) is not a supertype of ((a...) -> ()) & ((number, a...) -> number)[0].arguments().tail() (a...))", + toString(result.errors[0]) + ); + } + else + { + CHECK_EQ( + R"(Type + '((a...) -> ()) & ((number, a...) -> number)' +could not be converted into + '(number?) -> ()'; none of the intersection parts are compatible)", + toString(result.errors[0]) + ); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "intersect_metatables") diff --git a/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp index f8c80bf8..98063d0f 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp @@ -32,7 +32,14 @@ TEST_CASE_FIXTURE(Fixture, "for_loop") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(*builtinTypes->numberType, *requireType("q")); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // Luau cannot see that the loop must always run at least once, so we + // think that q could be nil. + CHECK("number?" == toString(requireType("q"))); + } + else + CHECK_EQ(*builtinTypes->numberType, *requireType("q")); } TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_no_table_passed") @@ -107,8 +114,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_regression_issue_69967_alt") )"); LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("number", toString(requireType("x"))); - CHECK_EQ("string", toString(requireType("y"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // It's possible for the loop body to execute 0 times. + CHECK("number?" == toString(requireType("x"))); + CHECK("string?" == toString(requireType("y"))); + } + else + { + CHECK_EQ("number", toString(requireType("x"))); + CHECK_EQ("string", toString(requireType("y"))); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop") @@ -124,12 +140,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(*builtinTypes->numberType, *requireType("n")); - CHECK_EQ(*builtinTypes->stringType, *requireType("s")); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK("number?" == toString(requireType("n"))); + CHECK("string?" == toString(requireType("s"))); + } + else + { + CHECK_EQ(*builtinTypes->numberType, *requireType("n")); + CHECK_EQ(*builtinTypes->stringType, *requireType("s")); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next") { + // CLI-116494 The generics K and V are leaking out of the next() function somehow. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local n local s @@ -240,11 +267,17 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error") LUAU_REQUIRE_ERROR_COUNT(2, result); TypeId p = requireType("p"); - CHECK_EQ("*error-type*", toString(p)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("*error-type*?", toString(p)); + else + CHECK_EQ("*error-type*", toString(p)); } TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") { + // We report a spuriouus duplicate error here. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local bad_iter = 5 @@ -259,6 +292,9 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_the_right_amount_of_values") { + // Spurious duplicate errors + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function hasDivisors(value: number, table) return false @@ -308,6 +344,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_t TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args_but_none_given") { + // CLI-116496 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function prime_iter(state, index) return 1 @@ -380,7 +419,10 @@ TEST_CASE_FIXTURE(Fixture, "while_loop") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(*builtinTypes->numberType, *requireType("i")); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("number?" == toString(requireType("i"))); + else + CHECK_EQ(*builtinTypes->numberType, *requireType("i")); } TEST_CASE_FIXTURE(Fixture, "repeat_loop") @@ -394,7 +436,10 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(*builtinTypes->stringType, *requireType("i")); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("string?" == toString(requireType("i"))); + else + CHECK_EQ(*builtinTypes->stringType, *requireType("i")); } TEST_CASE_FIXTURE(Fixture, "repeat_loop_condition_binds_to_its_block") @@ -490,7 +535,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table") end )"); - LUAU_REQUIRE_NO_ERRORS(result); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // In the new solver, we infer iter: unknown and so we warn on use of its properties. + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK(get(result.errors[0])); + CHECK(Location{{2, 12}, {2, 18}} == result.errors[0].location); + } + else + LUAU_REQUIRE_NO_ERRORS(result); } TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while") @@ -532,7 +585,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices") LUAU_REQUIRE_NO_ERRORS(result); - REQUIRE_EQ("number", toString(requireType("key"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("number?" == toString(requireType("key"))); + else + REQUIRE_EQ("number", toString(requireType("key"))); } TEST_CASE_FIXTURE(Fixture, "for_in_loop_where_iteratee_is_free") @@ -639,6 +695,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_typecheck_crash_on_empty_optional") { + // CLI-116498 Sometimes you can iterate over tables with no indexers. + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + ScopedFastFlag sff{FFlag::LuauOkWithIteratingOverTableProperties, true}; CheckResult result = check(R"( @@ -704,6 +764,9 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic") TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil") { + // CLI-116498 Sometimes you can iterate over tables with no indexers. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local t: {string} = {} local extra @@ -718,7 +781,11 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil") TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict") { - ScopedFastFlag sff{FFlag::LuauOkWithIteratingOverTableProperties, true}; + // CLI-116498 Sometimes you can iterate over tables with no indexers. + ScopedFastFlag sff[] = { + {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauOkWithIteratingOverTableProperties, true} + }; CheckResult result = check(R"( local t = {} @@ -742,7 +809,8 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_nonstrict") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_nil") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + // CLI-116499 Free types persisting until typechecking time. + if (1 || !FFlag::DebugLuauDeferredConstraintResolution) return; CheckResult result = check(R"( @@ -757,7 +825,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_nil") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_not_enough_returns") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + // CLI-116500 + if (1 || !FFlag::DebugLuauDeferredConstraintResolution) return; CheckResult result = check(R"( @@ -778,7 +847,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_not_enough_returns") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + // CLI-116500 + if (1 || !FFlag::DebugLuauDeferredConstraintResolution) return; CheckResult result = check(R"( @@ -794,7 +864,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok_with_inference") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + // CLI-116500 + if (1 || !FFlag::DebugLuauDeferredConstraintResolution) return; CheckResult result = check(R"( @@ -844,6 +915,10 @@ TEST_CASE_FIXTURE(Fixture, "for_loop_lower_bound_is_string_3") TEST_CASE_FIXTURE(BuiltinsFixture, "cli_68448_iterators_need_not_accept_nil") { + // CLI-116500 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( local function makeEnum(members) local enum = {} @@ -975,6 +1050,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_fragmented_keys") TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_xpath_candidates") { + // CLI-116500 + if (FFlag::DebugLuauDeferredConstraintResolution) + return; + CheckResult result = check(R"( type Instance = {} local function findCandidates(instances: { Instance }, path: { string }) @@ -1004,11 +1083,18 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never") )"); LUAU_REQUIRE_NO_ERRORS(result); - CHECK(toString(requireType("ans")) == "never"); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("never?" == toString(requireType("ans"))); // CLI-114134 egraph simplification. Should just be nil. + else + CHECK(toString(requireType("ans")) == "never"); } TEST_CASE_FIXTURE(BuiltinsFixture, "iterate_over_properties") { + // CLI-116498 - Sometimes you can iterate over tables with no indexer. + ScopedFastFlag sff0{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauOkWithIteratingOverTableProperties, true}; CheckResult result = check(R"( diff --git a/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp index 13a18c14..6719f158 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp @@ -56,12 +56,24 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require") return {hooty=hooty} )"; - fileResolver.source["game/B"] = R"( - local Hooty = require(game.A) + if (FFlag::DebugLuauDeferredConstraintResolution) + { + fileResolver.source["game/B"] = R"( + local Hooty = require(game.A) - local h -- free! - local i = Hooty.hooty(h) - )"; + local h = 4 + local i = Hooty.hooty(h) + )"; + } + else + { + fileResolver.source["game/B"] = R"( + local Hooty = require(game.A) + + local h -- free! + local i = Hooty.hooty(h) + )"; + } CheckResult aResult = frontend.check("game/A"); dumpErrors(aResult); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp index e1d2e1b6..29935a08 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp @@ -18,6 +18,9 @@ TEST_SUITE_BEGIN("TypeInferOOP"); TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon") { + // CLI-116571 method calls are missing arity checking? + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local someTable = {} @@ -33,6 +36,9 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defi TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2") { + // CLI-116571 method calls are missing arity checking? + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local someTable = {} @@ -138,7 +144,10 @@ TEST_CASE_FIXTURE(Fixture, "inferring_hundreds_of_self_calls_should_not_suffocat )"); ModulePtr module = getMainModule(); - CHECK_GE(50, module->internalTypes.types.size()); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_GE(80, module->internalTypes.types.size()); + else + CHECK_GE(50, module->internalTypes.types.size()); } TEST_CASE_FIXTURE(BuiltinsFixture, "object_constructor_can_refer_to_method_of_self") @@ -410,10 +419,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cycle_between_object_constructor_and_alias") TEST_CASE_FIXTURE(BuiltinsFixture, "promise_type_error_too_complex" * doctest::timeout(2)) { - // TODO: LTI changes to function call resolution have rendered this test impossibly slow - // shared self should fix it, but there may be other mitigations possible as well - REQUIRE(!FFlag::DebugLuauDeferredConstraintResolution); - frontend.options.retainFullTypeGraphs = false; // Used `luau-reduce` tool to extract a minimal reproduction. diff --git a/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp index a39ef1a7..e5514db0 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp @@ -189,11 +189,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ("Vec3", toString(requireType("a"))); - CHECK_EQ("Vec3", toString(requireType("b"))); - CHECK_EQ("Vec3", toString(requireType("c"))); - CHECK_EQ("Vec3", toString(requireType("d"))); - CHECK_EQ("Vec3", toString(requireType("e"))); + CHECK("Vec3" == toString(requireType("a"))); + CHECK("Vec3" == toString(requireType("b"))); + CHECK("Vec3" == toString(requireType("c"))); + CHECK("Vec3" == toString(requireType("d"))); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("mul" == toString(requireType("e"))); + else + CHECK_EQ("Vec3", toString(requireType("e"))); } TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_intersection_on_rhs") @@ -223,11 +227,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ("Vec3", toString(requireType("a"))); - CHECK_EQ("Vec3", toString(requireType("b"))); - CHECK_EQ("Vec3", toString(requireType("c"))); - CHECK_EQ("Vec3", toString(requireType("d"))); - CHECK_EQ("Vec3", toString(requireType("e"))); + CHECK("Vec3" == toString(requireType("a"))); + CHECK("Vec3" == toString(requireType("b"))); + CHECK("Vec3" == toString(requireType("c"))); + CHECK("Vec3" == toString(requireType("d"))); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("mul" == toString(requireType("e"))); + else + CHECK_EQ("Vec3", toString(requireType("e"))); } TEST_CASE_FIXTURE(Fixture, "compare_numbers") @@ -477,7 +485,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_result_must_be_compatible_wi )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK(result.errors[0] == TypeError{Location{{13, 8}, {13, 14}}, TypeMismatch{requireType("x"), builtinTypes->numberType}}); + + CHECK(Location{{13, 8}, {13, 14}} == result.errors[0].location); + + TypeMismatch* tm = get(result.errors[0]); + REQUIRE(tm); + CHECK("x" == toString(tm->wantedType)); + CHECK("number" == toString(tm->givenType)); } TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_mismatch_metatable") @@ -593,17 +607,32 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error") local a = -foo )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ("string", toString(requireType("a"))); + CHECK(get(result.errors[0])); - TypeMismatch* tm = get(result.errors[0]); - REQUIRE_EQ(*tm->wantedType, *builtinTypes->booleanType); - // given type is the typeof(foo) which is complex to compare against + // This second error is spurious. We should not be reporting it. + CHECK(get(result.errors[1])); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + + CHECK_EQ("string", toString(requireType("a"))); + + TypeMismatch* tm = get(result.errors[0]); + REQUIRE_EQ(*tm->wantedType, *builtinTypes->booleanType); + // given type is the typeof(foo) which is complex to compare against + } } TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error") { + // CLI-116463 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict local mt = {} @@ -673,22 +702,34 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables LUAU_REQUIRE_ERROR_COUNT(3, result); - TypeMismatch* tm = get(result.errors[0]); - REQUIRE(tm); - CHECK_EQ(*tm->wantedType, *builtinTypes->numberType); - CHECK_EQ(*tm->givenType, *builtinTypes->stringType); - - GenericError* gen1 = get(result.errors[1]); - REQUIRE(gen1); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ(gen1->message, "Operator + is not applicable for '{ value: number }' and 'number' because neither type has a metatable"); + { + CHECK(get(result.errors[0])); + CHECK(Location{{2, 18}, {2, 30}} == result.errors[0].location); + CHECK(get(result.errors[1])); + CHECK(Location{{8, 18}, {8, 25}} == result.errors[1].location); + CHECK(get(result.errors[2])); + CHECK(Location{{24, 18}, {24, 27}} == result.errors[2].location); + } else - CHECK_EQ(gen1->message, "Binary operator '+' not supported by types 'foo' and 'number'"); - - TypeMismatch* tm2 = get(result.errors[2]); - REQUIRE(tm2); - CHECK_EQ(*tm2->wantedType, *builtinTypes->numberType); - CHECK_EQ(*tm2->givenType, *requireType("foo")); + { + TypeMismatch* tm = get(result.errors[0]); + REQUIRE_MESSAGE(tm, "Expected a TypeMismatch but got " << result.errors[0]); + CHECK_EQ(*tm->wantedType, *builtinTypes->numberType); + CHECK_EQ(*tm->givenType, *builtinTypes->stringType); + + GenericError* gen1 = get(result.errors[1]); + REQUIRE(gen1); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ(gen1->message, "Operator + is not applicable for '{ value: number }' and 'number' because neither type has a metatable"); + else + CHECK_EQ(gen1->message, "Binary operator '+' not supported by types 'foo' and 'number'"); + + TypeMismatch* tm2 = get(result.errors[2]); + REQUIRE(tm2); + CHECK_EQ(*tm2->wantedType, *builtinTypes->numberType); + CHECK_EQ(*tm2->givenType, *requireType("foo")); + } } // CLI-29033 @@ -712,8 +753,16 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_free_lhs_and_string_rhs") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - REQUIRE(get(result.errors[0])); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_NO_ERRORS(result); + CHECK("(a) -> concat" == toString(requireType("f"))); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + REQUIRE(get(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "concat_op_on_string_lhs_and_free_rhs") @@ -726,7 +775,10 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_string_lhs_and_free_rhs") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("(string) -> string", toString(requireType("f"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("(a) -> concat" == toString(requireType("f"))); + else + CHECK_EQ("(string) -> string", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown") @@ -746,11 +798,10 @@ TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown") { LUAU_REQUIRE_ERROR_COUNT(ops.size(), result); CHECK_EQ( - "Type function instance Add depends on generic function parameters but does not appear in the function signature; this " - "construct cannot be type-checked at this time", + "Operator '+' could not be applied to operands of types unknown and unknown; there is no corresponding overload for __add", toString(result.errors[0]) ); - CHECK_EQ("Unknown type used in - operation; consider adding a type annotation to 'a'", toString(result.errors[1])); + CHECK_EQ("Operator '-' could not be applied to operands of types unknown and unknown; there is no corresponding overload for __sub", toString(result.errors[1])); } else { @@ -833,6 +884,9 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union") { + // There's an extra spurious warning here when the new solver is enabled. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict local _ @@ -847,14 +901,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign") { // In non-strict mode, global definition is still allowed { - CheckResult result = check(R"( - --!nonstrict - a = a + 1 - print(a) - )"); - - LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); + if (!FFlag::DebugLuauDeferredConstraintResolution) + { + CheckResult result = check(R"( + --!nonstrict + a = a + 1 + print(a) + )"); + + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); + } } // In strict mode we no longer generate two errors from lhs @@ -871,14 +928,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign") // In non-strict mode, compound assignment is not a definition, it's a modification { - CheckResult result = check(R"( - --!nonstrict - a += 1 - print(a) - )"); - - LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); + if (!FFlag::DebugLuauDeferredConstraintResolution) + { + CheckResult result = check(R"( + --!nonstrict + a += 1 + print(a) + )"); + + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); + } } } @@ -1233,7 +1293,8 @@ TEST_CASE_FIXTURE(Fixture, "unrelated_primitives_cannot_be_compared") TEST_CASE_FIXTURE(BuiltinsFixture, "mm_comparisons_must_return_a_boolean") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + // CLI-115687 + if (1 || !FFlag::DebugLuauDeferredConstraintResolution) return; CheckResult result = check(R"( @@ -1286,7 +1347,7 @@ local w = c and 1 CHECK("boolean | number" == toString(requireType("z"))); // 'false' widened to boolean if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK("((false?) & unknown) | number" == toString(requireType("w"))); + CHECK("number?" == toString(requireType("w"))); else CHECK("(boolean | number)?" == toString(requireType("w"))); } @@ -1364,6 +1425,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array_simplified") TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array") { + // CLI-116480 Subtyping bug: table should probably be a subtype of {[unknown]: unknown} + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict return function(value: any): boolean @@ -1536,4 +1600,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_infinite_expansion_of_free_type" * doctes // just type-checking this code is enough } +TEST_CASE_FIXTURE(BuiltinsFixture, "compound_operator_on_upvalue") +{ + CheckResult result = check(R"( + local byteCursor: number = 0 + + local function advance(bytes: number) + byteCursor += bytes + end + )"); + + LUAU_REQUIRE_NO_ERRORS(result); +} + TEST_SUITE_END(); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp index 37f891cb..0f6d6132 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp @@ -73,18 +73,27 @@ TEST_CASE_FIXTURE(Fixture, "string_function_indirect") CHECK_EQ(*requireType("p"), *builtinTypes->stringType); } -TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber") +TEST_CASE_FIXTURE(Fixture, "check_methods_of_number") { CheckResult result = check(R"( -local x: number = 9999 -function x:y(z: number) - local s: string = z -end -)"); + local x: number = 9999 + function x:y(z: number) + local s: string = z + end + )"); LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), "Cannot add method to non-table type 'number'"); - CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'string'"); + + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK("Expected type table, got 'number' instead" == toString(result.errors[0])); + CHECK("Type 'number' could not be converted into 'string'" == toString(result.errors[1])); + } + else + { + CHECK_EQ(toString(result.errors[0]), "Cannot add method to non-table type 'number'"); + CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'string'"); + } } TEST_CASE("singleton_types") diff --git a/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp index c9d6f5db..9107c6f4 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp @@ -55,11 +55,26 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete") end )"; - CHECK_EQ(expected, decorateWithTypes(code)); + const std::string expectedWithNewSolver = R"( + function f(a:{fn:()->(unknown,...unknown)}): () + if type(a) == 'boolean'then + local a1:{fn:()->(unknown,...unknown)}&boolean=a + elseif a.fn()then + local a2:{fn:()->(unknown,...unknown)}&(class|function|nil|number|string|thread|buffer|table)=a + end + end + )"; + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ(expectedWithNewSolver, decorateWithTypes(code)); + else + CHECK_EQ(expected, decorateWithTypes(code)); } TEST_CASE_FIXTURE(BuiltinsFixture, "luau-polyfill.Array.filter") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + // This test exercises the fact that we should reduce sealed/unsealed/free tables // res is a unsealed table with type {((T & ~nil)?) & any} // Because we do not reduce it fully, we cannot unify it with `Array = { [number] : T} @@ -157,6 +172,8 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size") // For now, infer it as just a free table. TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_table") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local a = {} local b @@ -175,6 +192,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_ // Luau currently doesn't yet know how to allow assignments when the binding was refined. TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( type Node = { value: T, child: Node? } @@ -198,6 +217,8 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined") // We should be type checking the metamethod at the call site of setmetatable. TEST_CASE_FIXTURE(BuiltinsFixture, "error_on_eq_metamethod_returning_a_type_other_than_boolean") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local tab = {a = 1} setmetatable(tab, {__eq = function(a, b): number @@ -258,11 +279,8 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil") if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK_EQ("{ x: string, y: number }", toString(requireTypeAtPosition({5, 28}))); - - // Should be { x: nil, y: nil } - CHECK_EQ("{ x: nil, y: nil } | { x: string, y: number }", toString(requireTypeAtPosition({7, 28}))); + CHECK_EQ("{ x: nil, y: nil }", toString(requireTypeAtPosition({7, 28}))); } else { @@ -341,10 +359,19 @@ TEST_CASE_FIXTURE(Fixture, "do_not_ice_when_trying_to_pick_first_of_generic_type LUAU_REQUIRE_NO_ERRORS(result); - // f and g should have the type () -> () - CHECK_EQ("() -> (a...)", toString(requireType("f"))); - CHECK_EQ("() -> (a...)", toString(requireType("g"))); - CHECK_EQ("any", toString(requireType("x"))); // any is returned instead of ICE for now + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK("() -> ()" == toString(requireType("f"))); + CHECK("() -> ()" == toString(requireType("g"))); + CHECK("nil" == toString(requireType("x"))); + } + else + { + // f and g should have the type () -> () + CHECK_EQ("() -> (a...)", toString(requireType("f"))); + CHECK_EQ("() -> (a...)", toString(requireType("g"))); + CHECK_EQ("any", toString(requireType("x"))); // any is returned instead of ICE for now + } } TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early") @@ -355,7 +382,10 @@ TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early") local s2s: (string) -> string = id )"); - LUAU_REQUIRE_ERRORS(result); // Should not have any errors. + if (FFlag::DebugLuauDeferredConstraintResolution) + LUAU_REQUIRE_NO_ERRORS(result); + else + LUAU_REQUIRE_ERRORS(result); // Should not have any errors. } TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_type_pack") @@ -487,6 +517,8 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + TypeArena arena; TypeId nilType = builtinTypes->nilType; @@ -569,7 +601,7 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->returnType); REQUIRE(result); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("(any & ~(*error-type* | table))?", toString(*result)); + CHECK_EQ("unknown", toString(*result)); else CHECK_MESSAGE(get(*result), *result); } @@ -610,7 +642,11 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->returnType); REQUIRE(result); - CHECK(get(*result)); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("unknown" == toString(*result)); + else + CHECK("any" == toString(*result)); } namespace @@ -793,19 +829,26 @@ TEST_CASE_FIXTURE(Fixture, "assign_table_with_refined_property_with_a_similar_ty end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + LUAU_REQUIRE_NO_ERRORS(result); // This is wrong. We should be rejecting this assignment. + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '{| x: number? |}' could not be converted into '{| x: number |}' caused by: Property 'x' is not compatible. Type 'number?' could not be converted into 'number' in an invariant context)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function foo(t, x) if x == "hi" or x == "bye" then @@ -861,15 +904,25 @@ TEST_CASE_FIXTURE(Fixture, "expected_type_should_be_a_helpful_deduction_guide_fo local x: Ref = useRef(nil) )"); - // This is actually wrong! Sort of. It's doing the wrong thing, it's actually asking whether - // `{| val: number? |} <: {| val: nil |}` - // instead of the correct way, which is - // `{| val: nil |} <: {| val: number? |}` - LUAU_REQUIRE_NO_ERRORS(result); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // This bug is fixed in the new solver. + LUAU_REQUIRE_ERROR_COUNT(1, result); + } + else + { + // This is actually wrong! Sort of. It's doing the wrong thing, it's actually asking whether + // `{| val: number? |} <: {| val: nil |}` + // instead of the correct way, which is + // `{| val: nil |} <: {| val: number? |}` + LUAU_REQUIRE_NO_ERRORS(result); + } } TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local assign : (target: T, source0: U?, source1: V?, source2: W?, ...any) -> T & U & V & W = (nil :: any) @@ -892,6 +945,8 @@ TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed") TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + TypeArena arena; TypeId nilType = builtinTypes->nilType; @@ -935,8 +990,10 @@ TEST_CASE_FIXTURE(Fixture, "unify_more_complex_unions_that_include_nil") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant") +TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_old_solver") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + createSomeClasses(&frontend); CheckResult result = check(R"( @@ -951,6 +1008,24 @@ TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant") LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_new_solver") +{ + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + + createSomeClasses(&frontend); + + CheckResult result = check(R"( + function foo(ref: {read current: Parent?}) + end + + function bar(ref: {read current: Child?}) + foo(ref) + end + )"); + + LUAU_REQUIRE_ERROR_COUNT(0, result); +} + TEST_CASE_FIXTURE(BuiltinsFixture, "luau-polyfill.Map.entries") { @@ -1000,6 +1075,9 @@ end // We would prefer this unification to be able to complete, but at least it should not crash TEST_CASE_FIXTURE(BuiltinsFixture, "table_unification_infinite_recursion") { + // The new solver doesn't recurse as heavily in this situation. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + #if defined(_NOOPT) || defined(_DEBUG) ScopedFastInt LuauTypeInferRecursionLimit{FInt::LuauTypeInferRecursionLimit, 100}; #endif @@ -1027,16 +1105,8 @@ local tbl = require(game.A) tbl:f3() )"; - if (FFlag::DebugLuauDeferredConstraintResolution) - { - // TODO: DCR should transform RecursionLimitException into a CodeTooComplex error (currently it rethows it as InternalCompilerError) - CHECK_THROWS_AS(frontend.check("game/B"), Luau::InternalCompilerError); - } - else - { - CheckResult result = frontend.check("game/B"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - } + CheckResult result = frontend.check("game/B"); + LUAU_REQUIRE_ERROR_COUNT(1, result); } // Ideally, unification with any will not cause a 2^n normalization of a function overload @@ -1148,7 +1218,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_roact_useState_minimization") update("hello") )"); - LUAU_REQUIRE_NO_ERRORS(result); + // We actually expect this code to be fine. + LUAU_REQUIRE_ERRORS(result); } TEST_CASE_FIXTURE(BuiltinsFixture, "bin_prov") diff --git a/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp index 60f25a24..37c5e8d2 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp @@ -317,14 +317,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_if_condition_position") TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_assert_position") { CheckResult result = check(R"( - local a - assert(type(a) == "number") - local b = a + function f(a) + assert(type(a) == "number") + local b = a + return b + end )"); LUAU_REQUIRE_NO_ERRORS(result); - REQUIRE_EQ("number", toString(requireType("b"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("(a) -> a & number" == toString(requireType("f"))); + else + CHECK("(a) -> number" == toString(requireType("f"))); } TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_test_a_prop") @@ -440,15 +445,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "call_an_incompatible_function_after_using_ty end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) - LUAU_REQUIRE_ERROR_COUNT(1, result); - else - LUAU_REQUIRE_ERROR_COUNT(2, result); + LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); + CHECK("Type 'string' could not be converted into 'number'" == toString(result.errors[0])); + CHECK(Location{{ 7, 18}, {7, 19}} == result.errors[0].location); - if (!FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[1])); + CHECK("Type 'string' could not be converted into 'number'" == toString(result.errors[1])); + CHECK(Location{{ 13, 18}, {13, 19}} == result.errors[1].location); } TEST_CASE_FIXTURE(BuiltinsFixture, "impossible_type_narrow_is_not_an_error") @@ -485,7 +488,8 @@ TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties") if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK("{| x: number |}" == toString(requireTypeAtPosition({4, 23}))); + // CLI-115281 - Types produced by refinements don't always get simplified + CHECK("{ x: number? } & { x: ~(false?) }" == toString(requireTypeAtPosition({4, 23}))); CHECK("number" == toString(requireTypeAtPosition({5, 26}))); } @@ -699,7 +703,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_narrow_to_vector") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28}))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK_EQ("never", toString(requireTypeAtPosition({3, 28}))); + else + CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28}))); } TEST_CASE_FIXTURE(BuiltinsFixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true") @@ -722,11 +729,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "nonoptional_type_can_narrow_to_nil_if_sense_ LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("nil", toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil" - CHECK_EQ("string", toString(requireTypeAtPosition({6, 24}))); // type(v) ~= "nil" + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // CLI-115281 Types produced by refinements do not consistently get simplified + CHECK_EQ("(nil & string)?", toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil" + CHECK_EQ("(boolean | buffer | class | function | number | string | table | thread) & string", toString(requireTypeAtPosition({6, 24}))); // type(v) ~= "nil" - CHECK_EQ("nil", toString(requireTypeAtPosition({10, 24}))); // equivalent to type(v) == "nil" - CHECK_EQ("string", toString(requireTypeAtPosition({12, 24}))); // equivalent to type(v) ~= "nil" + CHECK_EQ("(nil & string)?", toString(requireTypeAtPosition({10, 24}))); // equivalent to type(v) == "nil" + CHECK_EQ("(boolean | buffer | class | function | number | string | table | thread) & string", toString(requireTypeAtPosition({12, 24}))); // equivalent to type(v) ~= "nil" + } + else + { + CHECK_EQ("nil", toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil" + CHECK_EQ("string", toString(requireTypeAtPosition({6, 24}))); // type(v) ~= "nil" + + CHECK_EQ("nil", toString(requireTypeAtPosition({10, 24}))); // equivalent to type(v) == "nil" + CHECK_EQ("string", toString(requireTypeAtPosition({12, 24}))); // equivalent to type(v) ~= "nil" + } } TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_not_to_be_string") @@ -844,7 +863,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("never", toString(requireTypeAtPosition({3, 28}))); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // CLI-115281 Types produced by refinements do not consistently get simplified + CHECK_EQ("{ x: number } & ~table", toString(requireTypeAtPosition({3, 28}))); + } + else + CHECK_EQ("never", toString(requireTypeAtPosition({3, 28}))); } TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b") @@ -950,7 +975,10 @@ TEST_CASE_FIXTURE(Fixture, "not_t_or_some_prop_of_t") LUAU_REQUIRE_NO_ERRORS(result); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("{| x: true |}?", toString(requireTypeAtPosition({3, 28}))); + { + // CLI-115281 Types produced by refinements do not consistently get simplified + CHECK_EQ("({ x: boolean } & { x: ~(false?) })?", toString(requireTypeAtPosition({3, 28}))); + } else CHECK_EQ("{| x: boolean |}?", toString(requireTypeAtPosition({3, 28}))); } @@ -1196,11 +1224,17 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(R"({| tag: "exists", x: string |})", toString(requireTypeAtPosition({5, 28}))); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ(R"({| tag: "missing", x: nil |})", toString(requireTypeAtPosition({7, 28}))); + { + // CLI-115281 Types produced by refinements do not consistently get simplified + CHECK("{ tag: \"exists\", x: string } & { x: ~(false?) }" == toString(requireTypeAtPosition({5, 28}))); + CHECK("({ tag: \"exists\", x: string } & { x: ~~(false?) }) | { tag: \"missing\", x: nil }" == toString(requireTypeAtPosition({7, 28}))); + } else + { + CHECK_EQ(R"({| tag: "exists", x: string |})", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ(R"({| tag: "exists", x: string |} | {| tag: "missing", x: nil |})", toString(requireTypeAtPosition({7, 28}))); + } } TEST_CASE_FIXTURE(Fixture, "discriminate_tag") @@ -1328,8 +1362,8 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x") if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK_EQ(R"({ tag: "Part", x: Part })", toString(requireTypeAtPosition({5, 28}))); - CHECK_EQ(R"({ tag: "Folder", x: Folder })", toString(requireTypeAtPosition({7, 28}))); + CHECK(R"({ tag: "Part", x: Part })" == toString(requireTypeAtPosition({5, 28}))); + CHECK(R"({ tag: "Folder", x: Folder })" == toString(requireTypeAtPosition({7, 28}))); } else { @@ -1340,6 +1374,9 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x") TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector") { + // CLI-115286 - Refining via type(x) == 'vector' does not work in the new solver + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function f(vec) local X, Y, Z = vec.X, vec.Y, vec.Z @@ -1527,6 +1564,10 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "refine_param_of_type_folder_or_part_w TEST_CASE_FIXTURE(RefinementClassFixture, "isa_type_refinement_must_be_known_ahead_of_time") { + // CLI-115087 - The new solver does not consistently combine tables with + // class types when they appear in the upper bounds of a free type. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function f(x): Instance if x:IsA("Folder") then @@ -1819,7 +1860,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_a_property_of_some_global") { LUAU_REQUIRE_ERROR_COUNT(3, result); - CHECK_EQ("~(false?)", toString(requireTypeAtPosition({4, 30}))); + CHECK_EQ("*error-type* | buffer | class | function | number | string | table | thread | true", toString(requireTypeAtPosition({4, 30}))); } } @@ -1843,9 +1884,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dataflow_analysis_can_tell_refinements_when_ end if typeof(s) == "nil" then - local foo = s + local foo = s -- line 18 else - local foo = s + local foo = s -- line 20 end end )"); @@ -1860,7 +1901,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dataflow_analysis_can_tell_refinements_when_ if (FFlag::DebugLuauDeferredConstraintResolution) { - CHECK_EQ("never", toString(requireTypeAtPosition({18, 28}))); + // CLI-115281 - Types produced by refinements don't always get simplified + CHECK_EQ("nil & string", toString(requireTypeAtPosition({18, 28}))); CHECK_EQ("string", toString(requireTypeAtPosition({20, 28}))); } else @@ -1948,7 +1990,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_annotations_arent_relevant_when_doing_d CHECK_EQ("nil", toString(requireTypeAtPosition({8, 28}))); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("never", toString(requireTypeAtPosition({9, 28}))); + { + // CLI-115478 - This should be never + CHECK_EQ("nil", toString(requireTypeAtPosition({9, 28}))); + } else CHECK_EQ("nil", toString(requireTypeAtPosition({9, 28}))); } @@ -2044,7 +2089,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table") TEST_CASE_FIXTURE(BuiltinsFixture, "conditional_refinement_should_stay_error_suppressing") { ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; - // this test is DCR-only as an instance of DCR fixing a bug in the old solver CheckResult result = check(R"( local function test(element: any?) @@ -2065,7 +2109,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "globals_can_be_narrowed_too") end )"); - CHECK("never" == toString(requireTypeAtPosition(Position{2, 24}))); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + // CLI-114134 + CHECK("string & typeof(string)" == toString(requireTypeAtPosition(Position{2, 24}))); + } + else + CHECK("never" == toString(requireTypeAtPosition(Position{2, 24}))); } TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_isindexkey_refine_conjunction") @@ -2096,17 +2146,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_isindexkey_refine_conjunction_ LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(BuiltinsFixture, "globals_can_be_narrowed_too") -{ - CheckResult result = check(R"( - if typeof(string) == 'string' then - local foo = string - end - )"); - - CHECK("never" == toString(requireTypeAtPosition(Position{2, 24}))); -} - TEST_CASE_FIXTURE(BuiltinsFixture, "ex") { CheckResult result = check(R"( @@ -2213,4 +2252,67 @@ function(obj) end )")); } + +TEST_CASE_FIXTURE(Fixture, "more_complex_long_disjunction_of_refinements_shouldnt_trip_ice") +{ + CHECK_NOTHROW(check(R"( +script:connect(function(obj) + if script.Parent.SeatNumber.Value == "1D" or + script.Parent.SeatNumber.Value == "2D" or + script.Parent.SeatNumber.Value == "3D" or + script.Parent.SeatNumber.Value == "4D" or + script.Parent.SeatNumber.Value == "5D" or + script.Parent.SeatNumber.Value == "6D" or + script.Parent.SeatNumber.Value == "7D" or + script.Parent.SeatNumber.Value == "8D" or + script.Parent.SeatNumber.Value == "9D" or + script.Parent.SeatNumber.Value == "10D" or + script.Parent.SeatNumber.Value == "11D" or + script.Parent.SeatNumber.Value == "12D" or + script.Parent.SeatNumber.Value == "13D" or + script.Parent.SeatNumber.Value == "14D" or + script.Parent.SeatNumber.Value == "15D" or + script.Parent.SeatNumber.Value == "16D" or + script.Parent.SeatNumber.Value == "1C" or + script.Parent.SeatNumber.Value == "2C" or + script.Parent.SeatNumber.Value == "3C" or + script.Parent.SeatNumber.Value == "4C" or + script.Parent.SeatNumber.Value == "5C" or + script.Parent.SeatNumber.Value == "6C" or + script.Parent.SeatNumber.Value == "7C" or + script.Parent.SeatNumber.Value == "8C" or + script.Parent.SeatNumber.Value == "9C" or + script.Parent.SeatNumber.Value == "10C" or + script.Parent.SeatNumber.Value == "11C" or + script.Parent.SeatNumber.Value == "12C" or + script.Parent.SeatNumber.Value == "13C" or + script.Parent.SeatNumber.Value == "14C" or + script.Parent.SeatNumber.Value == "15C" or + script.Parent.SeatNumber.Value == "16C" then + end) +)")); +} + +TEST_CASE_FIXTURE(Fixture, "refinements_should_avoid_building_up_big_intersect_families") +{ + CHECK_NOTHROW(check(R"( +script:connect(function(obj) + if script.Parent.SeatNumber.Value == "1D" or script.Parent.SeatNumber.Value == "2D" or script.Parent.SeatNumber.Value == "3D" or script.Parent.SeatNumber.Value == "4D" or script.Parent.SeatNumber.Value == "5D" or script.Parent.SeatNumber.Value == "6D" or script.Parent.SeatNumber.Value == "7D" or script.Parent.SeatNumber.Value == "8D" or script.Parent.SeatNumber.Value == "9D" or script.Parent.SeatNumber.Value == "10D" or script.Parent.SeatNumber.Value == "11D" or script.Parent.SeatNumber.Value == "12D" or script.Parent.SeatNumber.Value == "13D" or script.Parent.SeatNumber.Value == "14D" or script.Parent.SeatNumber.Value == "15D" or script.Parent.SeatNumber.Value == "16D" or script.Parent.SeatNumber.Value == "1C" or script.Parent.SeatNumber.Value == "2C" or script.Parent.SeatNumber.Value == "3C" or script.Parent.SeatNumber.Value == "4C" or script.Parent.SeatNumber.Value == "5C" or script.Parent.SeatNumber.Value == "6C" or script.Parent.SeatNumber.Value == "7C" or script.Parent.SeatNumber.Value == "8C" or script.Parent.SeatNumber.Value == "9C" or script.Parent.SeatNumber.Value == "10C" or script.Parent.SeatNumber.Value == "11C" or script.Parent.SeatNumber.Value == "12C" or script.Parent.SeatNumber.Value == "13C" or script.Parent.SeatNumber.Value == "14C" or script.Parent.SeatNumber.Value == "15C" or script.Parent.SeatNumber.Value == "16C" then + if p.Name == script.Parent.Parent.Parent.Parent.Parent.Parent.MainParts.CD.SurfaceGui[script.Parent.SeatNumber.Value].Player.Value or script.Parent.Parent.Parent.Parent.Parent.Parent.MainParts.CD.SurfaceGui[script.Parent.SeatNumber.Value].Player.Value == "" then + else + if script.Parent:FindFirstChild("SeatWeld") then + end + end + else + if p.Name == script.Parent.Parent.Parent.Parent.Parent.Parent.MainParts.AB.SurfaceGui[script.Parent.SeatNumber.Value].Player.Value or script.Parent.Parent.Parent.Parent.Parent.Parent.MainParts.AB.SurfaceGui[script.Parent.SeatNumber.Value].Player.Value == "" then + print("Allowed") + else + if script.Parent:FindFirstChild("SeatWeld") then + end + end + end +end) +)")); +} + TEST_SUITE_END(); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp index e4289649..bec9d953 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp @@ -153,6 +153,8 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons") TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(g: ((true, string) -> ()) & ((false, number) -> ())) g(true, 37) @@ -192,10 +194,14 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ( - "Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'; none of the union options are compatible", - toString(result.errors[0]) - ); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'" == toString(result.errors[0])); + else + CHECK_EQ( + "Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'; none of the union options are compatible", + toString(result.errors[0]) + ); } TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_subtyping") @@ -337,10 +343,18 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ( - R"(Table type '{ ["\n"]: number }' not compatible with type '{| ["<>"]: number |}' because the former is missing field '<>')", - toString(result.errors[0]) - ); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK( + "Type\n" + " '{ [\"\\n\"]: number }'\n" + "could not be converted into\n" + " '{ [\"<>\"]: number }'" == toString(result.errors[0]) + ); + else + CHECK_EQ( + R"(Table type '{ ["\n"]: number }' not compatible with type '{| ["<>"]: number |}' because the former is missing field '<>')", + toString(result.errors[0]) + ); } TEST_CASE_FIXTURE(Fixture, "error_detailed_tagged_union_mismatch_string") @@ -354,11 +368,16 @@ local a: Animal = { tag = 'cat', cafood = 'something' } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type 'a' could not be converted into 'Cat | Dog' + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Type '{ cafood: string, tag: \"cat\" }' could not be converted into 'Cat | Dog'" == toString(result.errors[0])); + else + { + const std::string expected = R"(Type 'a' could not be converted into 'Cat | Dog' caused by: None of the union options are compatible. For example: Table type 'a' not compatible with type 'Cat' because the former is missing field 'catfood')"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "error_detailed_tagged_union_mismatch_bool") @@ -372,11 +391,16 @@ local a: Result = { success = false, result = 'something' } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type 'a' could not be converted into 'Bad | Good' + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Type '{ result: string, success: boolean }' could not be converted into 'Bad | Good'" == toString(result.errors[0])); + else + { + const std::string expected = R"(Type 'a' could not be converted into 'Bad | Good' caused by: None of the union options are compatible. For example: Table type 'a' not compatible with type 'Bad' because the former is missing field 'error')"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "parametric_tagged_union_alias") @@ -418,6 +442,8 @@ local a: Animal = if true then { tag = 'cat', catfood = 'something' } else { tag TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_singleton") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function foo(f, x) if x == "hi" then @@ -427,7 +453,7 @@ TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_si end )"); - LUAU_REQUIRE_NO_ERRORS(result); + LUAU_CHECK_NO_ERRORS(result); CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 18}))); // should be ((string) -> a..., string) -> () but needs lower bounds calculation @@ -436,6 +462,8 @@ TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_si TEST_CASE_FIXTURE(Fixture, "return_type_of_f_is_not_widened") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function foo(f, x): "hello"? -- anyone there? return if x == "hi" diff --git a/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp index a0a3aaf3..6256ede6 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp @@ -2536,7 +2536,10 @@ local y: number = tmp.p.y LUAU_REQUIRE_ERROR_COUNT(1, result); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK("Type 'tmp' could not be converted into 'HasSuper'; at [read \"p\"], { x: number, y: number } is not exactly Super" == toString(result.errors[0])); + CHECK( + "Type 'tmp' could not be converted into 'HasSuper'; at [read \"p\"], { x: number, y: number } is not exactly Super" == + toString(result.errors[0]) + ); else { const std::string expected = R"(Type 'tmp' could not be converted into 'HasSuper' diff --git a/Dependencies/luau/Luau/tests/TypeInfer.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.test.cpp index 237fbcf9..1140976f 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.test.cpp @@ -224,6 +224,8 @@ TEST_CASE_FIXTURE(Fixture, "statements_are_topologically_sorted") TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local o o:method() @@ -263,6 +265,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case") TEST_CASE_FIXTURE(Fixture, "dont_ice_when_failing_the_occurs_check") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict local s @@ -380,6 +384,8 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types") // checker. We also want it to somewhat match up with production values, so we push up the parser recursion limit a little bit instead. TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + #if defined(LUAU_ENABLE_ASAN) int limit = 250; #elif defined(_DEBUG) || defined(_NOOPT) @@ -435,6 +441,9 @@ TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit") TEST_CASE_FIXTURE(Fixture, "globals") { + // The new solver does not permit assignments to globals like this. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!nonstrict foo = true @@ -447,6 +456,8 @@ TEST_CASE_FIXTURE(Fixture, "globals") TEST_CASE_FIXTURE(Fixture, "globals2") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!nonstrict foo = function() return 1 end @@ -495,6 +506,8 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do") TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CHECK_NOTHROW(check(R"( --!nonstrict f,g = ... @@ -587,6 +600,8 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert") TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error") { { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict local t = { x = 10, y = 20 } @@ -607,6 +622,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_ } { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict function string.() end @@ -680,6 +697,8 @@ TEST_CASE_FIXTURE(Fixture, "cli_39932_use_unifier_in_ensure_methods") TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( foo )"); @@ -689,6 +708,8 @@ TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError") TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local a = foo: )"); @@ -738,7 +759,10 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_isoptional") std::optional t0 = lookupType("t0"); REQUIRE(t0); - CHECK_EQ("*error-type*", toString(*t0)); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("any" == toString(*t0)); + else + CHECK_EQ("*error-type*", toString(*t0)); auto it = std::find_if( result.errors.begin(), @@ -1075,6 +1099,8 @@ end TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( --!strict --!nolint @@ -1150,7 +1176,11 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice") )"); LUAU_REQUIRE_ERRORS(result); - CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0])); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Type contains a self-recursive construct that cannot be resolved" == toString(result.errors[0])); + else + CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0])); } TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer") @@ -1168,7 +1198,11 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer") REQUIRE_MESSAGE(!result.errors.empty(), getErrors(result)); CHECK(1 == result.errors.size()); - CHECK(Location{{3, 12}, {3, 46}} == result.errors[0].location); + + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK(Location{{3, 22}, {3, 42}} == result.errors[0].location); + else + CHECK(Location{{3, 12}, {3, 46}} == result.errors[0].location); CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0])); } @@ -1187,6 +1221,9 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_cache_limit_normalizer") TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution") { + // CLI-114134 + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local obj = {} @@ -1355,7 +1392,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_function_that_invokes_itself_with_ end )"); - CHECK("(a) -> ()" == toString(requireType("readValue"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("(unknown) -> ()" == toString(requireType("readValue"))); + else + CHECK("(a) -> ()" == toString(requireType("readValue"))); } TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_function_that_invokes_itself_with_a_refinement_of_its_parameter_2") @@ -1368,7 +1408,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_function_that_invokes_itself_with_ end )"); - CHECK("(number) -> ()" == toString(requireType("readValue"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("(unknown) -> ()" == toString(requireType("readValue"))); + else + CHECK("(number) -> ()" == toString(requireType("readValue"))); } /* @@ -1520,6 +1563,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lti_must_record_contributing_locations") */ TEST_CASE_FIXTURE(BuiltinsFixture, "be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local function concat(target: {T}, ...: {T} | T): {T} return (nil :: any) :: {T} diff --git a/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp index f2e73ede..7db4512b 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp @@ -154,6 +154,8 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_intersection_sub_anything") TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(arg : { prop : string & number }) : never return arg @@ -164,6 +166,8 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never") TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(arg : { prop : string & number }) : boolean return arg @@ -174,6 +178,8 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything") TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_with_errorType") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(arg: number) end local a @@ -189,6 +195,8 @@ TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_w TEST_CASE_FIXTURE(Fixture, "result_of_failed_typepack_unification_is_constrained") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(arg: number) return arg end local a diff --git a/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp index 108b1fa9..f23dfb47 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp @@ -575,12 +575,12 @@ local b: Y<(), ()> TEST_CASE_FIXTURE(Fixture, "type_alias_backwards_compatible") { CheckResult result = check(R"( -type X = () -> T -type Y = (T) -> U + type X = () -> T + type Y = (T) -> U -type A = X<(number)> -type B = Y<(number), (boolean)> -type C = Y<(number), boolean> + type A = X<(number)> + type B = Y<(number), (boolean)> + type C = Y<(number), boolean> )"); LUAU_REQUIRE_NO_ERRORS(result); @@ -787,48 +787,69 @@ local d: Y ()> TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( -type Y = { a: T } -local a: Y = { a = 2 } + type Y = { a: T } + local a: Y = { a = 2 } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'"); +} - result = check(R"( -type Y = { a: (T...) -> () } -local a: Y<> +TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors2") +{ + CheckResult result = check(R"( + type Y = { a: (T...) -> () } + local a: Y<> )"); LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'"); +} - result = check(R"( -type Y = { a: (T) -> U... } -local a: Y<...number> +TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors3") +{ + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + + CheckResult result = check(R"( + type Y = { a: (T) -> U... } + local a: Y<...number> )"); LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ(toString(result.errors[0]), "Generic type 'Y' expects at least 1 type argument, but none are specified"); +} - result = check(R"( -type Packed = (T) -> T -local a: Packed +TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors4") +{ + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + + CheckResult result = check(R"( + type Packed = (T) -> T + local a: Packed )"); LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ(toString(result.errors[0]), "Type parameter list is required"); +} - result = check(R"( -type Y = { a: T } -local a: Y +TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors5") +{ + CheckResult result = check(R"( + type Y = { a: T } + local a: Y )"); LUAU_REQUIRE_ERRORS(result); +} - result = check(R"( -type Y = { a: T } -local a: Y<...number> +TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors6") +{ + CheckResult result = check(R"( + type Y = { a: T } + local a: Y<...number> )"); LUAU_REQUIRE_ERRORS(result); @@ -929,13 +950,27 @@ a = b )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + + if (FFlag::DebugLuauDeferredConstraintResolution) + { + const std::string expected = + "Type\n" + " '() -> (number, ...boolean)'\n" + "could not be converted into\n" + " '() -> (number, ...string)'; at returns().tail().variadic(), boolean is not a subtype of string"; + + CHECK(expected == toString(result.errors[0])); + } + else + { + const std::string expected = R"(Type '() -> (number, ...boolean)' could not be converted into '() -> (number, ...string)' caused by: Type 'boolean' could not be converted into 'string')"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } // TODO: File a Jira about this @@ -1030,6 +1065,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2") TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function foo(...: string): number return 1 diff --git a/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp index b2a8b084..3a880d6d 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp @@ -33,6 +33,10 @@ until _._ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint") { + // CLI-114134 We need egraphs to consistently reduce the cyclic union + // introduced by the increment here. + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local count = 0 function most_of_the_natural_numbers(): number? @@ -51,6 +55,27 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint") REQUIRE(utv != nullptr); } +TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint_using_compound_assignment") +{ + CheckResult result = check(R"( + local count = 0 + function most_of_the_natural_numbers(): number? + if count < 10 then + -- count = count + 1 + count += 1 + return count + else + return nil + end + end + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + + const FunctionType* utv = get(requireType("most_of_the_natural_numbers")); + REQUIRE(utv != nullptr); +} + TEST_CASE_FIXTURE(Fixture, "allow_specific_assign") { CheckResult result = check(R"( @@ -95,6 +120,9 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments") TEST_CASE_FIXTURE(Fixture, "optional_arguments_table") { + // CLI-115588 - Bidirectional inference does not happen for assignments + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local a:{a:string, b:string?} a = {a="ok"} @@ -209,7 +237,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_missing_property") CHECK_EQ("Key 'x' is missing from 'B' in the type 'A | B'", toString(result.errors[0])); if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("(A | B) -> number | *error-type*", toString(requireType("f"))); + CHECK_EQ("(A | B) -> number", toString(requireType("f"))); else CHECK_EQ("(A | B) -> *error-type*", toString(requireType("f"))); } @@ -261,11 +289,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_union_members") LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0])); - - if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("(A?) -> number | *error-type*", toString(requireType("f"))); - else - CHECK_EQ("(A?) -> number", toString(requireType("f"))); + CHECK_EQ("(A?) -> number", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "optional_union_functions") @@ -282,11 +306,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_union_functions") LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0])); - - if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("(A?) -> number | *error-type*", toString(requireType("f"))); - else - CHECK_EQ("(A?) -> number", toString(requireType("f"))); + CHECK_EQ("(A?) -> number", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "optional_union_methods") @@ -303,11 +323,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_union_methods") LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0])); - - if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("(A?) -> number | *error-type*", toString(requireType("f"))); - else - CHECK_EQ("(A?) -> number", toString(requireType("f"))); + CHECK_EQ("(A?) -> number", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "optional_union_follow") @@ -456,6 +472,8 @@ end TEST_CASE_FIXTURE(Fixture, "unify_unsealed_table_union_check") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( local x = { x = 3 } type A = number? @@ -537,17 +555,20 @@ Table type 'X' not compatible with type '{| w: number |}' because the former is TEST_CASE_FIXTURE(Fixture, "error_detailed_union_all") { CheckResult result = check(R"( -type X = { x: number } -type Y = { y: number } -type Z = { z: number } + type X = { x: number } + type Y = { y: number } + type Z = { z: number } -type XYZ = X | Y | Z + type XYZ = X | Y | Z -local a: XYZ = { w = 4 } + local a: XYZ = { w = 4 } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X | Y | Z'; none of the union options are compatible)"); + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK(toString(result.errors[0]) == "Type '{ w: number }' could not be converted into 'X | Y | Z'"); + else + CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X | Y | Z'; none of the union options are compatible)"); } TEST_CASE_FIXTURE(Fixture, "error_detailed_optional") @@ -559,11 +580,16 @@ local a: X? = { w = 4 } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type 'a' could not be converted into 'X?' + if (FFlag::DebugLuauDeferredConstraintResolution) + CHECK("Type '{ w: number }' could not be converted into 'X?'" == toString(result.errors[0])); + else + { + const std::string expected = R"(Type 'a' could not be converted into 'X?' caused by: None of the union options are compatible. For example: Table type 'a' not compatible with type 'X' because the former is missing field 'x')"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } // We had a bug where a cyclic union caused a stack overflow. @@ -615,6 +641,7 @@ TEST_CASE_FIXTURE(Fixture, "indexing_into_a_cyclic_union_doesnt_crash") TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; CheckResult result = check(R"( type A = { x: number, y: (number) -> string } | { z: number, y: (number) -> string } @@ -690,6 +717,8 @@ TEST_CASE_FIXTURE(Fixture, "union_of_generic_typepack_functions") TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f() function g(x : (a) -> a?) @@ -708,6 +737,8 @@ TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics") TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generic_typepacks") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f() function g(x : (number, a...) -> (number?, a...)) @@ -727,6 +758,8 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_arg_arities") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(x : (number) -> number?) local y : ((number?) -> number) | ((number | string) -> nil) = x -- OK @@ -744,6 +777,8 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_arities") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(x : () -> (number | string)) local y : (() -> number) | (() -> string) = x -- OK @@ -761,6 +796,8 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_variadics") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(x : (...nil) -> (...number?)) local y : ((...string?) -> (...number)) | ((...number?) -> nil) = x -- OK @@ -786,15 +823,27 @@ TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_arg_variadics") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::DebugLuauDeferredConstraintResolution) + { + CHECK(R"(Type + '(number) -> ()' +could not be converted into + '((...number?) -> ()) | ((number?) -> ())')" == toString(result.errors[0])); + } + else + { + const std::string expected = R"(Type '(number) -> ()' could not be converted into '((...number?) -> ()) | ((number?) -> ())'; none of the union options are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_variadics") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(x : () -> (number?, ...number)) local y : (() -> (...number)) | (() -> nil) = x -- OK @@ -824,7 +873,7 @@ TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("({| x: number |} | {| x: string |}) -> {| x: number |} | {| x: string |}", toString(requireType("f"))); + CHECK_EQ("(({ read x: unknown } & { x: number }) | ({ read x: unknown } & { x: string })) -> { x: number } | { x: string }", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types_2") @@ -840,10 +889,7 @@ TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types_2") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) - CHECK_EQ("({ x: number } | { x: string }) -> number | string", toString(requireType("f"))); - else - CHECK_EQ("({| x: number |} | {| x: string |}) -> number | string", toString(requireType("f"))); + CHECK_EQ("({ x: number } | { x: string }) -> number | string", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "union_table_any_property") @@ -864,6 +910,8 @@ TEST_CASE_FIXTURE(Fixture, "union_table_any_property") TEST_CASE_FIXTURE(Fixture, "union_function_any_args") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(sup : ((...any) -> (...any))?, sub : ((number) -> (...any))) sup = sub @@ -886,6 +934,8 @@ TEST_CASE_FIXTURE(Fixture, "optional_any") TEST_CASE_FIXTURE(Fixture, "generic_function_with_optional_arg") { + ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + CheckResult result = check(R"( function f(x : T?) : {T} local result = {} diff --git a/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp index f1924b1c..42007078 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp @@ -121,11 +121,11 @@ TEST_CASE_FIXTURE(Fixture, "type_packs_containing_never_is_itself_uninhabitable" if (FFlag::DebugLuauDeferredConstraintResolution) { LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ("Function only returns 2 values, but 3 are required here", toString(result.errors[0])); + CHECK("Function only returns 2 values, but 3 are required here" == toString(result.errors[0])); - CHECK_EQ("string", toString(requireType("x"))); - CHECK_EQ("never", toString(requireType("y"))); - CHECK_EQ("*error-type*", toString(requireType("z"))); + CHECK("string" == toString(requireType("x"))); + CHECK("never" == toString(requireType("y"))); + CHECK("nil" == toString(requireType("z"))); } else { @@ -335,8 +335,20 @@ TEST_CASE_FIXTURE(Fixture, "math_operators_and_never") end )"); - LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ("(nil, a) -> boolean", toString(requireType("mul"))); + if (FFlag::DebugLuauDeferredConstraintResolution) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK(get(result.errors[0])); + + // CLI-114134 Egraph-based simplification. + // CLI-116549 x ~= nil : false when x : nil + CHECK("(nil, a) -> and>" == toString(requireType("mul"))); + } + else + { + LUAU_REQUIRE_NO_ERRORS(result); + CHECK_EQ("(nil, a) -> boolean", toString(requireType("mul"))); + } } TEST_CASE_FIXTURE(Fixture, "compare_never") diff --git a/Dependencies/luau/Luau/tools/faillist.txt b/Dependencies/luau/Luau/tools/faillist.txt index da08116f..d785d14d 100644 --- a/Dependencies/luau/Luau/tools/faillist.txt +++ b/Dependencies/luau/Luau/tools/faillist.txt @@ -1,26 +1,9 @@ -AstQuery.last_argument_function_call_type AutocompleteTest.anonymous_autofilled_generic_on_argument_type_pack_vararg AutocompleteTest.anonymous_autofilled_generic_type_pack_vararg AutocompleteTest.autocomplete_string_singletons -AutocompleteTest.string_singleton_as_table_key AutocompleteTest.suggest_table_keys AutocompleteTest.type_correct_suggestion_for_overloads AutocompleteTest.type_correct_suggestion_in_table -BuiltinTests.aliased_string_format -BuiltinTests.assert_removes_falsy_types_even_from_type_pack_tail_but_only_for_the_first_type -BuiltinTests.assert_returns_false_and_string_iff_it_knows_the_first_argument_cannot_be_truthy -BuiltinTests.coroutine_resume_anything_goes -BuiltinTests.select_slightly_out_of_range -BuiltinTests.select_way_out_of_range -BuiltinTests.select_with_variadic_typepack_tail_and_string_head -BuiltinTests.set_metatable_needs_arguments -BuiltinTests.setmetatable_should_not_mutate_persisted_types -BuiltinTests.sort_with_bad_predicate -BuiltinTests.string_format_as_method -BuiltinTests.string_format_correctly_ordered_types -BuiltinTests.string_format_report_all_type_errors_at_correct_positions -BuiltinTests.string_format_use_correct_argument2 -BuiltinTests.table_freeze_is_generic GenericsTests.do_not_always_instantiate_generic_intersection_types GenericsTests.error_detailed_function_mismatch_generic_pack GenericsTests.error_detailed_function_mismatch_generic_types @@ -47,238 +30,16 @@ IntersectionTypes.overloaded_functions_mentioning_generic_packs IntersectionTypes.overloaded_functions_mentioning_generics IntersectionTypes.overloaded_functions_returning_intersections IntersectionTypes.overloadeded_functions_with_never_arguments -IntersectionTypes.overloadeded_functions_with_never_result -IntersectionTypes.overloadeded_functions_with_overlapping_results_and_variadics -IntersectionTypes.overloadeded_functions_with_unknown_arguments -IntersectionTypes.overloadeded_functions_with_unknown_result -IntersectionTypes.overloadeded_functions_with_weird_typepacks_1 -IntersectionTypes.overloadeded_functions_with_weird_typepacks_2 -IntersectionTypes.overloadeded_functions_with_weird_typepacks_3 -IntersectionTypes.overloadeded_functions_with_weird_typepacks_4 -IntersectionTypes.table_write_sealed_indirect -IntersectionTypes.union_saturate_overloaded_functions -Linter.TableOperationsIndexer ModuleTests.clone_self_property Negations.cofinite_strings_can_be_compared_for_equality Normalize.higher_order_function_with_annotation -Normalize.negations_of_tables -Normalize.specific_functions_cannot_be_negated -ProvisionalTests.assign_table_with_refined_property_with_a_similar_type_is_illegal -ProvisionalTests.discriminate_from_x_not_equal_to_nil -ProvisionalTests.do_not_ice_when_trying_to_pick_first_of_generic_type_pack -ProvisionalTests.error_on_eq_metamethod_returning_a_type_other_than_boolean -ProvisionalTests.expected_type_should_be_a_helpful_deduction_guide_for_function_calls -ProvisionalTests.floating_generics_should_not_be_allowed -ProvisionalTests.free_options_can_be_unified_together -ProvisionalTests.free_options_cannot_be_unified_together -ProvisionalTests.generic_type_leak_to_module_interface -ProvisionalTests.generic_type_leak_to_module_interface_variadic -ProvisionalTests.luau-polyfill.Array.filter -ProvisionalTests.luau_roact_useState_minimization -ProvisionalTests.optional_class_instances_are_invariant -ProvisionalTests.setmetatable_constrains_free_type_into_free_table -ProvisionalTests.specialization_binds_with_prototypes_too_early -ProvisionalTests.table_insert_with_a_singleton_argument -ProvisionalTests.table_unification_infinite_recursion -ProvisionalTests.typeguard_inference_incomplete -ProvisionalTests.while_body_are_also_refined -RefinementTest.call_an_incompatible_function_after_using_typeguard -RefinementTest.dataflow_analysis_can_tell_refinements_when_its_appropriate_to_refine_into_nil_or_never -RefinementTest.discriminate_from_isa_of_x -RefinementTest.discriminate_from_truthiness_of_x -RefinementTest.globals_can_be_narrowed_too -RefinementTest.isa_type_refinement_must_be_known_ahead_of_time -RefinementTest.nonoptional_type_can_narrow_to_nil_if_sense_is_true -RefinementTest.not_t_or_some_prop_of_t RefinementTest.refine_a_param_that_got_resolved_during_constraint_solving_stage -RefinementTest.refine_a_property_of_some_global -RefinementTest.refine_param_of_type_folder_or_part_without_using_typeof -RefinementTest.refine_unknown_to_table_then_clone_it -RefinementTest.truthy_constraint_on_properties -RefinementTest.type_annotations_arent_relevant_when_doing_dataflow_analysis -RefinementTest.type_guard_narrowed_into_nothingness -RefinementTest.type_narrow_to_vector -RefinementTest.typeguard_cast_free_table_to_vector -RefinementTest.typeguard_in_assert_position RefinementTest.x_as_any_if_x_is_instance_elseif_x_is_table RefinementTest.x_is_not_instance_or_else_not_part -ToDot.function -ToString.exhaustive_toString_of_cyclic_table -ToString.free_types -ToString.named_metatable_toStringNamedFunction -ToString.no_parentheses_around_cyclic_function_type_in_intersection -ToString.pick_distinct_names_for_mixed_explicit_and_implicit_generics -ToString.primitive -ToString.toStringErrorPack -TryUnifyTests.members_of_failed_typepack_unification_are_unified_with_errorType -TryUnifyTests.result_of_failed_typepack_unification_is_constrained -TryUnifyTests.uninhabited_table_sub_anything -TryUnifyTests.uninhabited_table_sub_never -TypeAliases.dont_lose_track_of_PendingExpansionTypes_after_substitution -TypeAliases.generic_param_remap -TypeAliases.mismatched_generic_type_param -TypeAliases.mutually_recursive_generic_aliases -TypeAliases.mutually_recursive_types_restriction_not_ok_1 -TypeAliases.mutually_recursive_types_restriction_not_ok_2 -TypeAliases.mutually_recursive_types_swapsies_not_ok -TypeAliases.recursive_types_restriction_not_ok -TypeAliases.report_shadowed_aliases -TypeAliases.type_alias_local_mutation -TypeAliases.type_alias_local_rename -TypeAliases.type_alias_of_an_imported_recursive_generic_type -TypeInfer.be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload -TypeInfer.check_type_infer_recursion_count -TypeInfer.checking_should_not_ice -TypeInfer.cli_50041_committing_txnlog_in_apollo_client_error -TypeInfer.dont_ice_when_failing_the_occurs_check -TypeInfer.dont_report_type_errors_within_an_AstExprError -TypeInfer.dont_report_type_errors_within_an_AstStatError -TypeInfer.follow_on_new_types_in_substitution -TypeInfer.globals -TypeInfer.globals2 -TypeInfer.infer_through_group_expr -TypeInfer.no_stack_overflow_from_isoptional -TypeInfer.recursive_function_that_invokes_itself_with_a_refinement_of_its_parameter -TypeInfer.recursive_function_that_invokes_itself_with_a_refinement_of_its_parameter_2 -TypeInfer.tc_after_error_recovery_no_replacement_name_in_error -TypeInfer.type_infer_recursion_limit_no_ice -TypeInfer.type_infer_recursion_limit_normalizer -TypeInfer.unify_nearly_identical_recursive_types -TypeInferClasses.cannot_unify_class_instance_with_primitive -TypeInferClasses.class_type_mismatch_with_name_conflict -TypeInferClasses.detailed_class_unification_error -TypeInferClasses.indexable_classes -TypeInferClasses.table_class_unification_reports_sane_errors_for_missing_properties -TypeInferClasses.we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class -TypeInferFunctions.another_other_higher_order_function -TypeInferFunctions.bidirectional_checking_of_callback_property -TypeInferFunctions.calling_function_with_anytypepack_doesnt_leak_free_types -TypeInferFunctions.complicated_return_types_require_an_explicit_annotation -TypeInferFunctions.concrete_functions_are_not_supertypes_of_function -TypeInferFunctions.dont_assert_when_the_tarjan_limit_is_exceeded_during_generalization -TypeInferFunctions.dont_give_other_overloads_message_if_only_one_argument_matching_overload_exists -TypeInferFunctions.dont_infer_parameter_types_for_functions_from_their_call_site -TypeInferFunctions.duplicate_functions_with_different_signatures_not_allowed_in_nonstrict -TypeInferFunctions.error_detailed_function_mismatch_arg -TypeInferFunctions.error_detailed_function_mismatch_arg_count -TypeInferFunctions.error_detailed_function_mismatch_ret -TypeInferFunctions.error_detailed_function_mismatch_ret_count -TypeInferFunctions.error_detailed_function_mismatch_ret_mult -TypeInferFunctions.function_cast_error_uses_correct_language -TypeInferFunctions.function_decl_non_self_sealed_overwrite_2 -TypeInferFunctions.function_decl_non_self_unsealed_overwrite -TypeInferFunctions.function_does_not_return_enough_values -TypeInferFunctions.function_exprs_are_generalized_at_signature_scope_not_enclosing -TypeInferFunctions.function_is_supertype_of_concrete_functions -TypeInferFunctions.function_statement_sealed_table_assignment_through_indexer -TypeInferFunctions.generic_packs_are_not_variadic -TypeInferFunctions.higher_order_function_4 -TypeInferFunctions.improved_function_arg_mismatch_error_nonstrict -TypeInferFunctions.improved_function_arg_mismatch_errors -TypeInferFunctions.infer_anonymous_function_arguments -TypeInferFunctions.infer_anonymous_function_arguments_outside_call -TypeInferFunctions.infer_generic_function_function_argument -TypeInferFunctions.infer_generic_function_function_argument_overloaded -TypeInferFunctions.infer_return_value_type -TypeInferFunctions.inferred_higher_order_functions_are_quantified_at_the_right_time3 -TypeInferFunctions.instantiated_type_packs_must_have_a_non_null_scope -TypeInferFunctions.list_only_alternative_overloads_that_match_argument_count -TypeInferFunctions.luau_subtyping_is_np_hard -TypeInferFunctions.no_lossy_function_type -TypeInferFunctions.occurs_check_failure_in_function_return_type -TypeInferFunctions.other_things_are_not_related_to_function -TypeInferFunctions.param_1_and_2_both_takes_the_same_generic_but_their_arguments_are_incompatible -TypeInferFunctions.param_1_and_2_both_takes_the_same_generic_but_their_arguments_are_incompatible_2 -TypeInferFunctions.report_exiting_without_return_nonstrict -TypeInferFunctions.return_type_by_overload TypeInferFunctions.simple_unannotated_mutual_recursion -TypeInferFunctions.too_few_arguments_variadic -TypeInferFunctions.too_few_arguments_variadic_generic -TypeInferFunctions.too_few_arguments_variadic_generic2 -TypeInferFunctions.too_many_arguments -TypeInferFunctions.too_many_return_values_in_parentheses -TypeInferFunctions.too_many_return_values_no_function -TypeInferFunctions.unifier_should_not_bind_free_types -TypeInferLoops.cli_68448_iterators_need_not_accept_nil -TypeInferLoops.dcr_iteration_on_never_gives_never -TypeInferLoops.dcr_xpath_candidates -TypeInferLoops.for_in_loop -TypeInferLoops.for_in_loop_error_on_factory_not_returning_the_right_amount_of_values -TypeInferLoops.for_in_loop_error_on_iterator_requiring_args_but_none_given -TypeInferLoops.for_in_loop_on_error -TypeInferLoops.for_in_loop_on_non_function -TypeInferLoops.for_in_loop_with_next -TypeInferLoops.for_loop -TypeInferLoops.ipairs_produces_integral_indices -TypeInferLoops.iterate_over_properties -TypeInferLoops.iteration_regression_issue_69967_alt -TypeInferLoops.loop_iter_metamethod_nil -TypeInferLoops.loop_iter_metamethod_not_enough_returns -TypeInferLoops.loop_iter_metamethod_ok -TypeInferLoops.loop_iter_metamethod_ok_with_inference -TypeInferLoops.loop_iter_no_indexer_strict -TypeInferLoops.loop_iter_trailing_nil -TypeInferLoops.loop_typecheck_crash_on_empty_optional -TypeInferLoops.properly_infer_iteratee_is_a_free_table -TypeInferLoops.repeat_loop -TypeInferLoops.while_loop -TypeInferModules.require -TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2 -TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon -TypeInferOOP.inferring_hundreds_of_self_calls_should_not_suffocate_memory -TypeInferOOP.promise_type_error_too_complex -TypeInferOperators.cli_38355_recursive_union -TypeInferOperators.compound_assign_result_must_be_compatible_with_var -TypeInferOperators.concat_op_on_free_lhs_and_string_rhs -TypeInferOperators.concat_op_on_string_lhs_and_free_rhs -TypeInferOperators.disallow_string_and_types_without_metatables_from_arithmetic_binary_ops -TypeInferOperators.luau_polyfill_is_array -TypeInferOperators.mm_comparisons_must_return_a_boolean -TypeInferOperators.reworked_and -TypeInferOperators.strict_binary_op_where_lhs_unknown -TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection -TypeInferOperators.typecheck_overloaded_multiply_that_is_an_intersection_on_rhs -TypeInferOperators.typecheck_unary_len_error -TypeInferOperators.typecheck_unary_minus_error -TypeInferOperators.UnknownGlobalCompoundAssign -TypeInferPrimitives.CheckMethodsOfNumber TypeInferUnknownNever.assign_to_local_which_is_never TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_never TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_sorta_never -TypeInferUnknownNever.length_of_never -TypeInferUnknownNever.math_operators_and_never -TypeInferUnknownNever.type_packs_containing_never_is_itself_uninhabitable TypePackTests.fuzz_typepack_iter_follow_2 -TypePackTests.pack_tail_unification_check -TypePackTests.type_alias_backwards_compatible -TypePackTests.type_alias_default_type_errors -TypePackTests.unify_variadic_tails_in_arguments -TypeSingletons.enums_using_singletons_mismatch -TypeSingletons.error_detailed_tagged_union_mismatch_bool -TypeSingletons.error_detailed_tagged_union_mismatch_string -TypeSingletons.overloaded_function_call_with_singletons_mismatch -TypeSingletons.return_type_of_f_is_not_widened -TypeSingletons.table_properties_type_error_escapes -TypeSingletons.widen_the_supertype_if_it_is_free_and_subtype_has_singleton TypeStatesTest.typestates_preserve_error_suppression_properties -UnionTypes.error_detailed_optional -UnionTypes.error_detailed_union_all -UnionTypes.generic_function_with_optional_arg -UnionTypes.index_on_a_union_type_with_missing_property -UnionTypes.less_greedy_unification_with_union_types -UnionTypes.optional_arguments_table -UnionTypes.optional_union_functions -UnionTypes.optional_union_members -UnionTypes.optional_union_methods -UnionTypes.return_types_can_be_disjoint -UnionTypes.table_union_write_indirect -UnionTypes.unify_unsealed_table_union_check -UnionTypes.union_function_any_args -UnionTypes.union_of_functions_mentioning_generic_typepacks -UnionTypes.union_of_functions_mentioning_generics -UnionTypes.union_of_functions_with_mismatching_arg_arities -UnionTypes.union_of_functions_with_mismatching_arg_variadics -UnionTypes.union_of_functions_with_mismatching_result_arities -UnionTypes.union_of_functions_with_mismatching_result_variadics -UnionTypes.union_of_functions_with_variadics VisitType.throw_when_limit_is_exceeded diff --git a/Dependencies/luau/Version-0.638 b/Dependencies/luau/Version-0.639 similarity index 100% rename from Dependencies/luau/Version-0.638 rename to Dependencies/luau/Version-0.639 diff --git a/Dependencies/luau/luau.lua b/Dependencies/luau/luau.lua index 251e8107..1aeee385 100644 --- a/Dependencies/luau/luau.lua +++ b/Dependencies/luau/luau.lua @@ -18,14 +18,14 @@ Luau.SetupAst = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/**.h", sourceDir .. "/**.c", sourceDir .. "/**.cpp" } - Solution.Util.SetFiles(files) Solution.Util.SetIncludes(includeDir) Solution.Util.SetDefines(defines) @@ -45,7 +45,7 @@ Luau.SetupCompiler = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { @@ -72,10 +72,11 @@ Luau.SetupConfig = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/**.h", sourceDir .. "/**.c", sourceDir .. "/**.cpp" } @@ -98,10 +99,11 @@ Luau.SetupAnalysis = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/**.h", sourceDir .. "/**.c", sourceDir .. "/**.cpp" } @@ -128,10 +130,11 @@ Luau.SetupVM = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/**.h", sourceDir .. "/**.c", sourceDir .. "/**.cpp" } @@ -159,10 +162,11 @@ Luau.SetupCodeGen = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/**.h", sourceDir .. "/**.c", sourceDir .. "/**.cpp" } @@ -185,10 +189,11 @@ Luau.SetupIsocline = function() local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } Solution.Util.SetLanguage("C++") - Solution.Util.SetCppDialect(17) + Solution.Util.SetCppDialect(20) local files = { + includeDir .. "/isocline.h", sourceDir .. "/isocline.c" } Solution.Util.SetFiles(files) From 62919400429622116472ecc81eddcd8a0afca264 Mon Sep 17 00:00:00 2001 From: NixAJ Date: Tue, 17 Sep 2024 19:26:58 +0200 Subject: [PATCH 04/11] Updated Luau to version 0.643 --- Dependencies/luau/Luau/.gitignore | 1 + .../include/Luau/BuiltinDefinitions.h | 3 +- .../Luau/Analysis/include/Luau/Frontend.h | 4 + .../luau/Luau/Analysis/include/Luau/Set.h | 2 +- .../Luau/Analysis/include/Luau/Subtyping.h | 144 +- .../luau/Luau/Analysis/include/Luau/Type.h | 22 +- .../Luau/Analysis/include/Luau/TypeChecker2.h | 194 + .../Luau/Analysis/include/Luau/VisitType.h | 10 +- .../luau/Luau/Analysis/src/AnyTypeSummary.cpp | 19 +- .../luau/Luau/Analysis/src/AstQuery.cpp | 9 +- .../luau/Luau/Analysis/src/Autocomplete.cpp | 14 +- .../Luau/Analysis/src/BuiltinDefinitions.cpp | 67 +- Dependencies/luau/Luau/Analysis/src/Clone.cpp | 4 +- .../Luau/Analysis/src/ConstraintGenerator.cpp | 2 +- .../luau/Luau/Analysis/src/DataFlowGraph.cpp | 4 +- .../luau/Luau/Analysis/src/Frontend.cpp | 24 +- .../luau/Luau/Analysis/src/Generalization.cpp | 16 +- .../luau/Luau/Analysis/src/Instantiation.cpp | 4 +- .../luau/Luau/Analysis/src/Linter.cpp | 4 +- .../luau/Luau/Analysis/src/Module.cpp | 7 +- .../Analysis/src/NonStrictTypeChecker.cpp | 14 +- .../luau/Luau/Analysis/src/Normalize.cpp | 32 +- .../Luau/Analysis/src/OverloadResolution.cpp | 15 +- Dependencies/luau/Luau/Analysis/src/Scope.cpp | 6 +- .../luau/Luau/Analysis/src/Simplify.cpp | 13 +- .../luau/Luau/Analysis/src/Substitution.cpp | 6 +- .../luau/Luau/Analysis/src/Subtyping.cpp | 374 +- .../luau/Luau/Analysis/src/Symbol.cpp | 4 +- Dependencies/luau/Luau/Analysis/src/ToDot.cpp | 4 +- .../luau/Luau/Analysis/src/ToString.cpp | 26 +- Dependencies/luau/Luau/Analysis/src/Type.cpp | 2 +- .../luau/Luau/Analysis/src/TypeChecker2.cpp | 4611 ++++++++--------- .../luau/Luau/Analysis/src/TypeFunction.cpp | 102 +- .../luau/Luau/Analysis/src/TypeInfer.cpp | 230 +- .../luau/Luau/Analysis/src/TypePack.cpp | 2 +- .../luau/Luau/Analysis/src/TypePath.cpp | 14 +- .../luau/Luau/Analysis/src/TypeUtils.cpp | 10 +- .../luau/Luau/Analysis/src/Unifier.cpp | 6 +- Dependencies/luau/Luau/Ast/src/Parser.cpp | 3 +- Dependencies/luau/Luau/CLI/Require.cpp | 13 +- Dependencies/luau/Luau/CMakeLists.txt | 1 + .../Luau/CodeGen/include/Luau/IrVisitUseDef.h | 47 +- .../Luau/CodeGen/src/BytecodeAnalysis.cpp | 4 - .../luau/Luau/CodeGen/src/CodeGenAssembly.cpp | 5 +- .../luau/Luau/CodeGen/src/EmitBuiltinsX64.cpp | 36 - .../luau/Luau/CodeGen/src/IrBuilder.cpp | 4 - .../luau/Luau/CodeGen/src/IrLoweringA64.cpp | 116 +- .../luau/Luau/CodeGen/src/IrLoweringX64.cpp | 18 +- .../Luau/CodeGen/src/IrTranslateBuiltins.cpp | 88 +- .../luau/Luau/CodeGen/src/IrTranslation.cpp | 21 +- .../CodeGen/src/IrValueLocationTracking.cpp | 6 +- .../Luau/CodeGen/src/OptimizeConstProp.cpp | 12 +- .../luau/Luau/Common/include/Luau/Bytecode.h | 2 +- .../luau/Luau/Common/include/Luau/Common.h | 13 + .../Common/include/Luau/ExperimentalFlags.h | 3 +- .../Luau/Compiler/src/BytecodeBuilder.cpp | 112 +- .../luau/Luau/Compiler/src/Compiler.cpp | 58 +- Dependencies/luau/Luau/Compiler/src/Types.cpp | 11 +- .../luau/Luau/EqSat/include/Luau/EGraph.h | 5 +- .../luau/Luau/EqSat/include/Luau/Language.h | 7 - .../Luau/EqSat/include/Luau/LanguageHash.h | 1 + .../luau/Luau/EqSat/src/UnionFind.cpp | 3 + Dependencies/luau/Luau/Makefile | 3 +- Dependencies/luau/Luau/VM/src/lstrlib.cpp | 9 +- Dependencies/luau/Luau/VM/src/ltable.cpp | 2 +- Dependencies/luau/Luau/fuzz/proto.cpp | 4 +- .../luau/Luau/tests/AnyTypeSummary.test.cpp | 507 +- .../luau/Luau/tests/AstQuery.test.cpp | 6 +- .../luau/Luau/tests/Autocomplete.test.cpp | 36 +- .../luau/Luau/tests/Compiler.test.cpp | 9 - .../luau/Luau/tests/Conformance.test.cpp | 18 + .../Luau/tests/ConstraintGeneratorFixture.cpp | 4 +- .../luau/Luau/tests/ConstraintSolver.test.cpp | 2 +- .../luau/Luau/tests/DataFlowGraph.test.cpp | 4 +- Dependencies/luau/Luau/tests/Differ.test.cpp | 68 +- Dependencies/luau/Luau/tests/Error.test.cpp | 6 +- Dependencies/luau/Luau/tests/Fixture.cpp | 10 +- Dependencies/luau/Luau/tests/Fixture.h | 1 + .../luau/Luau/tests/Frontend.test.cpp | 28 +- .../luau/Luau/tests/Generalization.test.cpp | 4 +- .../luau/Luau/tests/IrBuilder.test.cpp | 10 - .../luau/Luau/tests/IrLowering.test.cpp | 61 +- Dependencies/luau/Luau/tests/Linter.test.cpp | 6 +- Dependencies/luau/Luau/tests/Module.test.cpp | 11 +- .../Luau/tests/NonStrictTypeChecker.test.cpp | 4 +- .../luau/Luau/tests/NonstrictMode.test.cpp | 16 +- .../luau/Luau/tests/Normalize.test.cpp | 44 +- Dependencies/luau/Luau/tests/Parser.test.cpp | 10 +- .../luau/Luau/tests/RequireByString.test.cpp | 6 + .../luau/Luau/tests/RuntimeLimits.test.cpp | 4 +- .../luau/Luau/tests/Simplify.test.cpp | 4 +- .../luau/Luau/tests/Subtyping.test.cpp | 40 +- Dependencies/luau/Luau/tests/Symbol.test.cpp | 4 +- Dependencies/luau/Luau/tests/ToDot.test.cpp | 10 +- .../luau/Luau/tests/ToString.test.cpp | 54 +- Dependencies/luau/Luau/tests/TxnLog.test.cpp | 8 +- .../luau/Luau/tests/TypeFunction.test.cpp | 183 +- .../Luau/tests/TypeInfer.aliases.test.cpp | 42 +- .../Luau/tests/TypeInfer.annotations.test.cpp | 8 +- .../Luau/tests/TypeInfer.anyerror.test.cpp | 22 +- .../Luau/tests/TypeInfer.builtins.test.cpp | 60 +- .../Luau/tests/TypeInfer.classes.test.cpp | 30 +- .../Luau/tests/TypeInfer.functions.test.cpp | 148 +- .../Luau/tests/TypeInfer.generics.test.cpp | 132 +- .../TypeInfer.intersectionTypes.test.cpp | 252 +- .../luau/Luau/tests/TypeInfer.loops.test.cpp | 72 +- .../Luau/tests/TypeInfer.modules.test.cpp | 10 +- .../Luau/tests/TypeInfer.negations.test.cpp | 3 + .../luau/Luau/tests/TypeInfer.oop.test.cpp | 12 +- .../Luau/tests/TypeInfer.operators.test.cpp | 74 +- .../Luau/tests/TypeInfer.primitives.test.cpp | 2 +- .../Luau/tests/TypeInfer.provisional.test.cpp | 68 +- .../Luau/tests/TypeInfer.refinements.test.cpp | 91 +- .../Luau/tests/TypeInfer.singletons.test.cpp | 28 +- .../luau/Luau/tests/TypeInfer.tables.test.cpp | 240 +- .../luau/Luau/tests/TypeInfer.test.cpp | 60 +- .../Luau/tests/TypeInfer.tryUnify.test.cpp | 14 +- .../Luau/tests/TypeInfer.typePacks.test.cpp | 38 +- .../Luau/tests/TypeInfer.typestates.test.cpp | 18 +- .../Luau/tests/TypeInfer.unionTypes.test.cpp | 52 +- .../tests/TypeInfer.unknownnever.test.cpp | 30 +- .../luau/Luau/tests/TypePath.test.cpp | 12 +- Dependencies/luau/Luau/tests/TypeVar.test.cpp | 2 +- .../luau/Luau/tests/Unifier2.test.cpp | 4 +- .../luau/Luau/tests/VisitType.test.cpp | 35 +- .../luau/Luau/tests/conformance/vector.lua | 19 + Dependencies/luau/Luau/tests/main.cpp | 2 +- .../tests/require/with_config/src/.luaurc | 3 +- .../src/directory_alias_requirer.luau | 1 + .../subdirectory/subdirectory_dependency.luau | 1 + Dependencies/luau/Luau/tools/faillist.txt | 45 - .../luau/Luau/tools/fuzz/requirements.txt | 2 +- .../luau/Luau/tools/lldb_formatters.py | 2 +- Dependencies/luau/Luau/tools/test_dcr.py | 2 +- .../luau/{Version-0.639 => Version-0.643} | 0 135 files changed, 5075 insertions(+), 4371 deletions(-) create mode 100644 Dependencies/luau/Luau/tests/require/with_config/src/directory_alias_requirer.luau create mode 100644 Dependencies/luau/Luau/tests/require/with_config/src/subdirectory/subdirectory_dependency.luau rename Dependencies/luau/{Version-0.639 => Version-0.643} (100%) diff --git a/Dependencies/luau/Luau/.gitignore b/Dependencies/luau/Luau/.gitignore index 8e5c95dd..764b97cf 100644 --- a/Dependencies/luau/Luau/.gitignore +++ b/Dependencies/luau/Luau/.gitignore @@ -1,5 +1,6 @@ /build/ /build[.-]*/ +/out /cmake/ /cmake[.-]*/ /coverage/ diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/BuiltinDefinitions.h b/Dependencies/luau/Luau/Analysis/include/Luau/BuiltinDefinitions.h index 94b0d87f..71e50580 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/BuiltinDefinitions.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/BuiltinDefinitions.h @@ -13,6 +13,7 @@ struct Frontend; struct GlobalTypes; struct TypeChecker; struct TypeArena; +struct Subtyping; void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeCheckForAutocomplete = false); TypeId makeUnion(TypeArena& arena, std::vector&& types); @@ -65,7 +66,7 @@ TypeId makeFunction( // Polymorphic void attachMagicFunction(TypeId ty, MagicFunction fn); void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn); void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn); - +void attachDcrMagicFunctionTypeCheck(TypeId ty, DcrMagicFunctionTypeCheck fn); Property makeProperty(TypeId ty, std::optional documentationSymbol = std::nullopt); void assignPropDocumentationSymbols(TableType::Props& props, const std::string& baseName); diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Frontend.h b/Dependencies/luau/Luau/Analysis/include/Luau/Frontend.h index f476b582..d8a40d24 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Frontend.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Frontend.h @@ -108,6 +108,10 @@ struct FrontendOptions // When true, some internal complexity limits will be scaled down for modules that miss the limit set by moduleTimeLimitSec bool applyInternalLimitScaling = false; + + // An optional callback which is called for every *dirty* module was checked + // Is multi-threaded typechecking is used, this callback might be called from multiple threads and has to be thread-safe + std::function customModuleCheck; }; struct CheckResult diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Set.h b/Dependencies/luau/Luau/Analysis/include/Luau/Set.h index 274375cf..613e5aa5 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Set.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Set.h @@ -4,7 +4,7 @@ #include "Luau/Common.h" #include "Luau/DenseHash.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h b/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h index 01f1a7ab..18217a6b 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Subtyping.h @@ -125,7 +125,6 @@ struct Subtyping NotNull normalizer; NotNull iceReporter; - NotNull scope; TypeCheckLimits limits; enum class Variance @@ -144,8 +143,7 @@ struct Subtyping NotNull builtinTypes, NotNull typeArena, NotNull normalizer, - NotNull iceReporter, - NotNull scope + NotNull iceReporter ); Subtyping(const Subtyping&) = delete; @@ -164,75 +162,125 @@ struct Subtyping // TODO cyclic types // TODO recursion limits - SubtypingResult isSubtype(TypeId subTy, TypeId superTy); - SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy); + SubtypingResult isSubtype(TypeId subTy, TypeId superTy, NotNull scope); + SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy, NotNull scope); private: DenseHashMap, SubtypingResult, TypePairHash> resultCache{{}}; SubtypingResult cache(SubtypingEnvironment& env, SubtypingResult res, TypeId subTy, TypeId superTy); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypePackId subTy, TypePackId superTy); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp, NotNull scope); template - SubtypingResult isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy); + SubtypingResult isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull scope); template - SubtypingResult isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy); + SubtypingResult isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull scope); template - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TryPair& pair); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull scope); template - SubtypingResult isContravariantWith(SubtypingEnvironment& env, const TryPair& pair); + SubtypingResult isContravariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull); template - SubtypingResult isInvariantWith(SubtypingEnvironment& env, const TryPair& pair); - - SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy); - - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation); - - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const PrimitiveType* superPrim); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const PrimitiveType* superPrim); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const SingletonType* superSingleton); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const ClassType* subClass, TypeId superTy, const TableType* superTable); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const FunctionType* subFunction, const FunctionType* superFunction); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable); - - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableIndexer& subIndexer, const TableIndexer& superIndexer); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name); + SubtypingResult isInvariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull); + + SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy, NotNull scope); + + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation, NotNull scope); + + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const PrimitiveType* superPrim, NotNull scope); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const SingletonType* subSingleton, + const PrimitiveType* superPrim, + NotNull scope + ); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const SingletonType* subSingleton, + const SingletonType* superSingleton, + NotNull scope + ); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass, NotNull scope); + SubtypingResult + isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const ClassType* subClass, TypeId superTy, const TableType* superTable, NotNull); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const FunctionType* subFunction, + const FunctionType* superFunction, + NotNull scope + ); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable, NotNull scope); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable, NotNull scope); + + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const TableIndexer& subIndexer, + const TableIndexer& superIndexer, + NotNull scope + ); + SubtypingResult + isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name, NotNull); SubtypingResult isCovariantWith( SubtypingEnvironment& env, const std::shared_ptr& subNorm, - const std::shared_ptr& superNorm + const std::shared_ptr& superNorm, + NotNull scope ); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const NormalizedClassType& superClass); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const NormalizedStringType& superString); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const TypeIds& superTables); SubtypingResult isCovariantWith( SubtypingEnvironment& env, - const NormalizedFunctionType& subFunction, - const NormalizedFunctionType& superFunction + const NormalizedClassType& subClass, + const NormalizedClassType& superClass, + NotNull scope + ); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables, NotNull scope); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const NormalizedStringType& subString, + const NormalizedStringType& superString, + NotNull scope ); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const NormalizedStringType& subString, + const TypeIds& superTables, + NotNull scope + ); + SubtypingResult + isCovariantWith(SubtypingEnvironment& env, const NormalizedFunctionType& subFunction, const NormalizedFunctionType& superFunction, NotNull); + SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes, NotNull scope); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const VariadicTypePack* subVariadic, const VariadicTypePack* superVariadic); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeFunctionInstanceType* subFunctionInstance, const TypeId superTy); - SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFunctionInstanceType* superFunctionInstance); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const VariadicTypePack* subVariadic, + const VariadicTypePack* superVariadic, + NotNull scope + ); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const TypeFunctionInstanceType* subFunctionInstance, + const TypeId superTy, + NotNull scope + ); + SubtypingResult isCovariantWith( + SubtypingEnvironment& env, + const TypeId subTy, + const TypeFunctionInstanceType* superFunctionInstance, + NotNull scope + ); bool bindGeneric(SubtypingEnvironment& env, TypeId subTp, TypeId superTp); bool bindGeneric(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp); @@ -240,7 +288,7 @@ struct Subtyping template TypeId makeAggregateType(const Container& container, TypeId orElse); - std::pair handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance); + std::pair handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance, NotNull scope); [[noreturn]] void unexpected(TypeId ty); [[noreturn]] void unexpected(TypePackId tp); diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/Type.h b/Dependencies/luau/Luau/Analysis/include/Luau/Type.h index 2b2cb960..a43dbff9 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/Type.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/Type.h @@ -34,6 +34,8 @@ using ScopePtr = std::shared_ptr; struct TypeFunction; struct Constraint; +struct Subtyping; +struct TypeChecker2; /** * There are three kinds of type variables: @@ -289,7 +291,6 @@ struct MagicFunctionCallContext }; using DcrMagicFunction = std::function; - struct MagicRefinementContext { NotNull scope; @@ -297,8 +298,17 @@ struct MagicRefinementContext std::vector> discriminantTypes; }; -using DcrMagicRefinement = void (*)(const MagicRefinementContext&); +struct MagicFunctionTypeCheckContext +{ + NotNull typechecker; + NotNull builtinTypes; + const class AstExprCall* callSite; + TypePackId arguments; + NotNull checkScope; +}; +using DcrMagicRefinement = void (*)(const MagicRefinementContext&); +using DcrMagicFunctionTypeCheck = std::function; struct FunctionType { // Global monomorphic function @@ -359,6 +369,14 @@ struct FunctionType MagicFunction magicFunction = nullptr; DcrMagicFunction dcrMagicFunction = nullptr; DcrMagicRefinement dcrMagicRefinement = nullptr; + + // Callback to allow custom typechecking of builtin function calls whose argument types + // will only be resolved after constraint solving. For example, the arguments to string.format + // have types that can only be decided after parsing the format string and unifying + // with the passed in values, but the correctness of the call can only be decided after + // all the types have been finalized. + DcrMagicFunctionTypeCheck dcrMagicTypeCheck = nullptr; + bool hasSelf; // `hasNoFreeOrGenericTypes` should be true if and only if the type does not have any free or generic types present inside it. // this flag is used as an optimization to exit early from procedures that manipulate free or generic types. diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/TypeChecker2.h b/Dependencies/luau/Luau/Analysis/include/Luau/TypeChecker2.h index 981fdfe6..0faf036d 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/TypeChecker2.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/TypeChecker2.h @@ -2,7 +2,15 @@ #pragma once +#include "Luau/Error.h" #include "Luau/NotNull.h" +#include "Luau/Common.h" +#include "Luau/TypeUtils.h" +#include "Luau/Type.h" +#include "Luau/TypeFwd.h" +#include "Luau/TypeOrPack.h" +#include "Luau/Normalize.h" +#include "Luau/Subtyping.h" namespace Luau { @@ -13,6 +21,42 @@ struct TypeCheckLimits; struct UnifierSharedState; struct SourceModule; struct Module; +struct InternalErrorReporter; +struct Scope; +struct PropertyType; +struct PropertyTypes; +struct StackPusher; + +struct Reasonings +{ + // the list of reasons + std::vector reasons; + + // this should be true if _all_ of the reasons have an error suppressing type, and false otherwise. + bool suppressed; + + std::string toString() + { + // DenseHashSet ordering is entirely undefined, so we want to + // sort the reasons here to achieve a stable error + // stringification. + std::sort(reasons.begin(), reasons.end()); + std::string allReasons; + bool first = true; + for (const std::string& reason : reasons) + { + if (first) + first = false; + else + allReasons += "\n\t"; + + allReasons += reason; + } + + return allReasons; + } +}; + void check( NotNull builtinTypes, @@ -23,4 +67,154 @@ void check( Module* module ); +struct TypeChecker2 +{ + NotNull builtinTypes; + DcrLogger* logger; + const NotNull limits; + const NotNull ice; + const SourceModule* sourceModule; + Module* module; + + TypeContext typeContext = TypeContext::Default; + std::vector> stack; + std::vector functionDeclStack; + + DenseHashSet seenTypeFunctionInstances{nullptr}; + + Normalizer normalizer; + Subtyping _subtyping; + NotNull subtyping; + + TypeChecker2( + NotNull builtinTypes, + NotNull unifierState, + NotNull limits, + DcrLogger* logger, + const SourceModule* sourceModule, + Module* module + ); + + void visit(AstStatBlock* block); + void reportError(TypeErrorData data, const Location& location); + Reasonings explainReasonings(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& r); + Reasonings explainReasonings(TypePackId subTp, TypePackId superTp, Location location, const SubtypingResult& r); + +private: + static bool allowsNoReturnValues(const TypePackId tp); + static Location getEndLocation(const AstExprFunction* function); + bool isErrorCall(const AstExprCall* call); + bool hasBreak(AstStat* node); + const AstStat* getFallthrough(const AstStat* node); + std::optional pushStack(AstNode* node); + void checkForInternalTypeFunction(TypeId ty, Location location); + TypeId checkForTypeFunctionInhabitance(TypeId instance, Location location); + TypePackId lookupPack(AstExpr* expr); + TypeId lookupType(AstExpr* expr); + TypeId lookupAnnotation(AstType* annotation); + std::optional lookupPackAnnotation(AstTypePack* annotation); + TypeId lookupExpectedType(AstExpr* expr); + TypePackId lookupExpectedPack(AstExpr* expr, TypeArena& arena); + TypePackId reconstructPack(AstArray exprs, TypeArena& arena); + Scope* findInnermostScope(Location location); + void visit(AstStat* stat); + void visit(AstStatIf* ifStatement); + void visit(AstStatWhile* whileStatement); + void visit(AstStatRepeat* repeatStatement); + void visit(AstStatBreak*); + void visit(AstStatContinue*); + void visit(AstStatReturn* ret); + void visit(AstStatExpr* expr); + void visit(AstStatLocal* local); + void visit(AstStatFor* forStatement); + void visit(AstStatForIn* forInStatement); + std::optional getBindingType(AstExpr* expr); + void reportErrorsFromAssigningToNever(AstExpr* lhs, TypeId rhsType); + void visit(AstStatAssign* assign); + void visit(AstStatCompoundAssign* stat); + void visit(AstStatFunction* stat); + void visit(AstStatLocalFunction* stat); + void visit(const AstTypeList* typeList); + void visit(AstStatTypeAlias* stat); + void visit(AstStatTypeFunction* stat); + void visit(AstTypeList types); + void visit(AstStatDeclareFunction* stat); + void visit(AstStatDeclareGlobal* stat); + void visit(AstStatDeclareClass* stat); + void visit(AstStatError* stat); + void visit(AstExpr* expr, ValueContext context); + void visit(AstExprGroup* expr, ValueContext context); + void visit(AstExprConstantNil* expr); + void visit(AstExprConstantBool* expr); + void visit(AstExprConstantNumber* expr); + void visit(AstExprConstantString* expr); + void visit(AstExprLocal* expr); + void visit(AstExprGlobal* expr); + void visit(AstExprVarargs* expr); + void visitCall(AstExprCall* call); + void visit(AstExprCall* call); + std::optional tryStripUnionFromNil(TypeId ty); + TypeId stripFromNilAndReport(TypeId ty, const Location& location); + void visitExprName(AstExpr* expr, Location location, const std::string& propName, ValueContext context, TypeId astIndexExprTy); + void visit(AstExprIndexName* indexName, ValueContext context); + void indexExprMetatableHelper(AstExprIndexExpr* indexExpr, const MetatableType* metaTable, TypeId exprType, TypeId indexType); + void visit(AstExprIndexExpr* indexExpr, ValueContext context); + void visit(AstExprFunction* fn); + void visit(AstExprTable* expr); + void visit(AstExprUnary* expr); + TypeId visit(AstExprBinary* expr, AstNode* overrideKey = nullptr); + void visit(AstExprTypeAssertion* expr); + void visit(AstExprIfElse* expr); + void visit(AstExprInterpString* interpString); + void visit(AstExprError* expr); + TypeId flattenPack(TypePackId pack); + void visitGenerics(AstArray generics, AstArray genericPacks); + void visit(AstType* ty); + void visit(AstTypeReference* ty); + void visit(AstTypeTable* table); + void visit(AstTypeFunction* ty); + void visit(AstTypeTypeof* ty); + void visit(AstTypeUnion* ty); + void visit(AstTypeIntersection* ty); + void visit(AstTypePack* pack); + void visit(AstTypePackExplicit* tp); + void visit(AstTypePackVariadic* tp); + void visit(AstTypePackGeneric* tp); + + template + Reasonings explainReasonings_(TID subTy, TID superTy, Location location, const SubtypingResult& r); + + void explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& result); + void explainError(TypePackId subTy, TypePackId superTy, Location location, const SubtypingResult& result); + bool testIsSubtype(TypeId subTy, TypeId superTy, Location location); + bool testIsSubtype(TypePackId subTy, TypePackId superTy, Location location); + void reportError(TypeError e); + void reportErrors(ErrorVec errors); + PropertyTypes lookupProp( + const NormalizedType* norm, + const std::string& prop, + ValueContext context, + const Location& location, + TypeId astIndexExprType, + std::vector& errors + ); + // If the provided type does not have the named property, report an error. + void checkIndexTypeFromType(TypeId tableTy, const std::string& prop, ValueContext context, const Location& location, TypeId astIndexExprType); + PropertyType hasIndexTypeFromType( + TypeId ty, + const std::string& prop, + ValueContext context, + const Location& location, + DenseHashSet& seen, + TypeId astIndexExprType, + std::vector& errors + ); + + void diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& data) const; + bool isErrorSuppressing(Location loc, TypeId ty); + bool isErrorSuppressing(Location loc1, TypeId ty1, Location loc2, TypeId ty2); + bool isErrorSuppressing(Location loc, TypePackId tp); + bool isErrorSuppressing(Location loc1, TypePackId tp1, Location loc2, TypePackId tp2); +}; + } // namespace Luau diff --git a/Dependencies/luau/Luau/Analysis/include/Luau/VisitType.h b/Dependencies/luau/Luau/Analysis/include/Luau/VisitType.h index e588d06b..e943cced 100644 --- a/Dependencies/luau/Luau/Analysis/include/Luau/VisitType.h +++ b/Dependencies/luau/Luau/Analysis/include/Luau/VisitType.h @@ -11,7 +11,7 @@ LUAU_FASTINT(LuauVisitRecursionLimit) LUAU_FASTFLAG(LuauBoundLazyTypes2) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { @@ -226,12 +226,12 @@ struct GenericTypeVisitor } else if (auto ftv = get(ty)) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (visit(ty, *ftv)) { // TODO: Replace these if statements with assert()s when we - // delete FFlag::DebugLuauDeferredConstraintResolution. + // delete FFlag::LuauSolverV2. // // When the old solver is used, these pointers are always // unused. When the new solver is used, they are never null. @@ -276,7 +276,7 @@ struct GenericTypeVisitor { for (auto& [_name, prop] : ttv->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto ty = prop.readTy) traverse(*ty); @@ -314,7 +314,7 @@ struct GenericTypeVisitor { for (const auto& [name, prop] : ctv->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto ty = prop.readTy) traverse(*ty); diff --git a/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp b/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp index 4ff2051b..85f567af 100644 --- a/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp +++ b/Dependencies/luau/Luau/Analysis/src/AnyTypeSummary.cpp @@ -38,7 +38,7 @@ #include -LUAU_FASTFLAGVARIABLE(StudioReportLuauAny, false); +LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2, false); LUAU_FASTINTVARIABLE(LuauAnySummaryRecursionLimit, 300); LUAU_FASTFLAG(DebugLuauMagicTypes); @@ -211,14 +211,17 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module if (!maybeRequire) continue; - if (isAnyCast(scope, local->values.data[posn], module, builtinTypes)) + if (std::min(local->values.size - 1, posn) < head.size()) { - TelemetryTypePair types; + if (isAnyCast(scope, local->values.data[posn], module, builtinTypes)) + { + TelemetryTypePair types; - types.inferredType = toString(head[std::min(local->values.size - 1, posn)]); + types.inferredType = toString(head[std::min(local->values.size - 1, posn)]); - TypeInfo ti{Pattern::Casts, toString(ctxNode), types}; - typeInfo.push_back(ti); + TypeInfo ti{Pattern::Casts, toString(ctxNode), types}; + typeInfo.push_back(ti); + } } } else @@ -292,7 +295,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatAssign* assign, const Modu types.annotatedType = toString(tp); auto loc = std::min(assign->vars.size - 1, posn); - if (head.size() >= assign->vars.size) + if (head.size() >= assign->vars.size && posn < head.size()) { types.inferredType = toString(head[posn]); } @@ -689,7 +692,7 @@ bool AnyTypeSummary::containsAny(TypeId typ) { for (auto& [_name, prop] : ty->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto newT = follow(prop.readTy)) { diff --git a/Dependencies/luau/Luau/Analysis/src/AstQuery.cpp b/Dependencies/luau/Luau/Analysis/src/AstQuery.cpp index 243834f8..c8470373 100644 --- a/Dependencies/luau/Luau/Analysis/src/AstQuery.cpp +++ b/Dependencies/luau/Luau/Analysis/src/AstQuery.cpp @@ -11,8 +11,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); -LUAU_FASTFLAGVARIABLE(LuauFixBindingForGlobalPos, false); +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { @@ -327,7 +326,7 @@ static std::optional findBindingLocalStatement(const SourceModule { // Bindings coming from global sources (e.g., definition files) have a zero position. // They cannot be defined from a local statement - if (FFlag::LuauFixBindingForGlobalPos && binding.location == Location{{0, 0}, {0, 0}}) + if (binding.location == Location{{0, 0}, {0, 0}}) return std::nullopt; std::vector nodes = findAstAncestryOfPosition(source, binding.location.begin); @@ -531,7 +530,7 @@ std::optional getDocumentationSymbolAtPosition(const Source { if (auto propIt = ttv->props.find(indexName->index.value); propIt != ttv->props.end()) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto ty = propIt->second.readTy) return checkOverloadedDocumentationSymbol(module, *ty, parentExpr, propIt->second.documentationSymbol); @@ -544,7 +543,7 @@ std::optional getDocumentationSymbolAtPosition(const Source { if (auto propIt = ctv->props.find(indexName->index.value); propIt != ctv->props.end()) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto ty = propIt->second.readTy) return checkOverloadedDocumentationSymbol(module, *ty, parentExpr, propIt->second.documentationSymbol); diff --git a/Dependencies/luau/Luau/Analysis/src/Autocomplete.cpp b/Dependencies/luau/Luau/Analysis/src/Autocomplete.cpp index a4acfb85..ee865edd 100644 --- a/Dependencies/luau/Luau/Analysis/src/Autocomplete.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Autocomplete.cpp @@ -13,7 +13,7 @@ #include #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); static const std::unordered_set kStatementStartingKeywords = {"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"}; @@ -142,11 +142,11 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull scope, T UnifierSharedState unifierState(&iceReporter); Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { - Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}, scope}; + Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}}; - return subtyping.isSubtype(subTy, superTy).isSubtype; + return subtyping.isSubtype(subTy, superTy, scope).isSubtype; } else { @@ -293,7 +293,7 @@ static void autocompleteProps( { Luau::TypeId type; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (auto ty = prop.readTy) type = follow(*ty); @@ -1964,7 +1964,7 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName return {}; ModulePtr module; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) module = frontend.moduleResolver.getModule(moduleName); else module = frontend.moduleResolverForAutocomplete.getModule(moduleName); @@ -1974,7 +1974,7 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName NotNull builtinTypes = frontend.builtinTypes; Scope* globalScope; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) globalScope = frontend.globals.globalScope.get(); else globalScope = frontend.globalsForAutocomplete.globalScope.get(); diff --git a/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp b/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp index e565f6bf..21ae0f11 100644 --- a/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp +++ b/Dependencies/luau/Luau/Analysis/src/BuiltinDefinitions.cpp @@ -10,10 +10,12 @@ #include "Luau/ConstraintGenerator.h" #include "Luau/NotNull.h" #include "Luau/TypeInfer.h" +#include "Luau/TypeChecker2.h" #include "Luau/TypeFunction.h" #include "Luau/TypePack.h" #include "Luau/Type.h" #include "Luau/TypeUtils.h" +#include "Luau/Subtyping.h" #include @@ -23,7 +25,8 @@ * about a function that takes any number of values, but where each value must have some specific type. */ -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); +LUAU_FASTFLAGVARIABLE(LuauDCRMagicFunctionTypeChecker, false); namespace Luau { @@ -181,6 +184,14 @@ void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn) LUAU_ASSERT(!"Got a non functional type"); } +void attachDcrMagicFunctionTypeCheck(TypeId ty, DcrMagicFunctionTypeCheck fn) +{ + if (auto ftv = getMutable(ty)) + ftv->dcrMagicTypeCheck = fn; + else + LUAU_ASSERT(!"Got a non functional type"); +} + Property makeProperty(TypeId ty, std::optional documentationSymbol) { return { @@ -260,7 +271,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC TypeArena& arena = globals.globalTypes; NotNull builtinTypes = globals.builtinTypes; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) builtinTypeFunctions().addToScope(NotNull{&arena}, NotNull{globals.globalScope.get()}); LoadDefinitionFileResult loadResult = frontend.loadDefinitionFile( @@ -305,7 +316,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC // getmetatable : ({ @metatable MT, {+ +} }) -> MT addGlobalBinding(globals, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { TypeId genericT = arena.addType(GenericType{"T"}); TypeId tMetaMT = arena.addType(MetatableType{genericT, genericMT}); @@ -354,7 +365,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC attachMagicFunction(getGlobalBinding(globals, "assert"), magicFunctionAssert); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // declare function assert(value: T, errorMessage: string?): intersect TypeId genericT = arena.addType(GenericType{"T"}); @@ -374,7 +385,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC if (TableType* ttv = getMutable(getGlobalBinding(globals, "table"))) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114044 - The new solver does not yet support generic tables, // which act, in an odd way, like generics that are constrained to @@ -517,7 +528,7 @@ static bool dcrMagicFunctionFormat(MagicFunctionCallContext context) size_t paramOffset = 1; - // unify the prefix one argument at a time + // unify the prefix one argument at a time - needed if any of the involved types are free for (size_t i = 0; i < expected.size() && i + paramOffset < params.size(); ++i) { context.solver->unify(context.constraint, params[i + paramOffset], expected[i]); @@ -530,12 +541,52 @@ static bool dcrMagicFunctionFormat(MagicFunctionCallContext context) if (numExpectedParams != numActualParams && (!tail || numExpectedParams < numActualParams)) context.solver->reportError(TypeError{context.callSite->location, CountMismatch{numExpectedParams, std::nullopt, numActualParams}}); + // This is invoked at solve time, so we just need to provide a type for the result of :/.format TypePackId resultPack = arena->addTypePack({context.solver->builtinTypes->stringType}); asMutable(context.result)->ty.emplace(resultPack); return true; } +static void dcrMagicFunctionTypeCheckFormat(MagicFunctionTypeCheckContext context) +{ + AstExprConstantString* fmt = nullptr; + if (auto index = context.callSite->func->as(); index && context.callSite->self) + { + if (auto group = index->expr->as()) + fmt = group->expr->as(); + else + fmt = index->expr->as(); + } + + if (!context.callSite->self && context.callSite->args.size > 0) + fmt = context.callSite->args.data[0]->as(); + + if (!fmt) + return; + + std::vector expected = parseFormatString(context.builtinTypes, fmt->value.data, fmt->value.size); + const auto& [params, tail] = flatten(context.arguments); + + size_t paramOffset = 1; + // Compare the expressions passed with the types the function expects to determine whether this function was called with : or . + bool calledWithSelf = expected.size() == context.callSite->args.size; + // unify the prefix one argument at a time + for (size_t i = 0; i < expected.size() && i + paramOffset < params.size(); ++i) + { + TypeId actualTy = params[i + paramOffset]; + TypeId expectedTy = expected[i]; + Location location = context.callSite->args.data[i + (calledWithSelf ? 0 : paramOffset)]->location; + // use subtyping instead here + SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope); + if (!result.isSubtype) + { + Reasonings reasonings = context.typechecker->explainReasonings(actualTy, expectedTy, location, result); + context.typechecker->reportError(TypeMismatch{expectedTy, actualTy, reasonings.toString()}, location); + } + } +} + static std::vector parsePatternString(NotNull builtinTypes, const char* data, size_t size) { std::vector result; @@ -869,7 +920,7 @@ TypeId makeStringMetatable(NotNull builtinTypes) const TypePackId oneStringPack = arena->addTypePack({stringType}); const TypePackId anyTypePack = builtinTypes->anyTypePack; - const TypePackId variadicTailPack = FFlag::DebugLuauDeferredConstraintResolution ? builtinTypes->unknownTypePack : anyTypePack; + const TypePackId variadicTailPack = FFlag::LuauSolverV2 ? builtinTypes->unknownTypePack : anyTypePack; const TypePackId emptyPack = arena->addTypePack({}); const TypePackId stringVariadicList = arena->addTypePack(TypePackVar{VariadicTypePack{stringType}}); const TypePackId numberVariadicList = arena->addTypePack(TypePackVar{VariadicTypePack{numberType}}); @@ -880,6 +931,8 @@ TypeId makeStringMetatable(NotNull builtinTypes) formatFTV.isCheckedFunction = true; const TypeId formatFn = arena->addType(formatFTV); attachDcrMagicFunction(formatFn, dcrMagicFunctionFormat); + if (FFlag::LuauDCRMagicFunctionTypeChecker) + attachDcrMagicFunctionTypeCheck(formatFn, dcrMagicFunctionTypeCheckFormat); const TypeId stringToStringType = makeFunction(*arena, std::nullopt, {}, {}, {stringType}, {}, {stringType}, /* checked */ true); diff --git a/Dependencies/luau/Luau/Analysis/src/Clone.cpp b/Dependencies/luau/Luau/Analysis/src/Clone.cpp index 7446846a..4af3e7f8 100644 --- a/Dependencies/luau/Luau/Analysis/src/Clone.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Clone.cpp @@ -6,7 +6,7 @@ #include "Luau/TypePack.h" #include "Luau/Unifiable.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) // For each `Luau::clone` call, we will clone only up to N amount of types _and_ packs, as controlled by this limit. LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000) @@ -191,7 +191,7 @@ class TypeCloner Property shallowClone(const Property& p) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { std::optional cloneReadTy; if (auto ty = p.readTy) diff --git a/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp b/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp index ba2d1beb..face6825 100644 --- a/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ConstraintGenerator.cpp @@ -1793,7 +1793,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall* std::vector> expectedTypesForCall = getExpectedCallTypesForFunctionOverloads(fnType); - module->astOriginalCallTypes[call] = fnType; + module->astOriginalCallTypes[call->func] = fnType; Checkpoint argBeginCheckpoint = checkpoint(this); diff --git a/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp b/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp index 73c2193c..9c42e4d8 100644 --- a/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp +++ b/Dependencies/luau/Luau/Analysis/src/DataFlowGraph.cpp @@ -10,7 +10,7 @@ #include LUAU_FASTFLAG(DebugLuauFreezeArena) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { @@ -139,7 +139,7 @@ DataFlowGraph DataFlowGraphBuilder::build(AstStatBlock* block, NotNull result = getCheckResult(name, true, frontendOptions.forAutocomplete)) @@ -511,7 +512,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optionallintResult; - if (FFlag::StudioReportLuauAny && item.options.retainFullTypeGraphs) + if (FFlag::StudioReportLuauAny2 && item.options.retainFullTypeGraphs) { if (item.module) { @@ -546,7 +547,7 @@ std::vector Frontend::checkQueuedModules( ) { FrontendOptions frontendOptions = optionOverride.value_or(options); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) frontendOptions.forAutocomplete = false; // By taking data into locals, we make sure queue is cleared at the end, even if an ICE or a different exception is thrown @@ -780,7 +781,7 @@ std::vector Frontend::checkQueuedModules( std::optional Frontend::getCheckResult(const ModuleName& name, bool accumulateNested, bool forAutocomplete) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) forAutocomplete = false; auto it = sourceNodes.find(name); @@ -1040,6 +1041,9 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item) item.stats.timeCheck += duration; item.stats.filesStrict += 1; + if (DFFlag::LuauRunCustomModuleChecks && item.options.customModuleCheck) + item.options.customModuleCheck(sourceModule, *moduleForAutocomplete); + item.module = moduleForAutocomplete; return; } @@ -1057,10 +1061,10 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item) item.stats.filesStrict += mode == Mode::Strict; item.stats.filesNonstrict += mode == Mode::Nonstrict; - if (module == nullptr) - throw InternalCompilerError("Frontend::check produced a nullptr module for " + item.name, item.name); + if (DFFlag::LuauRunCustomModuleChecks && item.options.customModuleCheck) + item.options.customModuleCheck(sourceModule, *module); - if (FFlag::DebugLuauDeferredConstraintResolution && mode == Mode::NoCheck) + if (FFlag::LuauSolverV2 && mode == Mode::NoCheck) module->errors.clear(); if (item.options.runLintChecks) @@ -1527,7 +1531,7 @@ ModulePtr Frontend::check( TypeCheckLimits typeCheckLimits ) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { auto prepareModuleScopeWrap = [this, forAutocomplete](const ModuleName& name, const ScopePtr& scope) { diff --git a/Dependencies/luau/Luau/Analysis/src/Generalization.cpp b/Dependencies/luau/Luau/Analysis/src/Generalization.cpp index ea736642..d209cb81 100644 --- a/Dependencies/luau/Luau/Analysis/src/Generalization.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Generalization.cpp @@ -887,9 +887,6 @@ std::optional generalize( if (ty->owningArena != arena || ty->persistent) return ty; - if (const FunctionType* ft = get(ty); ft && (!ft->generics.empty() || !ft->genericPacks.empty())) - return ty; - FreeTypeSearcher fts{scope, cachedTypes}; fts.traverse(ty); @@ -912,8 +909,17 @@ std::optional generalize( FunctionType* ftv = getMutable(ty); if (ftv) { - ftv->generics = std::move(gen.generics); - ftv->genericPacks = std::move(gen.genericPacks); + // If we're generalizing a function type, add any of the newly inferred + // generics to the list of existing generic types. + for (const auto g : std::move(gen.generics)) + { + ftv->generics.push_back(g); + } + // Ditto for generic packs. + for (const auto gp : std::move(gen.genericPacks)) + { + ftv->genericPacks.push_back(gp); + } } return ty; diff --git a/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp b/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp index 0c610aba..4b6d1115 100644 --- a/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Instantiation.cpp @@ -10,7 +10,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { @@ -157,7 +157,7 @@ TypeId ReplaceGenerics::clean(TypeId ty) clone.definitionLocation = ttv->definitionLocation; return addType(std::move(clone)); } - else if (FFlag::DebugLuauDeferredConstraintResolution) + else if (FFlag::LuauSolverV2) { TypeId res = freshType(NotNull{arena}, builtinTypes, scope); getMutable(res)->level = level; diff --git a/Dependencies/luau/Luau/Analysis/src/Linter.cpp b/Dependencies/luau/Luau/Analysis/src/Linter.cpp index 23457f4c..c4f46c84 100644 --- a/Dependencies/luau/Luau/Analysis/src/Linter.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Linter.cpp @@ -14,7 +14,7 @@ LUAU_FASTINTVARIABLE(LuauSuggestionDistance, 4) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauAttribute) LUAU_FASTFLAG(LuauNativeAttribute) @@ -1971,7 +1971,7 @@ class LintTableLiteral : AstVisitor bool visit(AstTypeTable* node) override { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { struct Rec { diff --git a/Dependencies/luau/Luau/Analysis/src/Module.cpp b/Dependencies/luau/Luau/Analysis/src/Module.cpp index f9a3f67a..3a049216 100644 --- a/Dependencies/luau/Luau/Analysis/src/Module.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Module.cpp @@ -14,8 +14,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); -LUAU_FASTFLAGVARIABLE(LuauSkipEmptyInstantiations, false); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { @@ -122,7 +121,7 @@ struct ClonePublicInterface : Substitution if (FunctionType* ftv = getMutable(result)) { - if (FFlag::LuauSkipEmptyInstantiations && ftv->generics.empty() && ftv->genericPacks.empty()) + if (ftv->generics.empty() && ftv->genericPacks.empty()) { GenericTypeFinder marker; marker.traverse(result); @@ -220,7 +219,7 @@ void Module::clonePublicInterface(NotNull builtinTypes, InternalEr ScopePtr moduleScope = getModuleScope(); TypePackId returnType = moduleScope->returnType; - std::optional varargPack = FFlag::DebugLuauDeferredConstraintResolution ? std::nullopt : moduleScope->varargPack; + std::optional varargPack = FFlag::LuauSolverV2 ? std::nullopt : moduleScope->varargPack; TxnLog log; ClonePublicInterface clonePublicInterface{&log, builtinTypes, this}; diff --git a/Dependencies/luau/Luau/Analysis/src/NonStrictTypeChecker.cpp b/Dependencies/luau/Luau/Analysis/src/NonStrictTypeChecker.cpp index 16225e96..116cf5cb 100644 --- a/Dependencies/luau/Luau/Analysis/src/NonStrictTypeChecker.cpp +++ b/Dependencies/luau/Luau/Analysis/src/NonStrictTypeChecker.cpp @@ -182,7 +182,7 @@ struct NonStrictTypeChecker , arena(arena) , module(module) , normalizer{arena, builtinTypes, unifierState, /* cache inhabitance */ true} - , subtyping{builtinTypes, arena, NotNull(&normalizer), ice, NotNull{module->getModuleScope().get()}} + , subtyping{builtinTypes, arena, NotNull(&normalizer), ice} , dfg(dfg) , limits(limits) { @@ -531,7 +531,7 @@ struct NonStrictTypeChecker NonStrictContext visit(AstExprCall* call) { NonStrictContext fresh{}; - TypeId* originalCallTy = module->astOriginalCallTypes.find(call); + TypeId* originalCallTy = module->astOriginalCallTypes.find(call->func); if (!originalCallTy) return fresh; @@ -699,6 +699,7 @@ struct NonStrictTypeChecker // If this fragment of the ast will run time error, return the type that causes this std::optional willRunTimeError(AstExpr* fragment, const NonStrictContext& context) { + NotNull scope{Luau::findScopeAtPosition(*module, fragment->location.end).get()}; DefId def = dfg->getDef(fragment); std::vector defs; collectOperands(def, &defs); @@ -708,7 +709,7 @@ struct NonStrictTypeChecker { TypeId actualType = lookupType(fragment); - SubtypingResult r = subtyping.isSubtype(actualType, *contextTy); + SubtypingResult r = subtyping.isSubtype(actualType, *contextTy, scope); if (r.normalizationTooComplex) reportError(NormalizationTooComplex{}, fragment->location); if (r.isSubtype) @@ -721,6 +722,7 @@ struct NonStrictTypeChecker std::optional willRunTimeErrorFunctionDefinition(AstLocal* fragment, const NonStrictContext& context) { + NotNull scope{Luau::findScopeAtPosition(*module, fragment->location.end).get()}; DefId def = dfg->getDef(fragment); std::vector defs; collectOperands(def, &defs); @@ -728,8 +730,8 @@ struct NonStrictTypeChecker { if (std::optional contextTy = context.find(def)) { - SubtypingResult r1 = subtyping.isSubtype(builtinTypes->unknownType, *contextTy); - SubtypingResult r2 = subtyping.isSubtype(*contextTy, builtinTypes->unknownType); + SubtypingResult r1 = subtyping.isSubtype(builtinTypes->unknownType, *contextTy, scope); + SubtypingResult r2 = subtyping.isSubtype(*contextTy, builtinTypes->unknownType, scope); if (r1.normalizationTooComplex || r2.normalizationTooComplex) reportError(NormalizationTooComplex{}, fragment->location); bool isUnknown = r1.isSubtype && r2.isSubtype; @@ -747,7 +749,7 @@ struct NonStrictTypeChecker if (!cachedResult) cachedResult = arena->addType(NegationType{baseType}); return cachedResult; - }; + } }; void checkNonStrict( diff --git a/Dependencies/luau/Luau/Analysis/src/Normalize.cpp b/Dependencies/luau/Luau/Analysis/src/Normalize.cpp index 8935a476..2db2f40c 100644 --- a/Dependencies/luau/Luau/Analysis/src/Normalize.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Normalize.cpp @@ -24,16 +24,16 @@ LUAU_FASTFLAGVARIABLE(LuauFixCyclicTablesBlowingStack, false); // This could theoretically be 2000 on amd64, but x86 requires this. LUAU_FASTINTVARIABLE(LuauNormalizeIterationLimit, 1200); LUAU_FASTINTVARIABLE(LuauNormalizeCacheLimit, 100000); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); static bool fixReduceStackPressure() { - return FFlag::LuauFixReduceStackPressure || FFlag::DebugLuauDeferredConstraintResolution; + return FFlag::LuauFixReduceStackPressure || FFlag::LuauSolverV2; } static bool fixCyclicTablesBlowingStack() { - return FFlag::LuauFixCyclicTablesBlowingStack || FFlag::DebugLuauDeferredConstraintResolution; + return FFlag::LuauFixCyclicTablesBlowingStack || FFlag::LuauSolverV2; } namespace Luau @@ -42,7 +42,7 @@ namespace Luau // helper to make `FFlag::LuauNormalizeAwayUninhabitableTables` not explicitly required when DCR is enabled. static bool normalizeAwayUninhabitableTables() { - return FFlag::LuauNormalizeAwayUninhabitableTables || FFlag::DebugLuauDeferredConstraintResolution; + return FFlag::LuauNormalizeAwayUninhabitableTables || FFlag::LuauSolverV2; } static bool shouldEarlyExit(NormalizationResult res) @@ -553,7 +553,7 @@ NormalizationResult Normalizer::isInhabited(TypeId ty, Set& seen) { for (const auto& [_, prop] : ttv->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // A table enclosing a read property whose type is uninhabitable is also itself uninhabitable, // but not its write property. That just means the write property doesn't exist, and so is readonly. @@ -2583,7 +2583,7 @@ std::optional Normalizer::intersectionOfTables(TypeId here, TypeId there { const auto& [_name, tprop] = *tfound; // TODO: variance issues here, which can't be fixed until we have read/write property types - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (hprop.readTy.has_value()) { @@ -3249,7 +3249,7 @@ NormalizationResult Normalizer::intersectNormalWithTy(NormalizedType& here, Type // this is a noop since an intersection with `unknown` is trivial. return NormalizationResult::True; } - else if ((FFlag::LuauNormalizeNotUnknownIntersection || FFlag::DebugLuauDeferredConstraintResolution) && get(t)) + else if ((FFlag::LuauNormalizeNotUnknownIntersection || FFlag::LuauSolverV2) && get(t)) { // if we're intersecting with `~unknown`, this is equivalent to intersecting with `never` // this means we should clear the type entirely. @@ -3389,7 +3389,7 @@ TypeId Normalizer::typeFromNormal(const NormalizedType& norm) if (!get(norm.buffers)) result.push_back(builtinTypes->bufferType); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { result.reserve(result.size() + norm.tables.size()); for (auto table : norm.tables) @@ -3427,11 +3427,11 @@ bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull scope, N Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; // Subtyping under DCR is not implemented using unification! - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { - Subtyping subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&ice}, scope}; + Subtyping subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&ice}}; - return subtyping.isSubtype(subPack, superPack).isSubtype; + return subtyping.isSubtype(subPack, superPack, scope).isSubtype; } else { @@ -3466,7 +3466,7 @@ bool isSubtype(TypePackId subPack, TypePackId superPack, NotNull scope, N bool isConsistentSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull builtinTypes, InternalErrorReporter& ice) { - LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(!FFlag::LuauSolverV2); UnifierSharedState sharedState{&ice}; TypeArena arena; @@ -3486,7 +3486,7 @@ bool isConsistentSubtype( InternalErrorReporter& ice ) { - LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(!FFlag::LuauSolverV2); UnifierSharedState sharedState{&ice}; TypeArena arena; diff --git a/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp b/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp index 612f4ad2..972c9e3a 100644 --- a/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp +++ b/Dependencies/luau/Luau/Analysis/src/OverloadResolution.cpp @@ -28,7 +28,7 @@ OverloadResolver::OverloadResolver( , scope(scope) , ice(reporter) , limits(limits) - , subtyping({builtinTypes, arena, normalizer, ice, scope}) + , subtyping({builtinTypes, arena, normalizer, ice}) , callLoc(callLocation) { } @@ -41,7 +41,7 @@ std::pair OverloadResolver::selectOverload(T { Subtyping::Variance variance = subtyping.variance; subtyping.variance = Subtyping::Variance::Contravariant; - SubtypingResult r = subtyping.isSubtype(argsPack, ftv->argTypes); + SubtypingResult r = subtyping.isSubtype(argsPack, ftv->argTypes, scope); subtyping.variance = variance; if (r.isSubtype) @@ -92,7 +92,7 @@ void OverloadResolver::resolve(TypeId fnTy, const TypePack* args, AstExpr* selfE std::optional OverloadResolver::testIsSubtype(const Location& location, TypeId subTy, TypeId superTy) { - auto r = subtyping.isSubtype(subTy, superTy); + auto r = subtyping.isSubtype(subTy, superTy, scope); ErrorVec errors; if (r.normalizationTooComplex) @@ -107,6 +107,7 @@ std::optional OverloadResolver::testIsSubtype(const Location& location case ErrorSuppression::NormalizationFailed: errors.emplace_back(location, NormalizationTooComplex{}); // intentionally fallthrough here since we couldn't prove this was error-suppressing + [[fallthrough]]; case ErrorSuppression::DoNotSuppress: errors.emplace_back(location, TypeMismatch{superTy, subTy}); break; @@ -121,7 +122,7 @@ std::optional OverloadResolver::testIsSubtype(const Location& location std::optional OverloadResolver::testIsSubtype(const Location& location, TypePackId subTy, TypePackId superTy) { - auto r = subtyping.isSubtype(subTy, superTy); + auto r = subtyping.isSubtype(subTy, superTy, scope); ErrorVec errors; if (r.normalizationTooComplex) @@ -136,6 +137,7 @@ std::optional OverloadResolver::testIsSubtype(const Location& location case ErrorSuppression::NormalizationFailed: errors.emplace_back(location, NormalizationTooComplex{}); // intentionally fallthrough here since we couldn't prove this was error-suppressing + [[fallthrough]]; case ErrorSuppression::DoNotSuppress: errors.emplace_back(location, TypePackMismatch{superTy, subTy}); break; @@ -206,7 +208,7 @@ std::pair OverloadResolver::checkOverload_ TypePackId typ = arena->addTypePack(*args); TypeId prospectiveFunction = arena->addType(FunctionType{typ, builtinTypes->anyTypePack}); - SubtypingResult sr = subtyping.isSubtype(fnTy, prospectiveFunction); + SubtypingResult sr = subtyping.isSubtype(fnTy, prospectiveFunction, scope); if (sr.isSubtype) return {Analysis::Ok, {}}; @@ -250,7 +252,7 @@ std::pair OverloadResolver::checkOverload_ // nil, then this overload does not match. for (size_t i = firstUnsatisfiedArgument; i < requiredHead.size(); ++i) { - if (!subtyping.isSubtype(builtinTypes->nilType, requiredHead[i]).isSubtype) + if (!subtyping.isSubtype(builtinTypes->nilType, requiredHead[i], scope).isSubtype) { auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes); TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}}; @@ -301,6 +303,7 @@ std::pair OverloadResolver::checkOverload_ case ErrorSuppression::NormalizationFailed: errors.emplace_back(argLocation, NormalizationTooComplex{}); // intentionally fallthrough here since we couldn't prove this was error-suppressing + [[fallthrough]]; case ErrorSuppression::DoNotSuppress: // TODO extract location from the SubtypingResult path and argExprs switch (reason.variance) diff --git a/Dependencies/luau/Luau/Analysis/src/Scope.cpp b/Dependencies/luau/Luau/Analysis/src/Scope.cpp index 791167c8..27894505 100644 --- a/Dependencies/luau/Luau/Analysis/src/Scope.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Scope.cpp @@ -2,7 +2,7 @@ #include "Luau/Scope.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { @@ -184,7 +184,7 @@ std::optional Scope::linearSearchForBinding(const std::string& name, bo // Updates the `this` scope with the assignments from the `childScope` including ones that doesn't exist in `this`. void Scope::inheritAssignments(const ScopePtr& childScope) { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; for (const auto& [k, a] : childScope->lvalueTypes) @@ -194,7 +194,7 @@ void Scope::inheritAssignments(const ScopePtr& childScope) // Updates the `this` scope with the refinements from the `childScope` excluding ones that doesn't exist in `this`. void Scope::inheritRefinements(const ScopePtr& childScope) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { for (const auto& [k, a] : childScope->rvalueRefinements) { diff --git a/Dependencies/luau/Luau/Analysis/src/Simplify.cpp b/Dependencies/luau/Luau/Analysis/src/Simplify.cpp index ca9d5898..099e6a0d 100644 --- a/Dependencies/luau/Luau/Analysis/src/Simplify.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Simplify.cpp @@ -12,7 +12,7 @@ #include LUAU_FASTINT(LuauTypeReductionRecursionLimit) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_DYNAMIC_FASTINTVARIABLE(LuauSimplificationComplexityLimit, 8); namespace Luau @@ -141,6 +141,7 @@ Relation combine(Relation a, Relation b) case Relation::Superset: return Relation::Intersects; } + break; case Relation::Coincident: switch (b) { @@ -155,6 +156,7 @@ Relation combine(Relation a, Relation b) case Relation::Superset: return Relation::Intersects; } + break; case Relation::Superset: switch (b) { @@ -169,6 +171,7 @@ Relation combine(Relation a, Relation b) case Relation::Superset: return Relation::Superset; } + break; case Relation::Subset: switch (b) { @@ -183,6 +186,7 @@ Relation combine(Relation a, Relation b) case Relation::Superset: return Relation::Intersects; } + break; case Relation::Intersects: switch (b) { @@ -197,6 +201,7 @@ Relation combine(Relation a, Relation b) case Relation::Superset: return Relation::Intersects; } + break; } LUAU_UNREACHABLE(); @@ -1398,7 +1403,7 @@ TypeId TypeSimplifier::simplify(TypeId ty, DenseHashSet& seen) SimplifyResult simplifyIntersection(NotNull builtinTypes, NotNull arena, TypeId left, TypeId right) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); TypeSimplifier s{builtinTypes, arena}; @@ -1413,7 +1418,7 @@ SimplifyResult simplifyIntersection(NotNull builtinTypes, NotNull< SimplifyResult simplifyIntersection(NotNull builtinTypes, NotNull arena, std::set parts) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); TypeSimplifier s{builtinTypes, arena}; @@ -1424,7 +1429,7 @@ SimplifyResult simplifyIntersection(NotNull builtinTypes, NotNull< SimplifyResult simplifyUnion(NotNull builtinTypes, NotNull arena, TypeId left, TypeId right) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); TypeSimplifier s{builtinTypes, arena}; diff --git a/Dependencies/luau/Luau/Analysis/src/Substitution.cpp b/Dependencies/luau/Luau/Analysis/src/Substitution.cpp index 3eeb2095..526d8212 100644 --- a/Dependencies/luau/Luau/Analysis/src/Substitution.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Substitution.cpp @@ -9,7 +9,7 @@ #include LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256); namespace Luau @@ -182,7 +182,7 @@ void Tarjan::visitChildren(TypeId ty, int index) LUAU_ASSERT(!ttv->boundTo); for (const auto& [name, prop] : ttv->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { visitChild(prop.readTy); visitChild(prop.writeTy); @@ -740,7 +740,7 @@ void Substitution::replaceChildren(TypeId ty) LUAU_ASSERT(!ttv->boundTo); for (auto& [name, prop] : ttv->props) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (prop.readTy) prop.readTy = replace(prop.readTy); diff --git a/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp b/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp index 4bbe2ecd..ee199b66 100644 --- a/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Subtyping.cpp @@ -333,28 +333,25 @@ Subtyping::Subtyping( NotNull builtinTypes, NotNull typeArena, NotNull normalizer, - NotNull iceReporter, - NotNull scope + NotNull iceReporter ) : builtinTypes(builtinTypes) , arena(typeArena) , normalizer(normalizer) , iceReporter(iceReporter) - , scope(scope) { } -SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy) +SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy, NotNull scope) { SubtypingEnvironment env; - SubtypingResult result = isCovariantWith(env, subTy, superTy); + SubtypingResult result = isCovariantWith(env, subTy, superTy, scope); for (const auto& [subTy, bounds] : env.mappedGenerics) { const auto& lb = bounds.lowerBound; const auto& ub = bounds.upperBound; - TypeId lowerBound = makeAggregateType(lb, builtinTypes->neverType); TypeId upperBound = makeAggregateType(ub, builtinTypes->unknownType); @@ -382,7 +379,7 @@ SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy) result.isSubtype = false; } - SubtypingResult boundsResult = isCovariantWith(env, lowerBound, upperBound); + SubtypingResult boundsResult = isCovariantWith(env, lowerBound, upperBound, scope); boundsResult.reasoning.clear(); result.andAlso(boundsResult); @@ -406,10 +403,10 @@ SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy) return result; } -SubtypingResult Subtyping::isSubtype(TypePackId subTp, TypePackId superTp) +SubtypingResult Subtyping::isSubtype(TypePackId subTp, TypePackId superTp, NotNull scope) { SubtypingEnvironment env; - return isCovariantWith(env, subTp, superTp); + return isCovariantWith(env, subTp, superTp, scope); } SubtypingResult Subtyping::cache(SubtypingEnvironment& env, SubtypingResult result, TypeId subTy, TypeId superTy) @@ -443,7 +440,7 @@ struct SeenSetPopper }; } // namespace -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy, NotNull scope) { subTy = follow(subTy); superTy = follow(superTy); @@ -501,20 +498,20 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub // tested as though it were its upper bounds. We do not yet support bounded // generics, so the upper bound is always unknown. if (auto subGeneric = get(subTy); subGeneric && subsumes(subGeneric->scope, scope)) - return isCovariantWith(env, builtinTypes->neverType, superTy); + return isCovariantWith(env, builtinTypes->neverType, superTy, scope); if (auto superGeneric = get(superTy); superGeneric && subsumes(superGeneric->scope, scope)) - return isCovariantWith(env, subTy, builtinTypes->unknownType); + return isCovariantWith(env, subTy, builtinTypes->unknownType, scope); SubtypingResult result; if (auto subUnion = get(subTy)) - result = isCovariantWith(env, subUnion, superTy); + result = isCovariantWith(env, subUnion, superTy, scope); else if (auto superUnion = get(superTy)) { - result = isCovariantWith(env, subTy, superUnion); + result = isCovariantWith(env, subTy, superUnion, scope); if (!result.isSubtype && !result.normalizationTooComplex) { - SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy)); + SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope); if (semantic.isSubtype) { semantic.reasoning.clear(); @@ -523,13 +520,13 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub } } else if (auto superIntersection = get(superTy)) - result = isCovariantWith(env, subTy, superIntersection); + result = isCovariantWith(env, subTy, superIntersection, scope); else if (auto subIntersection = get(subTy)) { - result = isCovariantWith(env, subIntersection, superTy); + result = isCovariantWith(env, subIntersection, superTy, scope); if (!result.isSubtype && !result.normalizationTooComplex) { - SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy)); + SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope); if (semantic.isSubtype) { // Clear the semantic reasoning, as any reasonings within @@ -550,7 +547,8 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub { // any = unknown | error, so we rewrite this to match. // As per TAPL: A | B <: T iff A <: T && B <: T - result = isCovariantWith(env, builtinTypes->unknownType, superTy).andAlso(isCovariantWith(env, builtinTypes->errorType, superTy)); + result = + isCovariantWith(env, builtinTypes->unknownType, superTy, scope).andAlso(isCovariantWith(env, builtinTypes->errorType, superTy, scope)); } else if (get(superTy)) { @@ -566,15 +564,15 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub else if (get(superTy)) result = {false}; else if (get(subTy)) - result = {false}; + result = {true}; else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p.first->ty, p.second->ty).withBothComponent(TypePath::TypeField::Negated); + result = isCovariantWith(env, p.first->ty, p.second->ty, scope).withBothComponent(TypePath::TypeField::Negated); else if (auto subNegation = get(subTy)) { - result = isCovariantWith(env, subNegation, superTy); + result = isCovariantWith(env, subNegation, superTy, scope); if (!result.isSubtype && !result.normalizationTooComplex) { - SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy)); + SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope); if (semantic.isSubtype) { semantic.reasoning.clear(); @@ -584,10 +582,10 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub } else if (auto superNegation = get(superTy)) { - result = isCovariantWith(env, subTy, superNegation); + result = isCovariantWith(env, subTy, superNegation, scope); if (!result.isSubtype && !result.normalizationTooComplex) { - SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy)); + SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope); if (semantic.isSubtype) { semantic.reasoning.clear(); @@ -600,14 +598,14 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub if (auto substSubTy = env.applyMappedGenerics(builtinTypes, arena, subTy)) subTypeFunctionInstance = get(*substSubTy); - result = isCovariantWith(env, subTypeFunctionInstance, superTy); + result = isCovariantWith(env, subTypeFunctionInstance, superTy, scope); } else if (auto superTypeFunctionInstance = get(superTy)) { if (auto substSuperTy = env.applyMappedGenerics(builtinTypes, arena, superTy)) superTypeFunctionInstance = get(*substSuperTy); - result = isCovariantWith(env, subTy, superTypeFunctionInstance); + result = isCovariantWith(env, subTy, superTypeFunctionInstance, scope); } else if (auto subGeneric = get(subTy); subGeneric && variance == Variance::Covariant) { @@ -622,41 +620,41 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub result.isCacheable = false; } else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) { auto [subFunction, superPrimitive] = p; result.isSubtype = superPrimitive->type == PrimitiveType::Function; } else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, subTy, p.first, superTy, p.second); + result = isCovariantWith(env, subTy, p.first, superTy, p.second, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); else if (auto p = get2(subTy, superTy)) - result = isCovariantWith(env, p); + result = isCovariantWith(env, p, scope); assertReasoningValid(subTy, superTy, result, builtinTypes); return cache(env, result, subTy, superTy); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp, NotNull scope) { subTp = follow(subTp); superTp = follow(superTp); @@ -675,7 +673,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId // Match head types pairwise for (size_t i = 0; i < headSize; ++i) - results.push_back(isCovariantWith(env, subHead[i], superHead[i]).withBothComponent(TypePath::Index{i})); + results.push_back(isCovariantWith(env, subHead[i], superHead[i], scope).withBothComponent(TypePath::Index{i})); // Handle mismatched head sizes @@ -686,7 +684,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId if (auto vt = get(*subTail)) { for (size_t i = headSize; i < superHead.size(); ++i) - results.push_back(isCovariantWith(env, vt->ty, superHead[i]) + results.push_back(isCovariantWith(env, vt->ty, superHead[i], scope) .withSubPath(TypePath::PathBuilder().tail().variadic().build()) .withSuperComponent(TypePath::Index{i})); } @@ -704,7 +702,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId if (TypePackId* other = env.mappedGenericPacks.find(*subTail)) // TODO: TypePath can't express "slice of a pack + its tail". - results.push_back(isCovariantWith(env, *other, superTailPack).withSubComponent(TypePath::PackField::Tail)); + results.push_back(isCovariantWith(env, *other, superTailPack, scope).withSubComponent(TypePath::PackField::Tail)); else env.mappedGenericPacks.try_insert(*subTail, superTailPack); @@ -741,7 +739,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId if (auto vt = get(*superTail)) { for (size_t i = headSize; i < subHead.size(); ++i) - results.push_back(isCovariantWith(env, subHead[i], vt->ty) + results.push_back(isCovariantWith(env, subHead[i], vt->ty, scope) .withSubComponent(TypePath::Index{i}) .withSuperPath(TypePath::PathBuilder().tail().variadic().build())); } @@ -759,7 +757,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId if (TypePackId* other = env.mappedGenericPacks.find(*superTail)) // TODO: TypePath can't express "slice of a pack + its tail". - results.push_back(isContravariantWith(env, subTailPack, *other).withSuperComponent(TypePath::PackField::Tail)); + results.push_back(isContravariantWith(env, subTailPack, *other, scope).withSuperComponent(TypePath::PackField::Tail)); else env.mappedGenericPacks.try_insert(*superTail, subTailPack); @@ -794,7 +792,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId { // Variadic component is added by the isCovariantWith // implementation; no need to add it here. - results.push_back(isCovariantWith(env, p).withBothComponent(TypePath::PackField::Tail)); + results.push_back(isCovariantWith(env, p, scope).withBothComponent(TypePath::PackField::Tail)); } else if (auto p = get2(*subTail, *superTail)) { @@ -899,11 +897,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId } template -SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy) +SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull scope) { VarianceFlipper vf{&variance}; - SubtypingResult result = isCovariantWith(env, superTy, subTy); + SubtypingResult result = isCovariantWith(env, superTy, subTy, scope); if (result.reasoning.empty()) result.reasoning.insert(SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Contravariant}); else @@ -931,9 +929,9 @@ SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, SubTy& } template -SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy) +SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull scope) { - SubtypingResult result = isCovariantWith(env, subTy, superTy).andAlso(isContravariantWith(env, subTy, superTy)); + SubtypingResult result = isCovariantWith(env, subTy, superTy, scope).andAlso(isContravariantWith(env, subTy, superTy, scope)); if (result.reasoning.empty()) result.reasoning.insert(SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Invariant}); @@ -948,19 +946,19 @@ SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, SubTy&& su } template -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TryPair& pair) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull scope) { - return isCovariantWith(env, pair.first, pair.second); + return isCovariantWith(env, pair.first, pair.second, scope); } template -SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, const TryPair& pair) +SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull scope) { - return isContravariantWith(env, pair.first, pair.second); + return isContravariantWith(env, pair.first, pair.second, scope); } template -SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, const TryPair& pair) +SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, const TryPair& pair, NotNull scope) { return isInvariantWith(env, pair.first, pair.second); } @@ -996,13 +994,13 @@ SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, const TryP * other just asks for boolean ~ 'b. We can dispatch this and only commit * boolean ~ 'b. This constraint does not teach us anything about 'a. */ -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion, NotNull scope) { // As per TAPL: T <: A | B iff T <: A || T <: B for (TypeId ty : superUnion) { - SubtypingResult next = isCovariantWith(env, subTy, ty); + SubtypingResult next = isCovariantWith(env, subTy, ty, scope); if (next.isSubtype) return SubtypingResult{true}; } @@ -1015,37 +1013,37 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub return SubtypingResult{false}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy, NotNull scope) { // As per TAPL: A | B <: T iff A <: T && B <: T std::vector subtypings; size_t i = 0; for (TypeId ty : subUnion) - subtypings.push_back(isCovariantWith(env, ty, superTy).withSubComponent(TypePath::Index{i++})); + subtypings.push_back(isCovariantWith(env, ty, superTy, scope).withSubComponent(TypePath::Index{i++})); return SubtypingResult::all(subtypings); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection, NotNull scope) { // As per TAPL: T <: A & B iff T <: A && T <: B std::vector subtypings; size_t i = 0; for (TypeId ty : superIntersection) - subtypings.push_back(isCovariantWith(env, subTy, ty).withSuperComponent(TypePath::Index{i++})); + subtypings.push_back(isCovariantWith(env, subTy, ty, scope).withSuperComponent(TypePath::Index{i++})); return SubtypingResult::all(subtypings); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy, NotNull scope) { // As per TAPL: A & B <: T iff A <: T || B <: T std::vector subtypings; size_t i = 0; for (TypeId ty : subIntersection) - subtypings.push_back(isCovariantWith(env, ty, superTy).withSubComponent(TypePath::Index{i++})); + subtypings.push_back(isCovariantWith(env, ty, superTy, scope).withSubComponent(TypePath::Index{i++})); return SubtypingResult::any(subtypings); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy, NotNull scope) { TypeId negatedTy = follow(subNegation->ty); @@ -1057,17 +1055,17 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Nega if (is(negatedTy)) { // ¬never ~ unknown - result = isCovariantWith(env, builtinTypes->unknownType, superTy).withSubComponent(TypePath::TypeField::Negated); + result = isCovariantWith(env, builtinTypes->unknownType, superTy, scope).withSubComponent(TypePath::TypeField::Negated); } else if (is(negatedTy)) { // ¬unknown ~ never - result = isCovariantWith(env, builtinTypes->neverType, superTy).withSubComponent(TypePath::TypeField::Negated); + result = isCovariantWith(env, builtinTypes->neverType, superTy, scope).withSubComponent(TypePath::TypeField::Negated); } else if (is(negatedTy)) { // ¬any ~ any - result = isCovariantWith(env, negatedTy, superTy).withSubComponent(TypePath::TypeField::Negated); + result = isCovariantWith(env, negatedTy, superTy, scope).withSubComponent(TypePath::TypeField::Negated); } else if (auto u = get(negatedTy)) { @@ -1078,11 +1076,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Nega for (TypeId ty : u) { if (auto negatedPart = get(follow(ty))) - subtypings.push_back(isCovariantWith(env, negatedPart->ty, superTy).withSubComponent(TypePath::TypeField::Negated)); + subtypings.push_back(isCovariantWith(env, negatedPart->ty, superTy, scope).withSubComponent(TypePath::TypeField::Negated)); else { NegationType negatedTmp{ty}; - subtypings.push_back(isCovariantWith(env, &negatedTmp, superTy)); + subtypings.push_back(isCovariantWith(env, &negatedTmp, superTy, scope)); } } @@ -1097,11 +1095,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Nega for (TypeId ty : i) { if (auto negatedPart = get(follow(ty))) - subtypings.push_back(isCovariantWith(env, negatedPart->ty, superTy).withSubComponent(TypePath::TypeField::Negated)); + subtypings.push_back(isCovariantWith(env, negatedPart->ty, superTy, scope).withSubComponent(TypePath::TypeField::Negated)); else { NegationType negatedTmp{ty}; - subtypings.push_back(isCovariantWith(env, &negatedTmp, superTy)); + subtypings.push_back(isCovariantWith(env, &negatedTmp, superTy, scope)); } } @@ -1121,7 +1119,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Nega return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation, NotNull scope) { TypeId negatedTy = follow(superNegation->ty); @@ -1130,17 +1128,17 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type if (is(negatedTy)) { // ¬never ~ unknown - result = isCovariantWith(env, subTy, builtinTypes->unknownType); + result = isCovariantWith(env, subTy, builtinTypes->unknownType, scope); } else if (is(negatedTy)) { // ¬unknown ~ never - result = isCovariantWith(env, subTy, builtinTypes->neverType); + result = isCovariantWith(env, subTy, builtinTypes->neverType, scope); } else if (is(negatedTy)) { // ¬any ~ any - result = isSubtype(subTy, negatedTy); + result = isSubtype(subTy, negatedTy, scope); } else if (auto u = get(negatedTy)) { @@ -1151,11 +1149,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type for (TypeId ty : u) { if (auto negatedPart = get(follow(ty))) - subtypings.push_back(isCovariantWith(env, subTy, negatedPart->ty)); + subtypings.push_back(isCovariantWith(env, subTy, negatedPart->ty, scope)); else { NegationType negatedTmp{ty}; - subtypings.push_back(isCovariantWith(env, subTy, &negatedTmp)); + subtypings.push_back(isCovariantWith(env, subTy, &negatedTmp, scope)); } } @@ -1170,11 +1168,11 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type for (TypeId ty : i) { if (auto negatedPart = get(follow(ty))) - subtypings.push_back(isCovariantWith(env, subTy, negatedPart->ty)); + subtypings.push_back(isCovariantWith(env, subTy, negatedPart->ty, scope)); else { NegationType negatedTmp{ty}; - subtypings.push_back(isCovariantWith(env, subTy, &negatedTmp)); + subtypings.push_back(isCovariantWith(env, subTy, &negatedTmp, scope)); } } @@ -1218,7 +1216,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type else if (auto p = get2(subTy, negatedTy)) result = {*p.first != *p.second}; else if (auto p = get2(subTy, negatedTy)) - result = SubtypingResult::negate(isCovariantWith(env, p.first, p.second)); + result = SubtypingResult::negate(isCovariantWith(env, p.first, p.second, scope)); else if (get2(subTy, negatedTy)) result = {true}; else if (is(negatedTy)) @@ -1229,12 +1227,22 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type return result.withSuperComponent(TypePath::TypeField::Negated); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const PrimitiveType* superPrim) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const PrimitiveType* subPrim, + const PrimitiveType* superPrim, + NotNull scope +) { return {subPrim->type == superPrim->type}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const PrimitiveType* superPrim) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const SingletonType* subSingleton, + const PrimitiveType* superPrim, + NotNull scope +) { if (get(subSingleton) && superPrim->type == PrimitiveType::String) return {true}; @@ -1244,12 +1252,17 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Sing return {false}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const SingletonType* superSingleton) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const SingletonType* subSingleton, + const SingletonType* superSingleton, + NotNull scope +) { return {*subSingleton == *superSingleton}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable, NotNull scope) { SubtypingResult result{true}; @@ -1260,23 +1273,23 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl { std::vector results; if (auto subIter = subTable->props.find(name); subIter != subTable->props.end()) - results.push_back(isCovariantWith(env, subIter->second, superProp, name)); + results.push_back(isCovariantWith(env, subIter->second, superProp, name, scope)); else if (subTable->indexer) { - if (isCovariantWith(env, builtinTypes->stringType, subTable->indexer->indexType).isSubtype) + if (isCovariantWith(env, builtinTypes->stringType, subTable->indexer->indexType, scope).isSubtype) { if (superProp.isShared()) - results.push_back(isInvariantWith(env, subTable->indexer->indexResultType, superProp.type()) + results.push_back(isInvariantWith(env, subTable->indexer->indexResultType, superProp.type(), scope) .withSubComponent(TypePath::TypeField::IndexResult) .withSuperComponent(TypePath::Property::read(name))); else { if (superProp.readTy) - results.push_back(isCovariantWith(env, subTable->indexer->indexResultType, *superProp.readTy) + results.push_back(isCovariantWith(env, subTable->indexer->indexResultType, *superProp.readTy, scope) .withSubComponent(TypePath::TypeField::IndexResult) .withSuperComponent(TypePath::Property::read(name))); if (superProp.writeTy) - results.push_back(isContravariantWith(env, subTable->indexer->indexResultType, *superProp.writeTy) + results.push_back(isContravariantWith(env, subTable->indexer->indexResultType, *superProp.writeTy, scope) .withSubComponent(TypePath::TypeField::IndexResult) .withSuperComponent(TypePath::Property::write(name))); } @@ -1292,7 +1305,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl if (superTable->indexer) { if (subTable->indexer) - result.andAlso(isInvariantWith(env, *subTable->indexer, *superTable->indexer)); + result.andAlso(isInvariantWith(env, *subTable->indexer, *superTable->indexer, scope)); else return {false}; } @@ -1300,13 +1313,13 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt, NotNull scope) { - return isCovariantWith(env, subMt->table, superMt->table) - .andAlso(isCovariantWith(env, subMt->metatable, superMt->metatable).withBothComponent(TypePath::TypeField::Metatable)); + return isCovariantWith(env, subMt->table, superMt->table, scope) + .andAlso(isCovariantWith(env, subMt->metatable, superMt->metatable, scope).withBothComponent(TypePath::TypeField::Metatable)); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable, NotNull scope) { if (auto subTable = get(follow(subMt->table))) { @@ -1319,7 +1332,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Meta // that the metatable isn't a subtype of the table, even though they have // compatible properties/shapes. We'll revisit this later when we have a // better understanding of how important this is. - return isCovariantWith(env, subTable, superTable); + return isCovariantWith(env, subTable, superTable, scope); } else { @@ -1328,7 +1341,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Meta } } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass, NotNull scope) { return {isSubclass(subClass, superClass)}; } @@ -1338,7 +1351,8 @@ SubtypingResult Subtyping::isCovariantWith( TypeId subTy, const ClassType* subClass, TypeId superTy, - const TableType* superTable + const TableType* superTable, + NotNull scope ) { SubtypingResult result{true}; @@ -1349,7 +1363,7 @@ SubtypingResult Subtyping::isCovariantWith( { if (auto classProp = lookupClassProp(subClass, name)) { - result.andAlso(isCovariantWith(env, *classProp, prop, name)); + result.andAlso(isCovariantWith(env, *classProp, prop, name, scope)); } else { @@ -1363,19 +1377,26 @@ SubtypingResult Subtyping::isCovariantWith( return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const FunctionType* subFunction, const FunctionType* superFunction) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const FunctionType* subFunction, + const FunctionType* superFunction, + NotNull scope +) { SubtypingResult result; { - result.orElse(isContravariantWith(env, subFunction->argTypes, superFunction->argTypes).withBothComponent(TypePath::PackField::Arguments)); + result.orElse( + isContravariantWith(env, subFunction->argTypes, superFunction->argTypes, scope).withBothComponent(TypePath::PackField::Arguments) + ); } - result.andAlso(isCovariantWith(env, subFunction->retTypes, superFunction->retTypes).withBothComponent(TypePath::PackField::Returns)); + result.andAlso(isCovariantWith(env, subFunction->retTypes, superFunction->retTypes, scope).withBothComponent(TypePath::PackField::Returns)); return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim, NotNull scope) { SubtypingResult result{false}; if (superPrim->type == PrimitiveType::Table) @@ -1384,7 +1405,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable, NotNull scope) { SubtypingResult result{false}; if (subPrim->type == PrimitiveType::String) @@ -1397,7 +1418,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prim { if (auto stringTable = get(it->second.type())) result.orElse( - isCovariantWith(env, stringTable, superTable).withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()) + isCovariantWith(env, stringTable, superTable, scope).withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()) ); } } @@ -1412,7 +1433,12 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prim return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const SingletonType* subSingleton, + const TableType* superTable, + NotNull scope +) { SubtypingResult result{false}; if (auto stringleton = get(subSingleton)) @@ -1425,7 +1451,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Sing { if (auto stringTable = get(it->second.type())) result.orElse( - isCovariantWith(env, stringTable, superTable).withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()) + isCovariantWith(env, stringTable, superTable, scope).withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()) ); } } @@ -1434,25 +1460,38 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Sing return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TableIndexer& subIndexer, const TableIndexer& superIndexer) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const TableIndexer& subIndexer, + const TableIndexer& superIndexer, + NotNull scope +) { - return isInvariantWith(env, subIndexer.indexType, superIndexer.indexType) + return isInvariantWith(env, subIndexer.indexType, superIndexer.indexType, scope) .withBothComponent(TypePath::TypeField::IndexLookup) - .andAlso(isInvariantWith(env, subIndexer.indexResultType, superIndexer.indexResultType).withBothComponent(TypePath::TypeField::IndexResult)); + .andAlso( + isInvariantWith(env, subIndexer.indexResultType, superIndexer.indexResultType, scope).withBothComponent(TypePath::TypeField::IndexResult) + ); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Property& subProp, const Property& superProp, const std::string& name) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const Property& subProp, + const Property& superProp, + const std::string& name, + NotNull scope +) { SubtypingResult res{true}; if (superProp.isShared() && subProp.isShared()) - res.andAlso(isInvariantWith(env, subProp.type(), superProp.type()).withBothComponent(TypePath::Property::read(name))); + res.andAlso(isInvariantWith(env, subProp.type(), superProp.type(), scope).withBothComponent(TypePath::Property::read(name))); else { if (superProp.readTy.has_value() && subProp.readTy.has_value()) - res.andAlso(isCovariantWith(env, *subProp.readTy, *superProp.readTy).withBothComponent(TypePath::Property::read(name))); + res.andAlso(isCovariantWith(env, *subProp.readTy, *superProp.readTy, scope).withBothComponent(TypePath::Property::read(name))); if (superProp.writeTy.has_value() && subProp.writeTy.has_value()) - res.andAlso(isContravariantWith(env, *subProp.writeTy, *superProp.writeTy).withBothComponent(TypePath::Property::write(name))); + res.andAlso(isContravariantWith(env, *subProp.writeTy, *superProp.writeTy, scope).withBothComponent(TypePath::Property::write(name))); if (superProp.isReadWrite()) { @@ -1469,29 +1508,37 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prop SubtypingResult Subtyping::isCovariantWith( SubtypingEnvironment& env, const std::shared_ptr& subNorm, - const std::shared_ptr& superNorm + const std::shared_ptr& superNorm, + NotNull scope ) { if (!subNorm || !superNorm) return {false, true}; - SubtypingResult result = isCovariantWith(env, subNorm->tops, superNorm->tops); - result.andAlso(isCovariantWith(env, subNorm->booleans, superNorm->booleans)); - result.andAlso(isCovariantWith(env, subNorm->classes, superNorm->classes).orElse(isCovariantWith(env, subNorm->classes, superNorm->tables))); - result.andAlso(isCovariantWith(env, subNorm->errors, superNorm->errors)); - result.andAlso(isCovariantWith(env, subNorm->nils, superNorm->nils)); - result.andAlso(isCovariantWith(env, subNorm->numbers, superNorm->numbers)); - result.andAlso(isCovariantWith(env, subNorm->strings, superNorm->strings)); - result.andAlso(isCovariantWith(env, subNorm->strings, superNorm->tables)); - result.andAlso(isCovariantWith(env, subNorm->threads, superNorm->threads)); - result.andAlso(isCovariantWith(env, subNorm->buffers, superNorm->buffers)); - result.andAlso(isCovariantWith(env, subNorm->tables, superNorm->tables)); - result.andAlso(isCovariantWith(env, subNorm->functions, superNorm->functions)); + SubtypingResult result = isCovariantWith(env, subNorm->tops, superNorm->tops, scope); + result.andAlso(isCovariantWith(env, subNorm->booleans, superNorm->booleans, scope)); + result.andAlso( + isCovariantWith(env, subNorm->classes, superNorm->classes, scope).orElse(isCovariantWith(env, subNorm->classes, superNorm->tables, scope)) + ); + result.andAlso(isCovariantWith(env, subNorm->errors, superNorm->errors, scope)); + result.andAlso(isCovariantWith(env, subNorm->nils, superNorm->nils, scope)); + result.andAlso(isCovariantWith(env, subNorm->numbers, superNorm->numbers, scope)); + result.andAlso(isCovariantWith(env, subNorm->strings, superNorm->strings, scope)); + result.andAlso(isCovariantWith(env, subNorm->strings, superNorm->tables, scope)); + result.andAlso(isCovariantWith(env, subNorm->threads, superNorm->threads, scope)); + result.andAlso(isCovariantWith(env, subNorm->buffers, superNorm->buffers, scope)); + result.andAlso(isCovariantWith(env, subNorm->tables, superNorm->tables, scope)); + result.andAlso(isCovariantWith(env, subNorm->functions, superNorm->functions, scope)); // isCovariantWith(subNorm->tyvars, superNorm->tyvars); return result; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const NormalizedClassType& superClass) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const NormalizedClassType& subClass, + const NormalizedClassType& superClass, + NotNull scope +) { for (const auto& [subClassTy, _] : subClass.classes) { @@ -1499,13 +1546,13 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm for (const auto& [superClassTy, superNegations] : superClass.classes) { - result.orElse(isCovariantWith(env, subClassTy, superClassTy)); + result.orElse(isCovariantWith(env, subClassTy, superClassTy, scope)); if (!result.isSubtype) continue; for (TypeId negation : superNegations) { - result.andAlso(SubtypingResult::negate(isCovariantWith(env, subClassTy, negation))); + result.andAlso(SubtypingResult::negate(isCovariantWith(env, subClassTy, negation, scope))); if (result.isSubtype) break; } @@ -1518,14 +1565,19 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm return {true}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const NormalizedClassType& subClass, + const TypeIds& superTables, + NotNull scope +) { for (const auto& [subClassTy, _] : subClass.classes) { SubtypingResult result; for (TypeId superTableTy : superTables) - result.orElse(isCovariantWith(env, subClassTy, superTableTy)); + result.orElse(isCovariantWith(env, subClassTy, superTableTy, scope)); if (!result.isSubtype) return result; @@ -1534,13 +1586,23 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm return {true}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const NormalizedStringType& superString) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const NormalizedStringType& subString, + const NormalizedStringType& superString, + NotNull scope +) { bool isSubtype = Luau::isSubtype(subString, superString); return {isSubtype}; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const TypeIds& superTables) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const NormalizedStringType& subString, + const TypeIds& superTables, + NotNull scope +) { if (subString.isNever()) return {true}; @@ -1550,7 +1612,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm SubtypingResult result; for (const auto& superTable : superTables) { - result.orElse(isCovariantWith(env, builtinTypes->stringType, superTable)); + result.orElse(isCovariantWith(env, builtinTypes->stringType, superTable, scope)); if (result.isSubtype) return result; } @@ -1566,7 +1628,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm SubtypingResult result{true}; for (const auto& [_, subString] : subString.singletons) { - result.andAlso(isCovariantWith(env, subString, superTable)); + result.andAlso(isCovariantWith(env, subString, superTable, scope)); if (!result.isSubtype) break; } @@ -1583,7 +1645,8 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Norm SubtypingResult Subtyping::isCovariantWith( SubtypingEnvironment& env, const NormalizedFunctionType& subFunction, - const NormalizedFunctionType& superFunction + const NormalizedFunctionType& superFunction, + NotNull scope ) { if (subFunction.isNever()) @@ -1591,10 +1654,10 @@ SubtypingResult Subtyping::isCovariantWith( else if (superFunction.isTop) return {true}; else - return isCovariantWith(env, subFunction.parts, superFunction.parts); + return isCovariantWith(env, subFunction.parts, superFunction.parts, scope); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes) +SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes, NotNull scope) { std::vector results; @@ -1602,15 +1665,20 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Type { results.emplace_back(); for (TypeId superTy : superTypes) - results.back().orElse(isCovariantWith(env, subTy, superTy)); + results.back().orElse(isCovariantWith(env, subTy, superTy, scope)); } return SubtypingResult::all(results); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const VariadicTypePack* subVariadic, const VariadicTypePack* superVariadic) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const VariadicTypePack* subVariadic, + const VariadicTypePack* superVariadic, + NotNull scope +) { - return isCovariantWith(env, subVariadic->ty, superVariadic->ty).withBothComponent(TypePath::TypeField::Variadic); + return isCovariantWith(env, subVariadic->ty, superVariadic->ty, scope).withBothComponent(TypePath::TypeField::Variadic); } bool Subtyping::bindGeneric(SubtypingEnvironment& env, TypeId subTy, TypeId superTy) @@ -1633,20 +1701,30 @@ bool Subtyping::bindGeneric(SubtypingEnvironment& env, TypeId subTy, TypeId supe return true; } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeFunctionInstanceType* subFunctionInstance, const TypeId superTy) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const TypeFunctionInstanceType* subFunctionInstance, + const TypeId superTy, + NotNull scope +) { // Reduce the type function instance - auto [ty, errors] = handleTypeFunctionReductionResult(subFunctionInstance); + auto [ty, errors] = handleTypeFunctionReductionResult(subFunctionInstance, scope); // If we return optional, that means the type function was irreducible - we can reduce that to never - return isCovariantWith(env, ty, superTy).withErrors(errors).withSubComponent(TypePath::Reduction{ty}); + return isCovariantWith(env, ty, superTy, scope).withErrors(errors).withSubComponent(TypePath::Reduction{ty}); } -SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFunctionInstanceType* superFunctionInstance) +SubtypingResult Subtyping::isCovariantWith( + SubtypingEnvironment& env, + const TypeId subTy, + const TypeFunctionInstanceType* superFunctionInstance, + NotNull scope +) { // Reduce the type function instance - auto [ty, errors] = handleTypeFunctionReductionResult(superFunctionInstance); - return isCovariantWith(env, subTy, ty).withErrors(errors).withSuperComponent(TypePath::Reduction{ty}); + auto [ty, errors] = handleTypeFunctionReductionResult(superFunctionInstance, scope); + return isCovariantWith(env, subTy, ty, scope).withErrors(errors).withSuperComponent(TypePath::Reduction{ty}); } /* @@ -1681,7 +1759,7 @@ TypeId Subtyping::makeAggregateType(const Container& container, TypeId orElse) return arena->addType(T{std::vector(begin(container), end(container))}); } -std::pair Subtyping::handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance) +std::pair Subtyping::handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance, NotNull scope) { TypeFunctionContext context{arena, builtinTypes, scope, normalizer, iceReporter, NotNull{&limits}}; TypeId function = arena->addType(*functionInstance); diff --git a/Dependencies/luau/Luau/Analysis/src/Symbol.cpp b/Dependencies/luau/Luau/Analysis/src/Symbol.cpp index 4b808f19..5e5b9d8c 100644 --- a/Dependencies/luau/Luau/Analysis/src/Symbol.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Symbol.cpp @@ -3,7 +3,7 @@ #include "Luau/Common.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) namespace Luau { @@ -14,7 +14,7 @@ bool Symbol::operator==(const Symbol& rhs) const return local == rhs.local; else if (global.value) return rhs.global.value && global == rhs.global.value; // Subtlety: AstName::operator==(const char*) uses strcmp, not pointer identity. - else if (FFlag::DebugLuauDeferredConstraintResolution) + else if (FFlag::LuauSolverV2) return !rhs.local && !rhs.global.value; // Reflexivity: we already know `this` Symbol is empty, so check that rhs is. else return false; diff --git a/Dependencies/luau/Luau/Analysis/src/ToDot.cpp b/Dependencies/luau/Luau/Analysis/src/ToDot.cpp index aa2dc1e3..4408063f 100644 --- a/Dependencies/luau/Luau/Analysis/src/ToDot.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ToDot.cpp @@ -10,7 +10,7 @@ #include #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { @@ -254,7 +254,7 @@ void StateDot::visitChildren(TypeId ty, int index) finishNodeLabel(ty); finishNode(); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (!get(t.lowerBound)) visitChild(t.lowerBound, index, "[lowerBound]"); diff --git a/Dependencies/luau/Luau/Analysis/src/ToString.cpp b/Dependencies/luau/Luau/Analysis/src/ToString.cpp index 879ddfab..f0850835 100644 --- a/Dependencies/luau/Luau/Analysis/src/ToString.cpp +++ b/Dependencies/luau/Luau/Analysis/src/ToString.cpp @@ -19,7 +19,7 @@ #include #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) /* * Enables increasing levels of verbosity for Luau type names when stringifying. @@ -83,10 +83,10 @@ struct FindCyclicTypes final : TypeVisitor if (!visited.insert(ty)) return false; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // TODO: Replace these if statements with assert()s when we - // delete FFlag::DebugLuauDeferredConstraintResolution. + // delete FFlag::LuauSolverV2. // // When the old solver is used, these pointers are always // unused. When the new solver is used, they are never null. @@ -411,7 +411,7 @@ struct TypeStringifier void stringify(const std::string& name, const Property& prop) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return _newStringify(name, prop); emitKey(name); @@ -473,7 +473,7 @@ struct TypeStringifier // TODO: ftv.lowerBound and ftv.upperBound should always be non-nil when // the new solver is used. This can be replaced with an assert. - if (FFlag::DebugLuauDeferredConstraintResolution && ftv.lowerBound && ftv.upperBound) + if (FFlag::LuauSolverV2 && ftv.lowerBound && ftv.upperBound) { const TypeId lowerBound = follow(ftv.lowerBound); const TypeId upperBound = follow(ftv.upperBound); @@ -511,7 +511,7 @@ struct TypeStringifier if (FInt::DebugLuauVerboseTypeNames >= 2) { state.emit("-"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) state.emitLevel(ftv.scope); else state.emit(ftv.level); @@ -540,7 +540,7 @@ struct TypeStringifier if (FInt::DebugLuauVerboseTypeNames >= 2) { state.emit("-"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) state.emitLevel(gtv.scope); else state.emit(gtv.level); @@ -643,7 +643,7 @@ struct TypeStringifier state.emit(">"); } - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (ftv.isCheckedFunction) state.emit("@checked "); @@ -726,10 +726,10 @@ struct TypeStringifier std::string openbrace = "@@@"; std::string closedbrace = "@@@?!"; - switch (state.opts.hideTableKind ? (FFlag::DebugLuauDeferredConstraintResolution ? TableState::Sealed : TableState::Unsealed) : ttv.state) + switch (state.opts.hideTableKind ? (FFlag::LuauSolverV2 ? TableState::Sealed : TableState::Unsealed) : ttv.state) { case TableState::Sealed: - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { openbrace = "{"; closedbrace = "}"; @@ -742,7 +742,7 @@ struct TypeStringifier } break; case TableState::Unsealed: - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { state.result.invalid = true; openbrace = "{|"; @@ -1200,7 +1200,7 @@ struct TypePackStringifier if (FInt::DebugLuauVerboseTypeNames >= 2) { state.emit("-"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) state.emitLevel(pack.scope); else state.emit(pack.level); @@ -1219,7 +1219,7 @@ struct TypePackStringifier if (FInt::DebugLuauVerboseTypeNames >= 2) { state.emit("-"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) state.emitLevel(pack.scope); else state.emit(pack.level); diff --git a/Dependencies/luau/Luau/Analysis/src/Type.cpp b/Dependencies/luau/Luau/Analysis/src/Type.cpp index ffc4a97e..b024fdd2 100644 --- a/Dependencies/luau/Luau/Analysis/src/Type.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Type.cpp @@ -752,7 +752,7 @@ TypeId Property::type() const void Property::setType(TypeId ty) { readTy = ty; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) writeTy = ty; } diff --git a/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp b/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp index 5020adc6..7023fba9 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeChecker2.cpp @@ -76,6 +76,37 @@ struct StackPusher } }; +struct PropertyTypes +{ + // a vector of all the types assigned to the given property. + std::vector typesOfProp; + + // a vector of all the types that are missing the given property. + std::vector missingProp; + + bool foundOneProp() const + { + return !typesOfProp.empty(); + } + + bool noneMissingProp() const + { + return missingProp.empty(); + } + + bool foundMissingProp() const + { + return !missingProp.empty(); + } +}; + +struct PropertyType +{ + NormalizationResult present; + std::optional result; +}; + + static std::optional getIdentifierOfBaseVar(AstExpr* node) { if (AstExprGlobal* expr = node->as()) @@ -233,2955 +264,2907 @@ struct InternalTypeFunctionFinder : TypeOnceVisitor } }; -struct TypeChecker2 +void check( + NotNull builtinTypes, + NotNull unifierState, + NotNull limits, + DcrLogger* logger, + const SourceModule& sourceModule, + Module* module +) { - NotNull builtinTypes; - DcrLogger* logger; - const NotNull limits; - const NotNull ice; - const SourceModule* sourceModule; - Module* module; + LUAU_TIMETRACE_SCOPE("check", "Typechecking"); + + TypeChecker2 typeChecker{builtinTypes, unifierState, limits, logger, &sourceModule, module}; - TypeContext typeContext = TypeContext::Default; - std::vector> stack; - std::vector functionDeclStack; + typeChecker.visit(sourceModule.root); + + // if the only error we're producing is one about constraint solving being incomplete, we can silence it. + // this means we won't give this warning if types seem totally nonsensical, but there are no other errors. + // this is probably, on the whole, a good decision to not annoy users though. + if (module->errors.size() == 1 && get(module->errors[0])) + module->errors.clear(); - DenseHashSet seenTypeFunctionInstances{nullptr}; + unfreeze(module->interfaceTypes); + copyErrors(module->errors, module->interfaceTypes, builtinTypes); + freeze(module->interfaceTypes); +} - Normalizer normalizer; - Subtyping _subtyping; - NotNull subtyping; +TypeChecker2::TypeChecker2( + NotNull builtinTypes, + NotNull unifierState, + NotNull limits, + DcrLogger* logger, + const SourceModule* sourceModule, + Module* module +) + : builtinTypes(builtinTypes) + , logger(logger) + , limits(limits) + , ice(unifierState->iceHandler) + , sourceModule(sourceModule) + , module(module) + , normalizer{&module->internalTypes, builtinTypes, unifierState, /* cacheInhabitance */ true} + , _subtyping{builtinTypes, NotNull{&module->internalTypes}, NotNull{&normalizer}, NotNull{unifierState->iceHandler}} + , subtyping(&_subtyping) +{ +} - TypeChecker2(NotNull builtinTypes, NotNull unifierState, NotNull limits, DcrLogger* logger, - const SourceModule* sourceModule, Module* module) - : builtinTypes(builtinTypes) - , logger(logger) - , limits(limits) - , ice(unifierState->iceHandler) - , sourceModule(sourceModule) - , module(module) - , normalizer{&module->internalTypes, builtinTypes, unifierState, /* cacheInhabitance */ true} - , _subtyping{builtinTypes, NotNull{&module->internalTypes}, NotNull{&normalizer}, NotNull{unifierState->iceHandler}, - NotNull{module->getModuleScope().get()}} - , subtyping(&_subtyping) +bool TypeChecker2::allowsNoReturnValues(const TypePackId tp) +{ + for (TypeId ty : tp) { + if (!get(follow(ty))) + return false; } - static bool allowsNoReturnValues(const TypePackId tp) - { - for (TypeId ty : tp) - { - if (!get(follow(ty))) - return false; - } + return true; +} - return true; +Location TypeChecker2::getEndLocation(const AstExprFunction* function) +{ + Location loc = function->location; + if (loc.begin.line != loc.end.line) + { + Position begin = loc.end; + begin.column = std::max(0u, begin.column - 3); + loc = Location(begin, 3); } - static Location getEndLocation(const AstExprFunction* function) + return loc; +} + +bool TypeChecker2::isErrorCall(const AstExprCall* call) +{ + const AstExprGlobal* global = call->func->as(); + if (!global) + return false; + + if (global->name == "error") + return true; + else if (global->name == "assert") { - Location loc = function->location; - if (loc.begin.line != loc.end.line) - { - Position begin = loc.end; - begin.column = std::max(0u, begin.column - 3); - loc = Location(begin, 3); - } + // assert() will error because it is missing the first argument + if (call->args.size == 0) + return true; - return loc; + if (AstExprConstantBool* expr = call->args.data[0]->as()) + if (!expr->value) + return true; } - bool isErrorCall(const AstExprCall* call) - { - const AstExprGlobal* global = call->func->as(); - if (!global) - return false; + return false; +} - if (global->name == "error") - return true; - else if (global->name == "assert") +bool TypeChecker2::hasBreak(AstStat* node) +{ + if (AstStatBlock* stat = node->as()) + { + for (size_t i = 0; i < stat->body.size; ++i) { - // assert() will error because it is missing the first argument - if (call->args.size == 0) + if (hasBreak(stat->body.data[i])) return true; - - if (AstExprConstantBool* expr = call->args.data[0]->as()) - if (!expr->value) - return true; } return false; } - bool hasBreak(AstStat* node) - { - if (AstStatBlock* stat = node->as()) - { - for (size_t i = 0; i < stat->body.size; ++i) - { - if (hasBreak(stat->body.data[i])) - return true; - } - - return false; - } + if (node->is()) + return true; - if (node->is()) + if (AstStatIf* stat = node->as()) + { + if (hasBreak(stat->thenbody)) return true; - if (AstStatIf* stat = node->as()) - { - if (hasBreak(stat->thenbody)) - return true; - - if (stat->elsebody && hasBreak(stat->elsebody)) - return true; - - return false; - } + if (stat->elsebody && hasBreak(stat->elsebody)) + return true; return false; } - // returns the last statement before the block implicitly exits, or nullptr if the block does not implicitly exit - // i.e. returns nullptr if the block returns properly or never returns - const AstStat* getFallthrough(const AstStat* node) + return false; +} + +const AstStat* TypeChecker2::getFallthrough(const AstStat* node) +{ + if (const AstStatBlock* stat = node->as()) { - if (const AstStatBlock* stat = node->as()) + if (stat->body.size == 0) + return stat; + + for (size_t i = 0; i < stat->body.size - 1; ++i) { - if (stat->body.size == 0) - return stat; + if (getFallthrough(stat->body.data[i]) == nullptr) + return nullptr; + } - for (size_t i = 0; i < stat->body.size - 1; ++i) - { - if (getFallthrough(stat->body.data[i]) == nullptr) - return nullptr; - } + return getFallthrough(stat->body.data[stat->body.size - 1]); + } - return getFallthrough(stat->body.data[stat->body.size - 1]); - } + if (const AstStatIf* stat = node->as()) + { + if (const AstStat* thenf = getFallthrough(stat->thenbody)) + return thenf; - if (const AstStatIf* stat = node->as()) + if (stat->elsebody) { - if (const AstStat* thenf = getFallthrough(stat->thenbody)) - return thenf; - - if (stat->elsebody) - { - if (const AstStat* elsef = getFallthrough(stat->elsebody)) - return elsef; + if (const AstStat* elsef = getFallthrough(stat->elsebody)) + return elsef; - return nullptr; - } - else - return stat; + return nullptr; } + else + return stat; + } - if (node->is()) + if (node->is()) + return nullptr; + + if (const AstStatExpr* stat = node->as()) + { + if (AstExprCall* call = stat->expr->as(); call && isErrorCall(call)) return nullptr; - if (const AstStatExpr* stat = node->as()) + return stat; + } + + if (const AstStatWhile* stat = node->as()) + { + if (AstExprConstantBool* expr = stat->condition->as()) { - if (AstExprCall* call = stat->expr->as(); call && isErrorCall(call)) + if (expr->value && !hasBreak(stat->body)) return nullptr; - - return stat; } - if (const AstStatWhile* stat = node->as()) - { - if (AstExprConstantBool* expr = stat->condition->as()) - { - if (expr->value && !hasBreak(stat->body)) - return nullptr; - } - - return node; - } + return node; + } - if (const AstStatRepeat* stat = node->as()) + if (const AstStatRepeat* stat = node->as()) + { + if (AstExprConstantBool* expr = stat->condition->as()) { - if (AstExprConstantBool* expr = stat->condition->as()) - { - if (!expr->value && !hasBreak(stat->body)) - return nullptr; - } - - if (getFallthrough(stat->body) == nullptr) + if (!expr->value && !hasBreak(stat->body)) return nullptr; - - return node; } + if (getFallthrough(stat->body) == nullptr) + return nullptr; + return node; } - std::optional pushStack(AstNode* node) - { - if (Scope** scope = module->astScopes.find(node)) - return StackPusher{stack, *scope}; - else - return std::nullopt; - } + return node; +} - void checkForInternalTypeFunction(TypeId ty, Location location) - { - InternalTypeFunctionFinder finder(functionDeclStack); - finder.traverse(ty); +std::optional TypeChecker2::pushStack(AstNode* node) +{ + if (Scope** scope = module->astScopes.find(node)) + return StackPusher{stack, *scope}; + else + return std::nullopt; +} - for (TypeId internal : finder.internalFunctions) - reportError(WhereClauseNeeded{internal}, location); +void TypeChecker2::checkForInternalTypeFunction(TypeId ty, Location location) +{ + InternalTypeFunctionFinder finder(functionDeclStack); + finder.traverse(ty); - for (TypePackId internal : finder.internalPackFunctions) - reportError(PackWhereClauseNeeded{internal}, location); - } + for (TypeId internal : finder.internalFunctions) + reportError(WhereClauseNeeded{internal}, location); - TypeId checkForTypeFunctionInhabitance(TypeId instance, Location location) - { - if (seenTypeFunctionInstances.find(instance)) - return instance; - seenTypeFunctionInstances.insert(instance); + for (TypePackId internal : finder.internalPackFunctions) + reportError(PackWhereClauseNeeded{internal}, location); +} - ErrorVec errors = reduceTypeFunctions( - instance, - location, - TypeFunctionContext{NotNull{&module->internalTypes}, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, - true - ) - .errors; - if (!isErrorSuppressing(location, instance)) - reportErrors(std::move(errors)); +TypeId TypeChecker2::checkForTypeFunctionInhabitance(TypeId instance, Location location) +{ + if (seenTypeFunctionInstances.find(instance)) return instance; - } - - TypePackId lookupPack(AstExpr* expr) - { - // If a type isn't in the type graph, it probably means that a recursion limit was exceeded. - // We'll just return anyType in these cases. Typechecking against any is very fast and this - // allows us not to think about this very much in the actual typechecking logic. - TypePackId* tp = module->astTypePacks.find(expr); - if (tp) - return follow(*tp); - else - return builtinTypes->anyTypePack; - } + seenTypeFunctionInstances.insert(instance); - TypeId lookupType(AstExpr* expr) - { - // If a type isn't in the type graph, it probably means that a recursion limit was exceeded. - // We'll just return anyType in these cases. Typechecking against any is very fast and this - // allows us not to think about this very much in the actual typechecking logic. - TypeId* ty = module->astTypes.find(expr); - if (ty) - return checkForTypeFunctionInhabitance(follow(*ty), expr->location); + ErrorVec errors = reduceTypeFunctions( + instance, + location, + TypeFunctionContext{NotNull{&module->internalTypes}, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, + true + ) + .errors; + if (!isErrorSuppressing(location, instance)) + reportErrors(std::move(errors)); + return instance; +} - TypePackId* tp = module->astTypePacks.find(expr); - if (tp) - return checkForTypeFunctionInhabitance(flattenPack(*tp), expr->location); +TypePackId TypeChecker2::lookupPack(AstExpr* expr) +{ + // If a type isn't in the type graph, it probably means that a recursion limit was exceeded. + // We'll just return anyType in these cases. Typechecking against any is very fast and this + // allows us not to think about this very much in the actual typechecking logic. + TypePackId* tp = module->astTypePacks.find(expr); + if (tp) + return follow(*tp); + else + return builtinTypes->anyTypePack; +} - return builtinTypes->anyType; - } +TypeId TypeChecker2::lookupType(AstExpr* expr) +{ + // If a type isn't in the type graph, it probably means that a recursion limit was exceeded. + // We'll just return anyType in these cases. Typechecking against any is very fast and this + // allows us not to think about this very much in the actual typechecking logic. + TypeId* ty = module->astTypes.find(expr); + if (ty) + return checkForTypeFunctionInhabitance(follow(*ty), expr->location); + + TypePackId* tp = module->astTypePacks.find(expr); + if (tp) + return checkForTypeFunctionInhabitance(flattenPack(*tp), expr->location); + + return builtinTypes->anyType; +} - TypeId lookupAnnotation(AstType* annotation) +TypeId TypeChecker2::lookupAnnotation(AstType* annotation) +{ + if (FFlag::DebugLuauMagicTypes) { - if (FFlag::DebugLuauMagicTypes) + if (auto ref = annotation->as(); ref && ref->name == "_luau_print" && ref->parameters.size > 0) { - if (auto ref = annotation->as(); ref && ref->name == "_luau_print" && ref->parameters.size > 0) + if (auto ann = ref->parameters.data[0].type) { - if (auto ann = ref->parameters.data[0].type) - { - TypeId argTy = lookupAnnotation(ref->parameters.data[0].type); - luauPrintLine(format( - "_luau_print (%d, %d): %s\n", annotation->location.begin.line, annotation->location.begin.column, toString(argTy).c_str() - )); - return follow(argTy); - } + TypeId argTy = lookupAnnotation(ref->parameters.data[0].type); + luauPrintLine( + format("_luau_print (%d, %d): %s\n", annotation->location.begin.line, annotation->location.begin.column, toString(argTy).c_str()) + ); + return follow(argTy); } } - - TypeId* ty = module->astResolvedTypes.find(annotation); - LUAU_ASSERT(ty); - return checkForTypeFunctionInhabitance(follow(*ty), annotation->location); } - std::optional lookupPackAnnotation(AstTypePack* annotation) - { - TypePackId* tp = module->astResolvedTypePacks.find(annotation); - if (tp != nullptr) - return {follow(*tp)}; - return {}; - } + TypeId* ty = module->astResolvedTypes.find(annotation); + LUAU_ASSERT(ty); + return checkForTypeFunctionInhabitance(follow(*ty), annotation->location); +} - TypeId lookupExpectedType(AstExpr* expr) - { - if (TypeId* ty = module->astExpectedTypes.find(expr)) - return follow(*ty); +std::optional TypeChecker2::lookupPackAnnotation(AstTypePack* annotation) +{ + TypePackId* tp = module->astResolvedTypePacks.find(annotation); + if (tp != nullptr) + return {follow(*tp)}; + return {}; +} - return builtinTypes->anyType; - } +TypeId TypeChecker2::lookupExpectedType(AstExpr* expr) +{ + if (TypeId* ty = module->astExpectedTypes.find(expr)) + return follow(*ty); - TypePackId lookupExpectedPack(AstExpr* expr, TypeArena& arena) - { - if (TypeId* ty = module->astExpectedTypes.find(expr)) - return arena.addTypePack(TypePack{{follow(*ty)}, std::nullopt}); + return builtinTypes->anyType; +} - return builtinTypes->anyTypePack; - } +TypePackId TypeChecker2::lookupExpectedPack(AstExpr* expr, TypeArena& arena) +{ + if (TypeId* ty = module->astExpectedTypes.find(expr)) + return arena.addTypePack(TypePack{{follow(*ty)}, std::nullopt}); - TypePackId reconstructPack(AstArray exprs, TypeArena& arena) - { - if (exprs.size == 0) - return arena.addTypePack(TypePack{{}, std::nullopt}); + return builtinTypes->anyTypePack; +} - std::vector head; +TypePackId TypeChecker2::reconstructPack(AstArray exprs, TypeArena& arena) +{ + if (exprs.size == 0) + return arena.addTypePack(TypePack{{}, std::nullopt}); - for (size_t i = 0; i < exprs.size - 1; ++i) - { - head.push_back(lookupType(exprs.data[i])); - } + std::vector head; - TypePackId tail = lookupPack(exprs.data[exprs.size - 1]); - return arena.addTypePack(TypePack{head, tail}); + for (size_t i = 0; i < exprs.size - 1; ++i) + { + head.push_back(lookupType(exprs.data[i])); } - Scope* findInnermostScope(Location location) - { - Scope* bestScope = module->getModuleScope().get(); + TypePackId tail = lookupPack(exprs.data[exprs.size - 1]); + return arena.addTypePack(TypePack{head, tail}); +} + +Scope* TypeChecker2::findInnermostScope(Location location) +{ + Scope* bestScope = module->getModuleScope().get(); - bool didNarrow; - do + bool didNarrow; + do + { + didNarrow = false; + for (auto scope : bestScope->children) { - didNarrow = false; - for (auto scope : bestScope->children) + if (scope->location.encloses(location)) { - if (scope->location.encloses(location)) - { - bestScope = scope.get(); - didNarrow = true; - break; - } + bestScope = scope.get(); + didNarrow = true; + break; } - } while (didNarrow && bestScope->children.size() > 0); - - return bestScope; - } - - void visit(AstStat* stat) - { - auto pusher = pushStack(stat); - - if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto f = stat->as()) - return visit(f); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else if (auto s = stat->as()) - return visit(s); - else - LUAU_ASSERT(!"TypeChecker2 encountered an unknown node type"); - } + } + } while (didNarrow && bestScope->children.size() > 0); - void visit(AstStatBlock* block) - { - auto StackPusher = pushStack(block); + return bestScope; +} - for (AstStat* statement : block->body) - visit(statement); - } +void TypeChecker2::visit(AstStat* stat) +{ + auto pusher = pushStack(stat); + + if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto f = stat->as()) + return visit(f); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else if (auto s = stat->as()) + return visit(s); + else + LUAU_ASSERT(!"TypeChecker2 encountered an unknown node type"); +} - void visit(AstStatIf* ifStatement) - { - { - InConditionalContext flipper{&typeContext}; - visit(ifStatement->condition, ValueContext::RValue); - } +void TypeChecker2::visit(AstStatBlock* block) +{ + auto StackPusher = pushStack(block); - visit(ifStatement->thenbody); - if (ifStatement->elsebody) - visit(ifStatement->elsebody); - } + for (AstStat* statement : block->body) + visit(statement); +} - void visit(AstStatWhile* whileStatement) +void TypeChecker2::visit(AstStatIf* ifStatement) +{ { - visit(whileStatement->condition, ValueContext::RValue); - visit(whileStatement->body); + InConditionalContext flipper{&typeContext}; + visit(ifStatement->condition, ValueContext::RValue); } - void visit(AstStatRepeat* repeatStatement) - { - visit(repeatStatement->body); - visit(repeatStatement->condition, ValueContext::RValue); - } + visit(ifStatement->thenbody); + if (ifStatement->elsebody) + visit(ifStatement->elsebody); +} + +void TypeChecker2::visit(AstStatWhile* whileStatement) +{ + visit(whileStatement->condition, ValueContext::RValue); + visit(whileStatement->body); +} - void visit(AstStatBreak*) {} +void TypeChecker2::visit(AstStatRepeat* repeatStatement) +{ + visit(repeatStatement->body); + visit(repeatStatement->condition, ValueContext::RValue); +} - void visit(AstStatContinue*) {} +void TypeChecker2::visit(AstStatBreak*) {} - void visit(AstStatReturn* ret) - { - Scope* scope = findInnermostScope(ret->location); - TypePackId expectedRetType = scope->returnType; +void TypeChecker2::visit(AstStatContinue*) {} - TypeArena* arena = &module->internalTypes; - TypePackId actualRetType = reconstructPack(ret->list, *arena); +void TypeChecker2::visit(AstStatReturn* ret) +{ + Scope* scope = findInnermostScope(ret->location); + TypePackId expectedRetType = scope->returnType; - testIsSubtype(actualRetType, expectedRetType, ret->location); + TypeArena* arena = &module->internalTypes; + TypePackId actualRetType = reconstructPack(ret->list, *arena); - for (AstExpr* expr : ret->list) - visit(expr, ValueContext::RValue); - } + testIsSubtype(actualRetType, expectedRetType, ret->location); - void visit(AstStatExpr* expr) - { - visit(expr->expr, ValueContext::RValue); - } + for (AstExpr* expr : ret->list) + visit(expr, ValueContext::RValue); +} + +void TypeChecker2::visit(AstStatExpr* expr) +{ + visit(expr->expr, ValueContext::RValue); +} - void visit(AstStatLocal* local) +void TypeChecker2::visit(AstStatLocal* local) +{ + size_t count = std::max(local->values.size, local->vars.size); + for (size_t i = 0; i < count; ++i) { - size_t count = std::max(local->values.size, local->vars.size); - for (size_t i = 0; i < count; ++i) + AstExpr* value = i < local->values.size ? local->values.data[i] : nullptr; + const bool isPack = value && (value->is() || value->is()); + + if (value) + visit(value, ValueContext::RValue); + + if (i != local->values.size - 1 || !isPack) { - AstExpr* value = i < local->values.size ? local->values.data[i] : nullptr; - const bool isPack = value && (value->is() || value->is()); + AstLocal* var = i < local->vars.size ? local->vars.data[i] : nullptr; - if (value) - visit(value, ValueContext::RValue); + if (var && var->annotation) + { + TypeId annotationType = lookupAnnotation(var->annotation); + TypeId valueType = value ? lookupType(value) : nullptr; + if (valueType) + testIsSubtype(valueType, annotationType, value->location); + + visit(var->annotation); + } + } + else if (value) + { + TypePackId valuePack = lookupPack(value); + TypePack valueTypes; + if (i < local->vars.size) + valueTypes = extendTypePack(module->internalTypes, builtinTypes, valuePack, local->vars.size - i); - if (i != local->values.size - 1 || !isPack) + Location errorLocation; + for (size_t j = i; j < local->vars.size; ++j) { - AstLocal* var = i < local->vars.size ? local->vars.data[i] : nullptr; + if (j - i >= valueTypes.head.size()) + { + errorLocation = local->vars.data[j]->location; + break; + } - if (var && var->annotation) + AstLocal* var = local->vars.data[j]; + if (var->annotation) { - TypeId annotationType = lookupAnnotation(var->annotation); - TypeId valueType = value ? lookupType(value) : nullptr; - if (valueType) - testIsSubtype(valueType, annotationType, value->location); + TypeId varType = lookupAnnotation(var->annotation); + testIsSubtype(valueTypes.head[j - i], varType, value->location); visit(var->annotation); } } - else if (value) + + if (valueTypes.head.size() < local->vars.size - i) { - TypePackId valuePack = lookupPack(value); - TypePack valueTypes; - if (i < local->vars.size) - valueTypes = extendTypePack(module->internalTypes, builtinTypes, valuePack, local->vars.size - i); + reportError( + CountMismatch{ + // We subtract 1 here because the final AST + // expression is not worth one value. It is worth 0 + // or more depending on valueTypes.head + local->values.size - 1 + valueTypes.head.size(), + std::nullopt, + local->vars.size, + local->values.data[local->values.size - 1]->is() ? CountMismatch::FunctionResult : CountMismatch::ExprListResult, + }, + errorLocation + ); + } + } + } +} - Location errorLocation; - for (size_t j = i; j < local->vars.size; ++j) - { - if (j - i >= valueTypes.head.size()) - { - errorLocation = local->vars.data[j]->location; - break; - } - - AstLocal* var = local->vars.data[j]; - if (var->annotation) - { - TypeId varType = lookupAnnotation(var->annotation); - testIsSubtype(valueTypes.head[j - i], varType, value->location); - - visit(var->annotation); - } - } +void TypeChecker2::visit(AstStatFor* forStatement) +{ + if (forStatement->var->annotation) + { + visit(forStatement->var->annotation); - if (valueTypes.head.size() < local->vars.size - i) - { - reportError( - CountMismatch{ - // We subtract 1 here because the final AST - // expression is not worth one value. It is worth 0 - // or more depending on valueTypes.head - local->values.size - 1 + valueTypes.head.size(), - std::nullopt, - local->vars.size, - local->values.data[local->values.size - 1]->is() ? CountMismatch::FunctionResult - : CountMismatch::ExprListResult, - }, - errorLocation - ); - } - } - } + TypeId annotatedType = lookupAnnotation(forStatement->var->annotation); + testIsSubtype(builtinTypes->numberType, annotatedType, forStatement->var->location); } - void visit(AstStatFor* forStatement) + auto checkNumber = [this](AstExpr* expr) { - if (forStatement->var->annotation) - { - visit(forStatement->var->annotation); - - TypeId annotatedType = lookupAnnotation(forStatement->var->annotation); - testIsSubtype(builtinTypes->numberType, annotatedType, forStatement->var->location); - } + if (!expr) + return; - auto checkNumber = [this](AstExpr* expr) - { - if (!expr) - return; + visit(expr, ValueContext::RValue); + testIsSubtype(lookupType(expr), builtinTypes->numberType, expr->location); + }; - visit(expr, ValueContext::RValue); - testIsSubtype(lookupType(expr), builtinTypes->numberType, expr->location); - }; + checkNumber(forStatement->from); + checkNumber(forStatement->to); + checkNumber(forStatement->step); - checkNumber(forStatement->from); - checkNumber(forStatement->to); - checkNumber(forStatement->step); + visit(forStatement->body); +} - visit(forStatement->body); +void TypeChecker2::visit(AstStatForIn* forInStatement) +{ + for (AstLocal* local : forInStatement->vars) + { + if (local->annotation) + visit(local->annotation); } - void visit(AstStatForIn* forInStatement) - { - for (AstLocal* local : forInStatement->vars) - { - if (local->annotation) - visit(local->annotation); - } + for (AstExpr* expr : forInStatement->values) + visit(expr, ValueContext::RValue); - for (AstExpr* expr : forInStatement->values) - visit(expr, ValueContext::RValue); + visit(forInStatement->body); - visit(forInStatement->body); + // Rule out crazy stuff. Maybe possible if the file is not syntactically valid. + if (!forInStatement->vars.size || !forInStatement->values.size) + return; - // Rule out crazy stuff. Maybe possible if the file is not syntactically valid. - if (!forInStatement->vars.size || !forInStatement->values.size) - return; + NotNull scope = stack.back(); + TypeArena& arena = module->internalTypes; - NotNull scope = stack.back(); - TypeArena& arena = module->internalTypes; + std::vector variableTypes; + for (AstLocal* var : forInStatement->vars) + { + std::optional ty = scope->lookup(var); + LUAU_ASSERT(ty); + variableTypes.emplace_back(*ty); + } - std::vector variableTypes; - for (AstLocal* var : forInStatement->vars) - { - std::optional ty = scope->lookup(var); - LUAU_ASSERT(ty); - variableTypes.emplace_back(*ty); - } + AstExpr* firstValue = forInStatement->values.data[0]; - AstExpr* firstValue = forInStatement->values.data[0]; + // we need to build up a typepack for the iterators/values portion of the for-in statement. + std::vector valueTypes; + std::optional iteratorTail; - // we need to build up a typepack for the iterators/values portion of the for-in statement. - std::vector valueTypes; - std::optional iteratorTail; + // since the first value may be the only iterator (e.g. if it is a call), we want to + // look to see if it has a resulting typepack as our iterators. + TypePackId* retPack = module->astTypePacks.find(firstValue); + if (retPack) + { + auto [head, tail] = flatten(*retPack); + valueTypes = head; + iteratorTail = tail; + } + else + { + valueTypes.emplace_back(lookupType(firstValue)); + } - // since the first value may be the only iterator (e.g. if it is a call), we want to - // look to see if it has a resulting typepack as our iterators. - TypePackId* retPack = module->astTypePacks.find(firstValue); - if (retPack) - { - auto [head, tail] = flatten(*retPack); - valueTypes = head; - iteratorTail = tail; - } - else - { - valueTypes.emplace_back(lookupType(firstValue)); - } + // if the initial and expected types from the iterator unified during constraint solving, + // we'll have a resolved type to use here, but we'll only use it if either the iterator is + // directly present in the for-in statement or if we have an iterator state constraining us + TypeId* resolvedTy = module->astForInNextTypes.find(firstValue); + if (resolvedTy && (!retPack || valueTypes.size() > 1)) + valueTypes[0] = *resolvedTy; - // if the initial and expected types from the iterator unified during constraint solving, - // we'll have a resolved type to use here, but we'll only use it if either the iterator is - // directly present in the for-in statement or if we have an iterator state constraining us - TypeId* resolvedTy = module->astForInNextTypes.find(firstValue); - if (resolvedTy && (!retPack || valueTypes.size() > 1)) - valueTypes[0] = *resolvedTy; + for (size_t i = 1; i < forInStatement->values.size - 1; ++i) + { + valueTypes.emplace_back(lookupType(forInStatement->values.data[i])); + } - for (size_t i = 1; i < forInStatement->values.size - 1; ++i) - { - valueTypes.emplace_back(lookupType(forInStatement->values.data[i])); - } + // if we had more than one value, the tail from the first value is no longer appropriate to use. + if (forInStatement->values.size > 1) + { + auto [head, tail] = flatten(lookupPack(forInStatement->values.data[forInStatement->values.size - 1])); + valueTypes.insert(valueTypes.end(), head.begin(), head.end()); + iteratorTail = tail; + } - // if we had more than one value, the tail from the first value is no longer appropriate to use. - if (forInStatement->values.size > 1) - { - auto [head, tail] = flatten(lookupPack(forInStatement->values.data[forInStatement->values.size - 1])); - valueTypes.insert(valueTypes.end(), head.begin(), head.end()); - iteratorTail = tail; - } + // and now we can put everything together to get the actual typepack of the iterators. + TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail); - // and now we can put everything together to get the actual typepack of the iterators. - TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail); + // ... and then expand it out to 3 values (if possible) + TypePack iteratorTypes = extendTypePack(arena, builtinTypes, iteratorPack, 3); + if (iteratorTypes.head.empty()) + { + reportError(GenericError{"for..in loops require at least one value to iterate over. Got zero"}, getLocation(forInStatement->values)); + return; + } + TypeId iteratorTy = follow(iteratorTypes.head[0]); - // ... and then expand it out to 3 values (if possible) - TypePack iteratorTypes = extendTypePack(arena, builtinTypes, iteratorPack, 3); - if (iteratorTypes.head.empty()) + auto checkFunction = [this, &arena, &forInStatement, &variableTypes](const FunctionType* iterFtv, std::vector iterTys, bool isMm) + { + if (iterTys.size() < 1 || iterTys.size() > 3) { - reportError(GenericError{"for..in loops require at least one value to iterate over. Got zero"}, getLocation(forInStatement->values)); + if (isMm) + reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); + else + reportError(GenericError{"for..in loops must be passed (next[, table[, state]])"}, getLocation(forInStatement->values)); + return; } - TypeId iteratorTy = follow(iteratorTypes.head[0]); - auto checkFunction = [this, &arena, &forInStatement, &variableTypes](const FunctionType* iterFtv, std::vector iterTys, bool isMm) + // It is okay if there aren't enough iterators, but the iteratee must provide enough. + TypePack expectedVariableTypes = extendTypePack(arena, builtinTypes, iterFtv->retTypes, variableTypes.size()); + if (expectedVariableTypes.head.size() < variableTypes.size()) { - if (iterTys.size() < 1 || iterTys.size() > 3) - { - if (isMm) - reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); - else - reportError(GenericError{"for..in loops must be passed (next[, table[, state]])"}, getLocation(forInStatement->values)); - - return; - } - - // It is okay if there aren't enough iterators, but the iteratee must provide enough. - TypePack expectedVariableTypes = extendTypePack(arena, builtinTypes, iterFtv->retTypes, variableTypes.size()); - if (expectedVariableTypes.head.size() < variableTypes.size()) - { - if (isMm) - reportError( - GenericError{"__iter metamethod's next() function does not return enough values"}, getLocation(forInStatement->values) - ); - else - reportError(GenericError{"next() does not return enough values"}, forInStatement->values.data[0]->location); - } - - for (size_t i = 0; i < std::min(expectedVariableTypes.head.size(), variableTypes.size()); ++i) - testIsSubtype(variableTypes[i], expectedVariableTypes.head[i], forInStatement->vars.data[i]->location); - - // nextFn is going to be invoked with (arrayTy, startIndexTy) - - // It will be passed two arguments on every iteration save the - // first. + if (isMm) + reportError(GenericError{"__iter metamethod's next() function does not return enough values"}, getLocation(forInStatement->values)); + else + reportError(GenericError{"next() does not return enough values"}, forInStatement->values.data[0]->location); + } - // It may be invoked with 0 or 1 argument on the first iteration. - // This depends on the types in iterateePack and therefore - // iteratorTypes. + for (size_t i = 0; i < std::min(expectedVariableTypes.head.size(), variableTypes.size()); ++i) + testIsSubtype(variableTypes[i], expectedVariableTypes.head[i], forInStatement->vars.data[i]->location); - // If the iteratee is an error type, then we can't really say anything else about iteration over it. - // After all, it _could've_ been a table. - if (get(follow(flattenPack(iterFtv->argTypes)))) - return; + // nextFn is going to be invoked with (arrayTy, startIndexTy) - // If iteratorTypes is too short to be a valid call to nextFn, we have to report a count mismatch error. - // If 2 is too short to be a valid call to nextFn, we have to report a count mismatch error. - // If 2 is too long to be a valid call to nextFn, we have to report a count mismatch error. - auto [minCount, maxCount] = getParameterExtents(TxnLog::empty(), iterFtv->argTypes, /*includeHiddenVariadics*/ true); + // It will be passed two arguments on every iteration save the + // first. - TypePack flattenedArgTypes = extendTypePack(arena, builtinTypes, iterFtv->argTypes, 2); - size_t firstIterationArgCount = iterTys.empty() ? 0 : iterTys.size() - 1; - size_t actualArgCount = expectedVariableTypes.head.size(); - if (firstIterationArgCount < minCount) - { - if (isMm) - reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); - else - reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location); - } + // It may be invoked with 0 or 1 argument on the first iteration. + // This depends on the types in iterateePack and therefore + // iteratorTypes. - else if (actualArgCount < minCount) - { - if (isMm) - reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); - else - reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location); - } + // If the iteratee is an error type, then we can't really say anything else about iteration over it. + // After all, it _could've_ been a table. + if (get(follow(flattenPack(iterFtv->argTypes)))) + return; + // If iteratorTypes is too short to be a valid call to nextFn, we have to report a count mismatch error. + // If 2 is too short to be a valid call to nextFn, we have to report a count mismatch error. + // If 2 is too long to be a valid call to nextFn, we have to report a count mismatch error. + auto [minCount, maxCount] = getParameterExtents(TxnLog::empty(), iterFtv->argTypes, /*includeHiddenVariadics*/ true); - if (iterTys.size() >= 2 && flattenedArgTypes.head.size() > 0) - { - size_t valueIndex = forInStatement->values.size > 1 ? 1 : 0; - testIsSubtype(iterTys[1], flattenedArgTypes.head[0], forInStatement->values.data[valueIndex]->location); - } + TypePack flattenedArgTypes = extendTypePack(arena, builtinTypes, iterFtv->argTypes, 2); + size_t firstIterationArgCount = iterTys.empty() ? 0 : iterTys.size() - 1; + size_t actualArgCount = expectedVariableTypes.head.size(); + if (firstIterationArgCount < minCount) + { + if (isMm) + reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); + else + reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location); + } - if (iterTys.size() == 3 && flattenedArgTypes.head.size() > 1) - { - size_t valueIndex = forInStatement->values.size > 2 ? 2 : 0; - testIsSubtype(iterTys[2], flattenedArgTypes.head[1], forInStatement->values.data[valueIndex]->location); - } - }; - - std::shared_ptr iteratorNorm = normalizer.normalize(iteratorTy); - - if (!iteratorNorm) - reportError(NormalizationTooComplex{}, firstValue->location); - - /* - * If the first iterator argument is a function - * * There must be 1 to 3 iterator arguments. Name them (nextTy, - * arrayTy, startIndexTy) - * * The return type of nextTy() must correspond to the variables' - * types and counts. HOWEVER the first iterator will never be nil. - * * The first return value of nextTy must be compatible with - * startIndexTy. - * * The first argument to nextTy() must be compatible with arrayTy if - * present. nil if not. - * * The second argument to nextTy() must be compatible with - * startIndexTy if it is present. Else, it must be compatible with - * nil. - * * nextTy() must be callable with only 2 arguments. - */ - if (const FunctionType* nextFn = get(iteratorTy)) - { - checkFunction(nextFn, iteratorTypes.head, false); - } - else if (const TableType* ttv = get(iteratorTy)) - { - if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer) - { - testIsSubtype(variableTypes[0], ttv->indexer->indexType, forInStatement->vars.data[0]->location); - if (variableTypes.size() == 2) - testIsSubtype(variableTypes[1], ttv->indexer->indexResultType, forInStatement->vars.data[1]->location); - } + else if (actualArgCount < minCount) + { + if (isMm) + reportError(GenericError{"__iter metamethod must return (next[, table[, state]])"}, getLocation(forInStatement->values)); else - reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location); + reportError(CountMismatch{2, std::nullopt, firstIterationArgCount, CountMismatch::Arg}, forInStatement->values.data[0]->location); } - else if (get(iteratorTy) || get(iteratorTy) || get(iteratorTy)) + + + if (iterTys.size() >= 2 && flattenedArgTypes.head.size() > 0) { - // nothing + size_t valueIndex = forInStatement->values.size > 1 ? 1 : 0; + testIsSubtype(iterTys[1], flattenedArgTypes.head[0], forInStatement->values.data[valueIndex]->location); } - else if (isOptional(iteratorTy) && !(iteratorNorm && iteratorNorm->shouldSuppressErrors())) + + if (iterTys.size() == 3 && flattenedArgTypes.head.size() > 1) { - reportError(OptionalValueAccess{iteratorTy}, forInStatement->values.data[0]->location); + size_t valueIndex = forInStatement->values.size > 2 ? 2 : 0; + testIsSubtype(iterTys[2], flattenedArgTypes.head[1], forInStatement->values.data[valueIndex]->location); } - else if (std::optional iterMmTy = - findMetatableEntry(builtinTypes, module->errors, iteratorTy, "__iter", forInStatement->values.data[0]->location)) + }; + + std::shared_ptr iteratorNorm = normalizer.normalize(iteratorTy); + + if (!iteratorNorm) + reportError(NormalizationTooComplex{}, firstValue->location); + + /* + * If the first iterator argument is a function + * * There must be 1 to 3 iterator arguments. Name them (nextTy, + * arrayTy, startIndexTy) + * * The return type of nextTy() must correspond to the variables' + * types and counts. HOWEVER the first iterator will never be nil. + * * The first return value of nextTy must be compatible with + * startIndexTy. + * * The first argument to nextTy() must be compatible with arrayTy if + * present. nil if not. + * * The second argument to nextTy() must be compatible with + * startIndexTy if it is present. Else, it must be compatible with + * nil. + * * nextTy() must be callable with only 2 arguments. + */ + if (const FunctionType* nextFn = get(iteratorTy)) + { + checkFunction(nextFn, iteratorTypes.head, false); + } + else if (const TableType* ttv = get(iteratorTy)) + { + if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer) { - Instantiation instantiation{TxnLog::empty(), &arena, builtinTypes, TypeLevel{}, scope}; + testIsSubtype(variableTypes[0], ttv->indexer->indexType, forInStatement->vars.data[0]->location); + if (variableTypes.size() == 2) + testIsSubtype(variableTypes[1], ttv->indexer->indexResultType, forInStatement->vars.data[1]->location); + } + else + reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location); + } + else if (get(iteratorTy) || get(iteratorTy) || get(iteratorTy)) + { + // nothing + } + else if (isOptional(iteratorTy) && !(iteratorNorm && iteratorNorm->shouldSuppressErrors())) + { + reportError(OptionalValueAccess{iteratorTy}, forInStatement->values.data[0]->location); + } + else if (std::optional iterMmTy = findMetatableEntry(builtinTypes, module->errors, iteratorTy, "__iter", forInStatement->values.data[0]->location)) + { + Instantiation instantiation{TxnLog::empty(), &arena, builtinTypes, TypeLevel{}, scope}; - if (std::optional instantiatedIterMmTy = instantiate(builtinTypes, NotNull{&arena}, limits, scope, *iterMmTy)) + if (std::optional instantiatedIterMmTy = instantiate(builtinTypes, NotNull{&arena}, limits, scope, *iterMmTy)) + { + if (const FunctionType* iterMmFtv = get(*instantiatedIterMmTy)) { - if (const FunctionType* iterMmFtv = get(*instantiatedIterMmTy)) - { - TypePackId argPack = arena.addTypePack({iteratorTy}); - testIsSubtype(argPack, iterMmFtv->argTypes, forInStatement->values.data[0]->location); + TypePackId argPack = arena.addTypePack({iteratorTy}); + testIsSubtype(argPack, iterMmFtv->argTypes, forInStatement->values.data[0]->location); - TypePack mmIteratorTypes = extendTypePack(arena, builtinTypes, iterMmFtv->retTypes, 3); + TypePack mmIteratorTypes = extendTypePack(arena, builtinTypes, iterMmFtv->retTypes, 3); - if (mmIteratorTypes.head.size() == 0) - { - reportError(GenericError{"__iter must return at least one value"}, forInStatement->values.data[0]->location); - return; - } + if (mmIteratorTypes.head.size() == 0) + { + reportError(GenericError{"__iter must return at least one value"}, forInStatement->values.data[0]->location); + return; + } - TypeId nextFn = follow(mmIteratorTypes.head[0]); + TypeId nextFn = follow(mmIteratorTypes.head[0]); - if (std::optional instantiatedNextFn = instantiation.substitute(nextFn)) - { - std::vector instantiatedIteratorTypes = mmIteratorTypes.head; - instantiatedIteratorTypes[0] = *instantiatedNextFn; + if (std::optional instantiatedNextFn = instantiation.substitute(nextFn)) + { + std::vector instantiatedIteratorTypes = mmIteratorTypes.head; + instantiatedIteratorTypes[0] = *instantiatedNextFn; - if (const FunctionType* nextFtv = get(*instantiatedNextFn)) - { - checkFunction(nextFtv, instantiatedIteratorTypes, true); - } - else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *instantiatedNextFn)) - { - reportError(CannotCallNonFunction{*instantiatedNextFn}, forInStatement->values.data[0]->location); - } + if (const FunctionType* nextFtv = get(*instantiatedNextFn)) + { + checkFunction(nextFtv, instantiatedIteratorTypes, true); } - else + else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *instantiatedNextFn)) { - reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location); + reportError(CannotCallNonFunction{*instantiatedNextFn}, forInStatement->values.data[0]->location); } } - else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *iterMmTy)) + else { - // TODO: This will not tell the user that this is because the - // metamethod isn't callable. This is not ideal, and we should - // improve this error message. - - // TODO: This will also not handle intersections of functions or - // callable tables (which are supported by the runtime). - reportError(CannotCallNonFunction{*iterMmTy}, forInStatement->values.data[0]->location); + reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location); } } - else + else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *iterMmTy)) { - reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location); + // TODO: This will not tell the user that this is because the + // metamethod isn't callable. This is not ideal, and we should + // improve this error message. + + // TODO: This will also not handle intersections of functions or + // callable tables (which are supported by the runtime). + reportError(CannotCallNonFunction{*iterMmTy}, forInStatement->values.data[0]->location); } } - else if (iteratorNorm && iteratorNorm->hasTables()) - { - // Ok. All tables can be iterated. - } - else if (!iteratorNorm || !iteratorNorm->shouldSuppressErrors()) + else { - reportError(CannotCallNonFunction{iteratorTy}, forInStatement->values.data[0]->location); + reportError(UnificationTooComplex{}, forInStatement->values.data[0]->location); } } - - std::optional getBindingType(AstExpr* expr) + else if (iteratorNorm && iteratorNorm->hasTables()) { - if (auto localExpr = expr->as()) - { - Scope* s = stack.back(); - return s->lookup(localExpr->local); - } - else if (auto globalExpr = expr->as()) - { - Scope* s = stack.back(); - return s->lookup(globalExpr->name); - } - else - return std::nullopt; + // Ok. All tables can be iterated. + } + else if (!iteratorNorm || !iteratorNorm->shouldSuppressErrors()) + { + reportError(CannotCallNonFunction{iteratorTy}, forInStatement->values.data[0]->location); } +} - // this should only be called if the type of `lhs` is `never`. - void reportErrorsFromAssigningToNever(AstExpr* lhs, TypeId rhsType) +std::optional TypeChecker2::getBindingType(AstExpr* expr) +{ + if (auto localExpr = expr->as()) + { + Scope* s = stack.back(); + return s->lookup(localExpr->local); + } + else if (auto globalExpr = expr->as()) { + Scope* s = stack.back(); + return s->lookup(globalExpr->name); + } + else + return std::nullopt; +} - if (auto indexName = lhs->as()) - { - TypeId indexedType = lookupType(indexName->expr); +void TypeChecker2::reportErrorsFromAssigningToNever(AstExpr* lhs, TypeId rhsType) +{ - // if it's already never, I don't think we have anything to do here. - if (get(indexedType)) - return; + if (auto indexName = lhs->as()) + { + TypeId indexedType = lookupType(indexName->expr); - std::string prop = indexName->index.value; + // if it's already never, I don't think we have anything to do here. + if (get(indexedType)) + return; - std::shared_ptr norm = normalizer.normalize(indexedType); - if (!norm) - { - reportError(NormalizationTooComplex{}, lhs->location); - return; - } + std::string prop = indexName->index.value; + + std::shared_ptr norm = normalizer.normalize(indexedType); + if (!norm) + { + reportError(NormalizationTooComplex{}, lhs->location); + return; + } - // if the type is error suppressing, we don't actually have any work left to do. - if (norm->shouldSuppressErrors()) - return; + // if the type is error suppressing, we don't actually have any work left to do. + if (norm->shouldSuppressErrors()) + return; - const auto propTypes = lookupProp(norm.get(), prop, ValueContext::LValue, lhs->location, builtinTypes->stringType, module->errors); + const auto propTypes = lookupProp(norm.get(), prop, ValueContext::LValue, lhs->location, builtinTypes->stringType, module->errors); - reportError(CannotAssignToNever{rhsType, propTypes.typesOfProp, CannotAssignToNever::Reason::PropertyNarrowed}, lhs->location); - } + reportError(CannotAssignToNever{rhsType, propTypes.typesOfProp, CannotAssignToNever::Reason::PropertyNarrowed}, lhs->location); } +} - void visit(AstStatAssign* assign) - { - size_t count = std::min(assign->vars.size, assign->values.size); +void TypeChecker2::visit(AstStatAssign* assign) +{ + size_t count = std::min(assign->vars.size, assign->values.size); - for (size_t i = 0; i < count; ++i) - { - AstExpr* lhs = assign->vars.data[i]; - visit(lhs, ValueContext::LValue); - TypeId lhsType = lookupType(lhs); + for (size_t i = 0; i < count; ++i) + { + AstExpr* lhs = assign->vars.data[i]; + visit(lhs, ValueContext::LValue); + TypeId lhsType = lookupType(lhs); - AstExpr* rhs = assign->values.data[i]; - visit(rhs, ValueContext::RValue); - TypeId rhsType = lookupType(rhs); + AstExpr* rhs = assign->values.data[i]; + visit(rhs, ValueContext::RValue); + TypeId rhsType = lookupType(rhs); - if (get(lhsType)) - { - reportErrorsFromAssigningToNever(lhs, rhsType); - continue; - } + if (get(lhsType)) + { + reportErrorsFromAssigningToNever(lhs, rhsType); + continue; + } - bool ok = testIsSubtype(rhsType, lhsType, rhs->location); + bool ok = testIsSubtype(rhsType, lhsType, rhs->location); - // If rhsType bindingType = getBindingType(lhs); - if (bindingType) - testIsSubtype(rhsType, *bindingType, rhs->location); - } + // If rhsType bindingType = getBindingType(lhs); + if (bindingType) + testIsSubtype(rhsType, *bindingType, rhs->location); } } +} - void visit(AstStatCompoundAssign* stat) - { - AstExprBinary fake{stat->location, stat->op, stat->var, stat->value}; - visit(&fake, stat); - - TypeId* resultTy = module->astCompoundAssignResultTypes.find(stat); - LUAU_ASSERT(resultTy); - TypeId varTy = lookupType(stat->var); +void TypeChecker2::visit(AstStatCompoundAssign* stat) +{ + AstExprBinary fake{stat->location, stat->op, stat->var, stat->value}; + visit(&fake, stat); - testIsSubtype(*resultTy, varTy, stat->location); - } + TypeId* resultTy = module->astCompoundAssignResultTypes.find(stat); + LUAU_ASSERT(resultTy); + TypeId varTy = lookupType(stat->var); - void visit(AstStatFunction* stat) - { - visit(stat->name, ValueContext::LValue); - visit(stat->func); - } + testIsSubtype(*resultTy, varTy, stat->location); +} - void visit(AstStatLocalFunction* stat) - { - visit(stat->func); - } +void TypeChecker2::visit(AstStatFunction* stat) +{ + visit(stat->name, ValueContext::LValue); + visit(stat->func); +} - void visit(const AstTypeList* typeList) - { - for (AstType* ty : typeList->types) - visit(ty); +void TypeChecker2::visit(AstStatLocalFunction* stat) +{ + visit(stat->func); +} - if (typeList->tailType) - visit(typeList->tailType); - } +void TypeChecker2::visit(const AstTypeList* typeList) +{ + for (AstType* ty : typeList->types) + visit(ty); - void visit(AstStatTypeAlias* stat) - { - visitGenerics(stat->generics, stat->genericPacks); - visit(stat->type); - } + if (typeList->tailType) + visit(typeList->tailType); +} - void visit(AstStatTypeFunction* stat) - { - // TODO: add type checking for user-defined type functions +void TypeChecker2::visit(AstStatTypeAlias* stat) +{ + visitGenerics(stat->generics, stat->genericPacks); + visit(stat->type); +} - reportError(TypeError{stat->location, GenericError{"This syntax is not supported"}}); - } +void TypeChecker2::visit(AstStatTypeFunction* stat) +{ + // TODO: add type checking for user-defined type functions - void visit(AstTypeList types) - { - for (AstType* type : types.types) - visit(type); - if (types.tailType) - visit(types.tailType); - } + reportError(TypeError{stat->location, GenericError{"This syntax is not supported"}}); +} - void visit(AstStatDeclareFunction* stat) - { - visitGenerics(stat->generics, stat->genericPacks); - visit(stat->params); - visit(stat->retTypes); - } +void TypeChecker2::visit(AstTypeList types) +{ + for (AstType* type : types.types) + visit(type); + if (types.tailType) + visit(types.tailType); +} - void visit(AstStatDeclareGlobal* stat) - { - visit(stat->type); - } +void TypeChecker2::visit(AstStatDeclareFunction* stat) +{ + visitGenerics(stat->generics, stat->genericPacks); + visit(stat->params); + visit(stat->retTypes); +} - void visit(AstStatDeclareClass* stat) - { - for (const AstDeclaredClassProp& prop : stat->props) - visit(prop.ty); - } +void TypeChecker2::visit(AstStatDeclareGlobal* stat) +{ + visit(stat->type); +} - void visit(AstStatError* stat) - { - for (AstExpr* expr : stat->expressions) - visit(expr, ValueContext::RValue); +void TypeChecker2::visit(AstStatDeclareClass* stat) +{ + for (const AstDeclaredClassProp& prop : stat->props) + visit(prop.ty); +} - for (AstStat* s : stat->statements) - visit(s); - } +void TypeChecker2::visit(AstStatError* stat) +{ + for (AstExpr* expr : stat->expressions) + visit(expr, ValueContext::RValue); - void visit(AstExpr* expr, ValueContext context) - { - auto StackPusher = pushStack(expr); + for (AstStat* s : stat->statements) + visit(s); +} - if (auto e = expr->as()) - return visit(e, context); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e, context); - else if (auto e = expr->as()) - return visit(e, context); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - { - visit(e); - return; - } - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else if (auto e = expr->as()) - return visit(e); - else - LUAU_ASSERT(!"TypeChecker2 encountered an unknown expression type"); - } +void TypeChecker2::visit(AstExpr* expr, ValueContext context) +{ + auto StackPusher = pushStack(expr); + + if (auto e = expr->as()) + return visit(e, context); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e, context); + else if (auto e = expr->as()) + return visit(e, context); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + { + visit(e); + return; + } + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else if (auto e = expr->as()) + return visit(e); + else + LUAU_ASSERT(!"TypeChecker2 encountered an unknown expression type"); +} - void visit(AstExprGroup* expr, ValueContext context) - { - visit(expr->expr, context); - } +void TypeChecker2::visit(AstExprGroup* expr, ValueContext context) +{ + visit(expr->expr, context); +} - void visit(AstExprConstantNil* expr) - { +void TypeChecker2::visit(AstExprConstantNil* expr) +{ #if defined(LUAU_ENABLE_ASSERT) - TypeId actualType = lookupType(expr); - TypeId expectedType = builtinTypes->nilType; + TypeId actualType = lookupType(expr); + TypeId expectedType = builtinTypes->nilType; + NotNull scope{findInnermostScope(expr->location)}; - SubtypingResult r = subtyping->isSubtype(actualType, expectedType); - LUAU_ASSERT(r.isSubtype || isErrorSuppressing(expr->location, actualType)); + SubtypingResult r = subtyping->isSubtype(actualType, expectedType, scope); + LUAU_ASSERT(r.isSubtype || isErrorSuppressing(expr->location, actualType)); #endif - } +} - void visit(AstExprConstantBool* expr) - { - // booleans use specialized inference logic for singleton types, which can lead to real type errors here. +void TypeChecker2::visit(AstExprConstantBool* expr) +{ + // booleans use specialized inference logic for singleton types, which can lead to real type errors here. - const TypeId bestType = expr->value ? builtinTypes->trueType : builtinTypes->falseType; - const TypeId inferredType = lookupType(expr); + const TypeId bestType = expr->value ? builtinTypes->trueType : builtinTypes->falseType; + const TypeId inferredType = lookupType(expr); + NotNull scope{findInnermostScope(expr->location)}; - const SubtypingResult r = subtyping->isSubtype(bestType, inferredType); - if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType)) - reportError(TypeMismatch{inferredType, bestType}, expr->location); - } + const SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope); + if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType)) + reportError(TypeMismatch{inferredType, bestType}, expr->location); +} - void visit(AstExprConstantNumber* expr) - { +void TypeChecker2::visit(AstExprConstantNumber* expr) +{ #if defined(LUAU_ENABLE_ASSERT) - const TypeId bestType = builtinTypes->numberType; - const TypeId inferredType = lookupType(expr); + const TypeId bestType = builtinTypes->numberType; + const TypeId inferredType = lookupType(expr); + NotNull scope{findInnermostScope(expr->location)}; - const SubtypingResult r = subtyping->isSubtype(bestType, inferredType); - LUAU_ASSERT(r.isSubtype || isErrorSuppressing(expr->location, inferredType)); + const SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope); + LUAU_ASSERT(r.isSubtype || isErrorSuppressing(expr->location, inferredType)); #endif - } - - void visit(AstExprConstantString* expr) - { - // strings use specialized inference logic for singleton types, which can lead to real type errors here. +} - const TypeId bestType = module->internalTypes.addType(SingletonType{StringSingleton{std::string{expr->value.data, expr->value.size}}}); - const TypeId inferredType = lookupType(expr); +void TypeChecker2::visit(AstExprConstantString* expr) +{ + // strings use specialized inference logic for singleton types, which can lead to real type errors here. - const SubtypingResult r = subtyping->isSubtype(bestType, inferredType); - if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType)) - reportError(TypeMismatch{inferredType, bestType}, expr->location); - } + const TypeId bestType = module->internalTypes.addType(SingletonType{StringSingleton{std::string{expr->value.data, expr->value.size}}}); + const TypeId inferredType = lookupType(expr); + NotNull scope{findInnermostScope(expr->location)}; - void visit(AstExprLocal* expr) - { - // TODO! - } + const SubtypingResult r = subtyping->isSubtype(bestType, inferredType, scope); + if (!r.isSubtype && !isErrorSuppressing(expr->location, inferredType)) + reportError(TypeMismatch{inferredType, bestType}, expr->location); +} - void visit(AstExprGlobal* expr) - { - NotNull scope = stack.back(); - if (!scope->lookup(expr->name)) - reportError(UnknownSymbol{expr->name.value, UnknownSymbol::Binding}, expr->location); - } +void TypeChecker2::visit(AstExprLocal* expr) +{ + // TODO! +} - void visit(AstExprVarargs* expr) - { - // TODO! - } +void TypeChecker2::visit(AstExprGlobal* expr) +{ + NotNull scope = stack.back(); + if (!scope->lookup(expr->name)) + reportError(UnknownSymbol{expr->name.value, UnknownSymbol::Binding}, expr->location); +} - // Note: this is intentionally separated from `visit(AstExprCall*)` for stack allocation purposes. - void visitCall(AstExprCall* call) - { - TypePack args; - std::vector argExprs; - argExprs.reserve(call->args.size + 1); +void TypeChecker2::visit(AstExprVarargs* expr) +{ + // TODO! +} - TypeId* originalCallTy = module->astOriginalCallTypes.find(call); - TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(call); - if (!originalCallTy) - return; +void TypeChecker2::visitCall(AstExprCall* call) +{ + TypePack args; + std::vector argExprs; + NotNull scope{findInnermostScope(call->location)}; + argExprs.reserve(call->args.size + 1); - TypeId fnTy = follow(*originalCallTy); + TypeId* originalCallTy = module->astOriginalCallTypes.find(call->func); + TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(call); + if (!originalCallTy) + return; + TypeId fnTy = follow(*originalCallTy); - if (get(fnTy) || get(fnTy) || get(fnTy)) - return; - else if (isOptional(fnTy)) - { - switch (shouldSuppressErrors(NotNull{&normalizer}, fnTy)) - { - case ErrorSuppression::Suppress: - break; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, call->func->location); - // fallthrough intentional - case ErrorSuppression::DoNotSuppress: - reportError(OptionalValueAccess{fnTy}, call->func->location); - } - return; - } - if (selectedOverloadTy) + if (get(fnTy) || get(fnTy) || get(fnTy)) + return; + else if (isOptional(fnTy)) + { + switch (shouldSuppressErrors(NotNull{&normalizer}, fnTy)) { - SubtypingResult result = subtyping->isSubtype(*originalCallTy, *selectedOverloadTy); - if (result.isSubtype) - fnTy = follow(*selectedOverloadTy); - - if (result.normalizationTooComplex) - { - reportError(NormalizationTooComplex{}, call->func->location); - return; - } + case ErrorSuppression::Suppress: + break; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, call->func->location); + [[fallthrough]]; + case ErrorSuppression::DoNotSuppress: + reportError(OptionalValueAccess{fnTy}, call->func->location); } + return; + } - if (call->self) - { - AstExprIndexName* indexExpr = call->func->as(); - if (!indexExpr) - ice->ice("method call expression has no 'self'"); - - args.head.push_back(lookupType(indexExpr->expr)); - argExprs.push_back(indexExpr->expr); - } + if (selectedOverloadTy) + { + SubtypingResult result = subtyping->isSubtype(*originalCallTy, *selectedOverloadTy, scope); + if (result.isSubtype) + fnTy = follow(*selectedOverloadTy); - for (size_t i = 0; i < call->args.size; ++i) + if (result.normalizationTooComplex) { - AstExpr* arg = call->args.data[i]; - argExprs.push_back(arg); - TypeId* argTy = module->astTypes.find(arg); - if (argTy) - args.head.push_back(*argTy); - else if (i == call->args.size - 1) - { - if (auto argTail = module->astTypePacks.find(arg)) - { - auto [head, tail] = flatten(*argTail); - args.head.insert(args.head.end(), head.begin(), head.end()); - args.tail = tail; - } - else - args.tail = builtinTypes->anyTypePack; - } - else - args.head.push_back(builtinTypes->anyType); + reportError(NormalizationTooComplex{}, call->func->location); + return; } + } + if (call->self) + { + AstExprIndexName* indexExpr = call->func->as(); + if (!indexExpr) + ice->ice("method call expression has no 'self'"); + args.head.push_back(lookupType(indexExpr->expr)); + argExprs.push_back(indexExpr->expr); + } - OverloadResolver resolver{ - builtinTypes, - NotNull{&module->internalTypes}, - NotNull{&normalizer}, - NotNull{stack.back()}, - ice, - limits, - call->location, - }; - resolver.resolve(fnTy, &args, call->func, &argExprs); - - auto norm = normalizer.normalize(fnTy); - if (!norm) - reportError(NormalizationTooComplex{}, call->func->location); - auto isInhabited = normalizer.isInhabited(norm.get()); - if (isInhabited == NormalizationResult::HitLimits) - reportError(NormalizationTooComplex{}, call->func->location); - - if (norm && norm->shouldSuppressErrors()) - return; // error suppressing function type! - else if (!resolver.ok.empty()) - return; // We found a call that works, so this is ok. - else if (!norm || isInhabited == NormalizationResult::False) - return; // Ok. Calling an uninhabited type is no-op. - else if (!resolver.nonviableOverloads.empty()) + for (size_t i = 0; i < call->args.size; ++i) + { + AstExpr* arg = call->args.data[i]; + argExprs.push_back(arg); + TypeId* argTy = module->astTypes.find(arg); + if (argTy) + args.head.push_back(*argTy); + else if (i == call->args.size - 1) { - if (resolver.nonviableOverloads.size() == 1 && !isErrorSuppressing(call->func->location, resolver.nonviableOverloads.front().first)) - reportErrors(resolver.nonviableOverloads.front().second); - else + if (auto argTail = module->astTypePacks.find(arg)) { - std::string s = "None of the overloads for function that accept "; - s += std::to_string(args.head.size()); - s += " arguments are compatible."; - reportError(GenericError{std::move(s)}, call->location); + auto [head, tail] = flatten(*argTail); + args.head.insert(args.head.end(), head.begin(), head.end()); + args.tail = tail; } - } - else if (!resolver.arityMismatches.empty()) - { - if (resolver.arityMismatches.size() == 1) - reportErrors(resolver.arityMismatches.front().second); else - { - std::string s = "No overload for function accepts "; - s += std::to_string(args.head.size()); - s += " arguments."; - reportError(GenericError{std::move(s)}, call->location); - } + args.tail = builtinTypes->anyTypePack; } - else if (!resolver.nonFunctions.empty()) - reportError(CannotCallNonFunction{fnTy}, call->func->location); else - LUAU_ASSERT(!"Generating the best possible error from this function call resolution was inexhaustive?"); + args.head.push_back(builtinTypes->anyType); + } - if (resolver.nonviableOverloads.size() <= 1 && resolver.arityMismatches.size() <= 1) + TypePackId argsTp = module->internalTypes.addTypePack(args); + if (auto ftv = get(follow(*originalCallTy))) + { + if (ftv->dcrMagicTypeCheck) + { + ftv->dcrMagicTypeCheck(MagicFunctionTypeCheckContext{NotNull{this}, builtinTypes, call, argsTp, scope}); return; + } + } - std::string s = "Available overloads: "; - std::vector overloads; - if (resolver.nonviableOverloads.empty()) + OverloadResolver resolver{ + builtinTypes, + NotNull{&module->internalTypes}, + NotNull{&normalizer}, + NotNull{stack.back()}, + ice, + limits, + call->location, + }; + resolver.resolve(fnTy, &args, call->func, &argExprs); + + auto norm = normalizer.normalize(fnTy); + if (!norm) + reportError(NormalizationTooComplex{}, call->func->location); + auto isInhabited = normalizer.isInhabited(norm.get()); + if (isInhabited == NormalizationResult::HitLimits) + reportError(NormalizationTooComplex{}, call->func->location); + + if (norm && norm->shouldSuppressErrors()) + return; // error suppressing function type! + else if (!resolver.ok.empty()) + return; // We found a call that works, so this is ok. + else if (!norm || isInhabited == NormalizationResult::False) + return; // Ok. Calling an uninhabited type is no-op. + else if (!resolver.nonviableOverloads.empty()) + { + if (resolver.nonviableOverloads.size() == 1 && !isErrorSuppressing(call->func->location, resolver.nonviableOverloads.front().first)) + reportErrors(resolver.nonviableOverloads.front().second); + else { - for (const auto& [ty, p] : resolver.resolution) - { - if (p.first == OverloadResolver::TypeIsNotAFunction) - continue; - - overloads.push_back(ty); - } + std::string s = "None of the overloads for function that accept "; + s += std::to_string(args.head.size()); + s += " arguments are compatible."; + reportError(GenericError{std::move(s)}, call->location); } + } + else if (!resolver.arityMismatches.empty()) + { + if (resolver.arityMismatches.size() == 1) + reportErrors(resolver.arityMismatches.front().second); else { - for (const auto& [ty, _] : resolver.nonviableOverloads) - overloads.push_back(ty); + std::string s = "No overload for function accepts "; + s += std::to_string(args.head.size()); + s += " arguments."; + reportError(GenericError{std::move(s)}, call->location); } + } + else if (!resolver.nonFunctions.empty()) + reportError(CannotCallNonFunction{fnTy}, call->func->location); + else + LUAU_ASSERT(!"Generating the best possible error from this function call resolution was inexhaustive?"); - if (overloads.size() <= 1) - return; + if (resolver.nonviableOverloads.size() <= 1 && resolver.arityMismatches.size() <= 1) + return; + + std::string s = "Available overloads: "; - for (size_t i = 0; i < overloads.size(); ++i) + std::vector overloads; + if (resolver.nonviableOverloads.empty()) + { + for (const auto& [ty, p] : resolver.resolution) { - if (i > 0) - s += (i == overloads.size() - 1) ? "; and " : "; "; + if (p.first == OverloadResolver::TypeIsNotAFunction) + continue; - s += toString(overloads[i]); + overloads.push_back(ty); } - - reportError(ExtraInformation{std::move(s)}, call->func->location); } - - void visit(AstExprCall* call) + else { - visit(call->func, ValueContext::RValue); + for (const auto& [ty, _] : resolver.nonviableOverloads) + overloads.push_back(ty); + } + + if (overloads.size() <= 1) + return; - for (AstExpr* arg : call->args) - visit(arg, ValueContext::RValue); + for (size_t i = 0; i < overloads.size(); ++i) + { + if (i > 0) + s += (i == overloads.size() - 1) ? "; and " : "; "; - visitCall(call); + s += toString(overloads[i]); } - std::optional tryStripUnionFromNil(TypeId ty) - { - if (const UnionType* utv = get(ty)) - { - if (!std::any_of(begin(utv), end(utv), isNil)) - return ty; + reportError(ExtraInformation{std::move(s)}, call->func->location); +} - std::vector result; +void TypeChecker2::visit(AstExprCall* call) +{ + visit(call->func, ValueContext::RValue); - for (TypeId option : utv) - { - if (!isNil(option)) - result.push_back(option); - } + for (AstExpr* arg : call->args) + visit(arg, ValueContext::RValue); + + visitCall(call); +} + +std::optional TypeChecker2::tryStripUnionFromNil(TypeId ty) +{ + if (const UnionType* utv = get(ty)) + { + if (!std::any_of(begin(utv), end(utv), isNil)) + return ty; - if (result.empty()) - return std::nullopt; + std::vector result; - return result.size() == 1 ? result[0] : module->internalTypes.addType(UnionType{std::move(result)}); + for (TypeId option : utv) + { + if (!isNil(option)) + result.push_back(option); } - return std::nullopt; + if (result.empty()) + return std::nullopt; + + return result.size() == 1 ? result[0] : module->internalTypes.addType(UnionType{std::move(result)}); } - TypeId stripFromNilAndReport(TypeId ty, const Location& location) + return std::nullopt; +} + +TypeId TypeChecker2::stripFromNilAndReport(TypeId ty, const Location& location) +{ + ty = follow(ty); + + if (auto utv = get(ty)) { - ty = follow(ty); + if (!std::any_of(begin(utv), end(utv), isNil)) + return ty; + } - if (auto utv = get(ty)) + if (std::optional strippedUnion = tryStripUnionFromNil(ty)) + { + switch (shouldSuppressErrors(NotNull{&normalizer}, ty)) { - if (!std::any_of(begin(utv), end(utv), isNil)) - return ty; + case ErrorSuppression::Suppress: + break; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, location); + [[fallthrough]]; + case ErrorSuppression::DoNotSuppress: + reportError(OptionalValueAccess{ty}, location); } - if (std::optional strippedUnion = tryStripUnionFromNil(ty)) - { - switch (shouldSuppressErrors(NotNull{&normalizer}, ty)) - { - case ErrorSuppression::Suppress: - break; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, location); - // fallthrough intentional - case ErrorSuppression::DoNotSuppress: - reportError(OptionalValueAccess{ty}, location); - } + return follow(*strippedUnion); + } - return follow(*strippedUnion); - } + return ty; +} - return ty; - } +void TypeChecker2::visitExprName(AstExpr* expr, Location location, const std::string& propName, ValueContext context, TypeId astIndexExprTy) +{ + visit(expr, ValueContext::RValue); + TypeId leftType = stripFromNilAndReport(lookupType(expr), location); + checkIndexTypeFromType(leftType, propName, context, location, astIndexExprTy); +} + +void TypeChecker2::visit(AstExprIndexName* indexName, ValueContext context) +{ + // If we're indexing like _.foo - foo could either be a prop or a string. + visitExprName(indexName->expr, indexName->location, indexName->index.value, context, builtinTypes->stringType); +} - void visitExprName(AstExpr* expr, Location location, const std::string& propName, ValueContext context, TypeId astIndexExprTy) +void TypeChecker2::indexExprMetatableHelper(AstExprIndexExpr* indexExpr, const MetatableType* metaTable, TypeId exprType, TypeId indexType) +{ + if (auto tt = get(follow(metaTable->table)); tt && tt->indexer) + testIsSubtype(indexType, tt->indexer->indexType, indexExpr->index->location); + else if (auto mt = get(follow(metaTable->table))) + indexExprMetatableHelper(indexExpr, mt, exprType, indexType); + else if (auto tmt = get(follow(metaTable->metatable)); tmt && tmt->indexer) + testIsSubtype(indexType, tmt->indexer->indexType, indexExpr->index->location); + else if (auto mtmt = get(follow(metaTable->metatable))) + indexExprMetatableHelper(indexExpr, mtmt, exprType, indexType); + else { - visit(expr, ValueContext::RValue); - TypeId leftType = stripFromNilAndReport(lookupType(expr), location); - checkIndexTypeFromType(leftType, propName, context, location, astIndexExprTy); + LUAU_ASSERT(tt || get(follow(metaTable->table))); + + reportError(CannotExtendTable{exprType, CannotExtendTable::Indexer, "indexer??"}, indexExpr->location); } +} - void visit(AstExprIndexName* indexName, ValueContext context) +void TypeChecker2::visit(AstExprIndexExpr* indexExpr, ValueContext context) +{ + if (auto str = indexExpr->index->as()) { - // If we're indexing like _.foo - foo could either be a prop or a string. - visitExprName(indexName->expr, indexName->location, indexName->index.value, context, builtinTypes->stringType); + TypeId astIndexExprType = lookupType(indexExpr->index); + const std::string stringValue(str->value.data, str->value.size); + visitExprName(indexExpr->expr, indexExpr->location, stringValue, context, astIndexExprType); + return; } - void indexExprMetatableHelper(AstExprIndexExpr* indexExpr, const MetatableType* metaTable, TypeId exprType, TypeId indexType) + visit(indexExpr->expr, ValueContext::RValue); + visit(indexExpr->index, ValueContext::RValue); + + TypeId exprType = follow(lookupType(indexExpr->expr)); + TypeId indexType = follow(lookupType(indexExpr->index)); + + if (auto tt = get(exprType)) { - if (auto tt = get(follow(metaTable->table)); tt && tt->indexer) + if (tt->indexer) testIsSubtype(indexType, tt->indexer->indexType, indexExpr->index->location); - else if (auto mt = get(follow(metaTable->table))) - indexExprMetatableHelper(indexExpr, mt, exprType, indexType); - else if (auto tmt = get(follow(metaTable->metatable)); tmt && tmt->indexer) - testIsSubtype(indexType, tmt->indexer->indexType, indexExpr->index->location); - else if (auto mtmt = get(follow(metaTable->metatable))) - indexExprMetatableHelper(indexExpr, mtmt, exprType, indexType); else - { - LUAU_ASSERT(tt || get(follow(metaTable->table))); - reportError(CannotExtendTable{exprType, CannotExtendTable::Indexer, "indexer??"}, indexExpr->location); - } } - - void visit(AstExprIndexExpr* indexExpr, ValueContext context) + else if (auto mt = get(exprType)) + { + return indexExprMetatableHelper(indexExpr, mt, exprType, indexType); + } + else if (auto cls = get(exprType)) + { + if (cls->indexer) + testIsSubtype(indexType, cls->indexer->indexType, indexExpr->index->location); + else + reportError(DynamicPropertyLookupOnClassesUnsafe{exprType}, indexExpr->location); + } + else if (get(exprType) && isOptional(exprType)) { - if (auto str = indexExpr->index->as()) + switch (shouldSuppressErrors(NotNull{&normalizer}, exprType)) { - TypeId astIndexExprType = lookupType(indexExpr->index); - const std::string stringValue(str->value.data, str->value.size); - visitExprName(indexExpr->expr, indexExpr->location, stringValue, context, astIndexExprType); - return; + case ErrorSuppression::Suppress: + break; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, indexExpr->location); + [[fallthrough]]; + case ErrorSuppression::DoNotSuppress: + reportError(OptionalValueAccess{exprType}, indexExpr->location); } + } + else if (auto ut = get(exprType)) + { + // if all of the types are a table type, the union must be a table, and so we shouldn't error. + if (!std::all_of(begin(ut), end(ut), getTableType)) + reportError(NotATable{exprType}, indexExpr->location); + } + else if (auto it = get(exprType)) + { + // if any of the types are a table type, the intersection must be a table, and so we shouldn't error. + if (!std::any_of(begin(it), end(it), getTableType)) + reportError(NotATable{exprType}, indexExpr->location); + } + else if (get(exprType) || isErrorSuppressing(indexExpr->location, exprType)) + { + // Nothing + } + else + reportError(NotATable{exprType}, indexExpr->location); +} - visit(indexExpr->expr, ValueContext::RValue); - visit(indexExpr->index, ValueContext::RValue); +void TypeChecker2::visit(AstExprFunction* fn) +{ + auto StackPusher = pushStack(fn); - TypeId exprType = follow(lookupType(indexExpr->expr)); - TypeId indexType = follow(lookupType(indexExpr->index)); + visitGenerics(fn->generics, fn->genericPacks); - if (auto tt = get(exprType)) - { - if (tt->indexer) - testIsSubtype(indexType, tt->indexer->indexType, indexExpr->index->location); - else - reportError(CannotExtendTable{exprType, CannotExtendTable::Indexer, "indexer??"}, indexExpr->location); - } - else if (auto mt = get(exprType)) - { - return indexExprMetatableHelper(indexExpr, mt, exprType, indexType); - } - else if (auto cls = get(exprType)) - { - if (cls->indexer) - testIsSubtype(indexType, cls->indexer->indexType, indexExpr->index->location); - else - reportError(DynamicPropertyLookupOnClassesUnsafe{exprType}, indexExpr->location); - } - else if (get(exprType) && isOptional(exprType)) - { - switch (shouldSuppressErrors(NotNull{&normalizer}, exprType)) - { - case ErrorSuppression::Suppress: - break; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, indexExpr->location); - // fallthrough intentional - case ErrorSuppression::DoNotSuppress: - reportError(OptionalValueAccess{exprType}, indexExpr->location); - } - } - else if (auto exprIntersection = get(exprType)) - { - for (TypeId part : exprIntersection) - { - (void)part; - } - } - else if (get(exprType) || isErrorSuppressing(indexExpr->location, exprType)) - { - // Nothing - } - else - reportError(NotATable{exprType}, indexExpr->location); - } + TypeId inferredFnTy = lookupType(fn); + functionDeclStack.push_back(inferredFnTy); - void visit(AstExprFunction* fn) + std::shared_ptr normalizedFnTy = normalizer.normalize(inferredFnTy); + if (!normalizedFnTy) + { + reportError(CodeTooComplex{}, fn->location); + } + else if (get(normalizedFnTy->errors)) { - auto StackPusher = pushStack(fn); + // Nothing + } + else if (!normalizedFnTy->hasFunctions()) + { + ice->ice("Internal error: Lambda has non-function type " + toString(inferredFnTy), fn->location); + } + else + { + if (1 != normalizedFnTy->functions.parts.size()) + ice->ice("Unexpected: Lambda has unexpected type " + toString(inferredFnTy), fn->location); - visitGenerics(fn->generics, fn->genericPacks); + const FunctionType* inferredFtv = get(normalizedFnTy->functions.parts.front()); + LUAU_ASSERT(inferredFtv); - TypeId inferredFnTy = lookupType(fn); - functionDeclStack.push_back(inferredFnTy); + // There is no way to write an annotation for the self argument, so we + // cannot do anything to check it. + auto argIt = begin(inferredFtv->argTypes); + if (fn->self) + ++argIt; - std::shared_ptr normalizedFnTy = normalizer.normalize(inferredFnTy); - if (!normalizedFnTy) - { - reportError(CodeTooComplex{}, fn->location); - } - else if (get(normalizedFnTy->errors)) - { - // Nothing - } - else if (!normalizedFnTy->hasFunctions()) + for (const auto& arg : fn->args) { - ice->ice("Internal error: Lambda has non-function type " + toString(inferredFnTy), fn->location); - } - else - { - if (1 != normalizedFnTy->functions.parts.size()) - ice->ice("Unexpected: Lambda has unexpected type " + toString(inferredFnTy), fn->location); - - const FunctionType* inferredFtv = get(normalizedFnTy->functions.parts.front()); - LUAU_ASSERT(inferredFtv); + if (argIt == end(inferredFtv->argTypes)) + break; - // There is no way to write an annotation for the self argument, so we - // cannot do anything to check it. - auto argIt = begin(inferredFtv->argTypes); - if (fn->self) - ++argIt; + TypeId inferredArgTy = *argIt; - for (const auto& arg : fn->args) + if (arg->annotation) { - if (argIt == end(inferredFtv->argTypes)) - break; + // we need to typecheck any argument annotations themselves. + visit(arg->annotation); - TypeId inferredArgTy = *argIt; + TypeId annotatedArgTy = lookupAnnotation(arg->annotation); + + testIsSubtype(inferredArgTy, annotatedArgTy, arg->location); + } + // Some Luau constructs can result in an argument type being + // reduced to never by inference. In this case, we want to + // report an error at the function, instead of reporting an + // error at every callsite. + if (is(follow(inferredArgTy))) + { + // If the annotation simplified to never, we don't want to + // even look at contributors. + bool explicitlyNever = false; if (arg->annotation) { - // we need to typecheck any argument annotations themselves. - visit(arg->annotation); - TypeId annotatedArgTy = lookupAnnotation(arg->annotation); - - testIsSubtype(inferredArgTy, annotatedArgTy, arg->location); + explicitlyNever = is(annotatedArgTy); } - // Some Luau constructs can result in an argument type being - // reduced to never by inference. In this case, we want to - // report an error at the function, instead of reporting an - // error at every callsite. - if (is(follow(inferredArgTy))) + // Not following here is deliberate: the contribution map is + // keyed by type pointer, but that type pointer has, at some + // point, been transmuted to a bound type pointing to never. + if (const auto contributors = module->upperBoundContributors.find(inferredArgTy); contributors && !explicitlyNever) { - // If the annotation simplified to never, we don't want to - // even look at contributors. - bool explicitlyNever = false; - if (arg->annotation) - { - TypeId annotatedArgTy = lookupAnnotation(arg->annotation); - explicitlyNever = is(annotatedArgTy); - } - - // Not following here is deliberate: the contribution map is - // keyed by type pointer, but that type pointer has, at some - // point, been transmuted to a bound type pointing to never. - if (const auto contributors = module->upperBoundContributors.find(inferredArgTy); contributors && !explicitlyNever) - { - // It's unfortunate that we can't link error messages - // together. For now, this will work. + // It's unfortunate that we can't link error messages + // together. For now, this will work. + reportError( + GenericError{format( + "Parameter '%s' has been reduced to never. This function is not callable with any possible value.", arg->name.value + )}, + arg->location + ); + for (const auto& [site, component] : *contributors) reportError( - GenericError{format( - "Parameter '%s' has been reduced to never. This function is not callable with any possible value.", arg->name.value - )}, - arg->location + ExtraInformation{ + format("Parameter '%s' is required to be a subtype of '%s' here.", arg->name.value, toString(component).c_str()) + }, + site ); - for (const auto& [site, component] : *contributors) - reportError( - ExtraInformation{ - format("Parameter '%s' is required to be a subtype of '%s' here.", arg->name.value, toString(component).c_str()) - }, - site - ); - } } - - ++argIt; } - // we need to typecheck the vararg annotation, if it exists. - if (fn->vararg && fn->varargAnnotation) - visit(fn->varargAnnotation); - - bool reachesImplicitReturn = getFallthrough(fn->body) != nullptr; - if (reachesImplicitReturn && !allowsNoReturnValues(follow(inferredFtv->retTypes))) - reportError(FunctionExitsWithoutReturning{inferredFtv->retTypes}, getEndLocation(fn)); + ++argIt; } - visit(fn->body); + // we need to typecheck the vararg annotation, if it exists. + if (fn->vararg && fn->varargAnnotation) + visit(fn->varargAnnotation); - // we need to typecheck the return annotation itself, if it exists. - if (fn->returnAnnotation) - visit(*fn->returnAnnotation); + bool reachesImplicitReturn = getFallthrough(fn->body) != nullptr; + if (reachesImplicitReturn && !allowsNoReturnValues(follow(inferredFtv->retTypes))) + reportError(FunctionExitsWithoutReturning{inferredFtv->retTypes}, getEndLocation(fn)); + } + visit(fn->body); - // If the function type has a function annotation, we need to see if we can suggest an annotation - if (normalizedFnTy) - { - const FunctionType* inferredFtv = get(normalizedFnTy->functions.parts.front()); - LUAU_ASSERT(inferredFtv); + // we need to typecheck the return annotation itself, if it exists. + if (fn->returnAnnotation) + visit(*fn->returnAnnotation); + + + // If the function type has a function annotation, we need to see if we can suggest an annotation + if (normalizedFnTy) + { + const FunctionType* inferredFtv = get(normalizedFnTy->functions.parts.front()); + LUAU_ASSERT(inferredFtv); - TypeFunctionReductionGuesser guesser{NotNull{&module->internalTypes}, builtinTypes, NotNull{&normalizer}}; - for (TypeId retTy : inferredFtv->retTypes) + TypeFunctionReductionGuesser guesser{NotNull{&module->internalTypes}, builtinTypes, NotNull{&normalizer}}; + for (TypeId retTy : inferredFtv->retTypes) + { + if (get(follow(retTy))) { - if (get(follow(retTy))) - { - TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy); - if (result.shouldRecommendAnnotation && !get(result.guessedReturnType)) - reportError( - ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType}, - fn->location - ); - } + TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy); + if (result.shouldRecommendAnnotation && !get(result.guessedReturnType)) + reportError( + ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType}, fn->location + ); } } - - functionDeclStack.pop_back(); } - void visit(AstExprTable* expr) + functionDeclStack.pop_back(); +} + +void TypeChecker2::visit(AstExprTable* expr) +{ + // TODO! + for (const AstExprTable::Item& item : expr->items) { - // TODO! - for (const AstExprTable::Item& item : expr->items) - { - if (item.key) - visit(item.key, ValueContext::LValue); - visit(item.value, ValueContext::RValue); - } + if (item.key) + visit(item.key, ValueContext::LValue); + visit(item.value, ValueContext::RValue); } +} - void visit(AstExprUnary* expr) - { - visit(expr->expr, ValueContext::RValue); +void TypeChecker2::visit(AstExprUnary* expr) +{ + visit(expr->expr, ValueContext::RValue); - TypeId operandType = lookupType(expr->expr); - TypeId resultType = lookupType(expr); + TypeId operandType = lookupType(expr->expr); + TypeId resultType = lookupType(expr); - if (isErrorSuppressing(expr->expr->location, operandType)) - return; + if (isErrorSuppressing(expr->expr->location, operandType)) + return; - if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end()) + if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end()) + { + std::optional mm = findMetatableEntry(builtinTypes, module->errors, operandType, it->second, expr->location); + if (mm) { - std::optional mm = findMetatableEntry(builtinTypes, module->errors, operandType, it->second, expr->location); - if (mm) + if (const FunctionType* ftv = get(follow(*mm))) { - if (const FunctionType* ftv = get(follow(*mm))) + if (std::optional ret = first(ftv->retTypes)) { - if (std::optional ret = first(ftv->retTypes)) - { - if (expr->op == AstExprUnary::Op::Len) - { - testIsSubtype(follow(*ret), builtinTypes->numberType, expr->location); - } - } - else + if (expr->op == AstExprUnary::Op::Len) { - reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location); - } - - std::optional firstArg = first(ftv->argTypes); - if (!firstArg) - { - reportError(GenericError{"__unm metamethod must accept one argument"}, expr->location); - return; + testIsSubtype(follow(*ret), builtinTypes->numberType, expr->location); } - - TypePackId expectedArgs = module->internalTypes.addTypePack({operandType}); - TypePackId expectedRet = module->internalTypes.addTypePack({resultType}); - - TypeId expectedFunction = module->internalTypes.addType(FunctionType{expectedArgs, expectedRet}); - - bool success = testIsSubtype(*mm, expectedFunction, expr->location); - if (!success) - return; + } + else + { + reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location); } - return; - } - } + std::optional firstArg = first(ftv->argTypes); + if (!firstArg) + { + reportError(GenericError{"__unm metamethod must accept one argument"}, expr->location); + return; + } - if (expr->op == AstExprUnary::Op::Len) - { - DenseHashSet seen{nullptr}; - int recursionCount = 0; - std::shared_ptr nty = normalizer.normalize(operandType); + TypePackId expectedArgs = module->internalTypes.addTypePack({operandType}); + TypePackId expectedRet = module->internalTypes.addTypePack({resultType}); - if (nty && nty->shouldSuppressErrors()) - return; + TypeId expectedFunction = module->internalTypes.addType(FunctionType{expectedArgs, expectedRet}); - switch (normalizer.isInhabited(nty.get())) - { - case NormalizationResult::True: - break; - case NormalizationResult::False: - return; - case NormalizationResult::HitLimits: - reportError(NormalizationTooComplex{}, expr->location); + bool success = testIsSubtype(*mm, expectedFunction, expr->location); + if (!success) return; } - if (!hasLength(operandType, seen, &recursionCount)) - { - if (isOptional(operandType)) - reportError(OptionalValueAccess{operandType}, expr->location); - else - reportError(NotATable{operandType}, expr->location); - } - } - else if (expr->op == AstExprUnary::Op::Minus) - { - testIsSubtype(operandType, builtinTypes->numberType, expr->location); - } - else if (expr->op == AstExprUnary::Op::Not) - { - } - else - { - LUAU_ASSERT(!"Unhandled unary operator"); + return; } } - TypeId visit(AstExprBinary* expr, AstNode* overrideKey = nullptr) + if (expr->op == AstExprUnary::Op::Len) { - visit(expr->left, ValueContext::RValue); - visit(expr->right, ValueContext::RValue); + DenseHashSet seen{nullptr}; + int recursionCount = 0; + std::shared_ptr nty = normalizer.normalize(operandType); - NotNull scope = stack.back(); - - bool isEquality = expr->op == AstExprBinary::Op::CompareEq || expr->op == AstExprBinary::Op::CompareNe; - bool isComparison = expr->op >= AstExprBinary::Op::CompareEq && expr->op <= AstExprBinary::Op::CompareGe; - bool isLogical = expr->op == AstExprBinary::Op::And || expr->op == AstExprBinary::Op::Or; + if (nty && nty->shouldSuppressErrors()) + return; - TypeId leftType = follow(lookupType(expr->left)); - TypeId rightType = follow(lookupType(expr->right)); - TypeId expectedResult = follow(lookupType(expr)); - - if (get(expectedResult)) + switch (normalizer.isInhabited(nty.get())) { - checkForInternalTypeFunction(expectedResult, expr->location); - return expectedResult; + case NormalizationResult::True: + break; + case NormalizationResult::False: + return; + case NormalizationResult::HitLimits: + reportError(NormalizationTooComplex{}, expr->location); + return; } - if (expr->op == AstExprBinary::Op::Or) + if (!hasLength(operandType, seen, &recursionCount)) { - leftType = stripNil(builtinTypes, module->internalTypes, leftType); + if (isOptional(operandType)) + reportError(OptionalValueAccess{operandType}, expr->location); + else + reportError(NotATable{operandType}, expr->location); } + } + else if (expr->op == AstExprUnary::Op::Minus) + { + testIsSubtype(operandType, builtinTypes->numberType, expr->location); + } + else if (expr->op == AstExprUnary::Op::Not) + { + } + else + { + LUAU_ASSERT(!"Unhandled unary operator"); + } +} - std::shared_ptr normLeft = normalizer.normalize(leftType); - std::shared_ptr normRight = normalizer.normalize(rightType); +TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey) +{ + visit(expr->left, ValueContext::RValue); + visit(expr->right, ValueContext::RValue); - bool isStringOperation = - (normLeft ? normLeft->isSubtypeOfString() : isString(leftType)) && (normRight ? normRight->isSubtypeOfString() : isString(rightType)); - leftType = follow(leftType); - if (get(leftType) || get(leftType) || get(leftType)) - return leftType; - else if (get(rightType) || get(rightType) || get(rightType)) - return rightType; - else if ((normLeft && normLeft->shouldSuppressErrors()) || (normRight && normRight->shouldSuppressErrors())) - return builtinTypes->anyType; // we can't say anything better if it's error suppressing but not any or error alone. + NotNull scope = stack.back(); - if ((get(leftType) || get(leftType) || get(leftType)) && !isEquality && !isLogical) - { - auto name = getIdentifierOfBaseVar(expr->left); - reportError( - CannotInferBinaryOperation{ - expr->op, name, isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation - }, - expr->location - ); - return leftType; - } + bool isEquality = expr->op == AstExprBinary::Op::CompareEq || expr->op == AstExprBinary::Op::CompareNe; + bool isComparison = expr->op >= AstExprBinary::Op::CompareEq && expr->op <= AstExprBinary::Op::CompareGe; + bool isLogical = expr->op == AstExprBinary::Op::And || expr->op == AstExprBinary::Op::Or; - NormalizationResult typesHaveIntersection = normalizer.isIntersectionInhabited(leftType, rightType); - if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end()) - { - std::optional leftMt = getMetatable(leftType, builtinTypes); - std::optional rightMt = getMetatable(rightType, builtinTypes); - bool matches = leftMt == rightMt; + TypeId leftType = follow(lookupType(expr->left)); + TypeId rightType = follow(lookupType(expr->right)); + TypeId expectedResult = follow(lookupType(expr)); + + if (get(expectedResult)) + { + checkForInternalTypeFunction(expectedResult, expr->location); + return expectedResult; + } + + if (expr->op == AstExprBinary::Op::Or) + { + leftType = stripNil(builtinTypes, module->internalTypes, leftType); + } + + std::shared_ptr normLeft = normalizer.normalize(leftType); + std::shared_ptr normRight = normalizer.normalize(rightType); + + bool isStringOperation = + (normLeft ? normLeft->isSubtypeOfString() : isString(leftType)) && (normRight ? normRight->isSubtypeOfString() : isString(rightType)); + leftType = follow(leftType); + if (get(leftType) || get(leftType) || get(leftType)) + return leftType; + else if (get(rightType) || get(rightType) || get(rightType)) + return rightType; + else if ((normLeft && normLeft->shouldSuppressErrors()) || (normRight && normRight->shouldSuppressErrors())) + return builtinTypes->anyType; // we can't say anything better if it's error suppressing but not any or error alone. + + if ((get(leftType) || get(leftType) || get(leftType)) && !isEquality && !isLogical) + { + auto name = getIdentifierOfBaseVar(expr->left); + reportError( + CannotInferBinaryOperation{ + expr->op, name, isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation + }, + expr->location + ); + return leftType; + } + + NormalizationResult typesHaveIntersection = normalizer.isIntersectionInhabited(leftType, rightType); + if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end()) + { + std::optional leftMt = getMetatable(leftType, builtinTypes); + std::optional rightMt = getMetatable(rightType, builtinTypes); + bool matches = leftMt == rightMt; - if (isEquality && !matches) + if (isEquality && !matches) + { + auto testUnion = [&matches, builtinTypes = this->builtinTypes](const UnionType* utv, std::optional otherMt) { - auto testUnion = [&matches, builtinTypes = this->builtinTypes](const UnionType* utv, std::optional otherMt) + for (TypeId option : utv) { - for (TypeId option : utv) + if (getMetatable(follow(option), builtinTypes) == otherMt) { - if (getMetatable(follow(option), builtinTypes) == otherMt) - { - matches = true; - break; - } + matches = true; + break; } - }; - - if (const UnionType* utv = get(leftType); utv && rightMt) - { - testUnion(utv, rightMt); } + }; - if (const UnionType* utv = get(rightType); utv && leftMt && !matches) - { - testUnion(utv, leftMt); - } - } - - // If we're working with things that are not tables, the metatable comparisons above are a little excessive - // It's ok for one type to have a meta table and the other to not. In that case, we should fall back on - // checking if the intersection of the types is inhabited. If `typesHaveIntersection` failed due to limits, - // TODO: Maybe add more checks here (e.g. for functions, classes, etc) - if (!(get(leftType) || get(rightType))) - if (!leftMt.has_value() || !rightMt.has_value()) - matches = matches || typesHaveIntersection != NormalizationResult::False; - - if (!matches && isComparison) + if (const UnionType* utv = get(leftType); utv && rightMt) { - reportError( - GenericError{format( - "Types %s and %s cannot be compared with %s because they do not have the same metatable", - toString(leftType).c_str(), - toString(rightType).c_str(), - toString(expr->op).c_str() - )}, - expr->location - ); - - return builtinTypes->errorRecoveryType(); + testUnion(utv, rightMt); } - std::optional mm; - if (std::optional leftMm = findMetatableEntry(builtinTypes, module->errors, leftType, it->second, expr->left->location)) - mm = leftMm; - else if (std::optional rightMm = findMetatableEntry(builtinTypes, module->errors, rightType, it->second, expr->right->location)) + if (const UnionType* utv = get(rightType); utv && leftMt && !matches) { - mm = rightMm; - std::swap(leftType, rightType); + testUnion(utv, leftMt); } + } - if (mm) - { - AstNode* key = expr; - if (overrideKey != nullptr) - key = overrideKey; + // If we're working with things that are not tables, the metatable comparisons above are a little excessive + // It's ok for one type to have a meta table and the other to not. In that case, we should fall back on + // checking if the intersection of the types is inhabited. If `typesHaveIntersection` failed due to limits, + // TODO: Maybe add more checks here (e.g. for functions, classes, etc) + if (!(get(leftType) || get(rightType))) + if (!leftMt.has_value() || !rightMt.has_value()) + matches = matches || typesHaveIntersection != NormalizationResult::False; - TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(key); - if (!selectedOverloadTy) - { - // reportError(CodeTooComplex{}, expr->location); - // was handled by a type function - return expectedResult; - } - - else if (const FunctionType* ftv = get(follow(*selectedOverloadTy))) - { - TypePackId expectedArgs; - // For >= and > we invoke __lt and __le respectively with - // swapped argument ordering. - if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt) - { - expectedArgs = module->internalTypes.addTypePack({rightType, leftType}); - } - else - { - expectedArgs = module->internalTypes.addTypePack({leftType, rightType}); - } + if (!matches && isComparison) + { + reportError( + GenericError{format( + "Types %s and %s cannot be compared with %s because they do not have the same metatable", + toString(leftType).c_str(), + toString(rightType).c_str(), + toString(expr->op).c_str() + )}, + expr->location + ); - TypePackId expectedRets; - if (expr->op == AstExprBinary::CompareEq || expr->op == AstExprBinary::CompareNe || expr->op == AstExprBinary::CompareGe || - expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::Op::CompareLe || expr->op == AstExprBinary::Op::CompareLt) - { - expectedRets = module->internalTypes.addTypePack({builtinTypes->booleanType}); - } - else - { - expectedRets = module->internalTypes.addTypePack({module->internalTypes.freshType(scope, TypeLevel{})}); - } + return builtinTypes->errorRecoveryType(); + } - TypeId expectedTy = module->internalTypes.addType(FunctionType(expectedArgs, expectedRets)); + std::optional mm; + if (std::optional leftMm = findMetatableEntry(builtinTypes, module->errors, leftType, it->second, expr->left->location)) + mm = leftMm; + else if (std::optional rightMm = findMetatableEntry(builtinTypes, module->errors, rightType, it->second, expr->right->location)) + { + mm = rightMm; + std::swap(leftType, rightType); + } - testIsSubtype(follow(*mm), expectedTy, expr->location); + if (mm) + { + AstNode* key = expr; + if (overrideKey != nullptr) + key = overrideKey; - std::optional ret = first(ftv->retTypes); - if (ret) - { - if (isComparison) - { - if (!isBoolean(follow(*ret))) - { - reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location); - } + TypeId* selectedOverloadTy = module->astOverloadResolvedTypes.find(key); + if (!selectedOverloadTy) + { + // reportError(CodeTooComplex{}, expr->location); + // was handled by a type function + return expectedResult; + } - return builtinTypes->booleanType; - } - else - { - return follow(*ret); - } - } - else - { - if (isComparison) - { - reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location); - } - else - { - reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location); - } + else if (const FunctionType* ftv = get(follow(*selectedOverloadTy))) + { + TypePackId expectedArgs; + // For >= and > we invoke __lt and __le respectively with + // swapped argument ordering. + if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt) + { + expectedArgs = module->internalTypes.addTypePack({rightType, leftType}); + } + else + { + expectedArgs = module->internalTypes.addTypePack({leftType, rightType}); + } - return builtinTypes->errorRecoveryType(); - } + TypePackId expectedRets; + if (expr->op == AstExprBinary::CompareEq || expr->op == AstExprBinary::CompareNe || expr->op == AstExprBinary::CompareGe || + expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::Op::CompareLe || expr->op == AstExprBinary::Op::CompareLt) + { + expectedRets = module->internalTypes.addTypePack({builtinTypes->booleanType}); } else { - reportError(CannotCallNonFunction{*mm}, expr->location); + expectedRets = module->internalTypes.addTypePack({module->internalTypes.freshType(scope, TypeLevel{})}); } - return builtinTypes->errorRecoveryType(); - } - // If this is a string comparison, or a concatenation of strings, we - // want to fall through to primitive behavior. - else if (!isEquality && !(isStringOperation && (expr->op == AstExprBinary::Op::Concat || isComparison))) - { - if ((leftMt && !isString(leftType)) || (rightMt && !isString(rightType))) + TypeId expectedTy = module->internalTypes.addType(FunctionType(expectedArgs, expectedRets)); + + testIsSubtype(follow(*mm), expectedTy, expr->location); + + std::optional ret = first(ftv->retTypes); + if (ret) { if (isComparison) { - reportError( - GenericError{format( - "Types '%s' and '%s' cannot be compared with %s because neither type's metatable has a '%s' metamethod", - toString(leftType).c_str(), - toString(rightType).c_str(), - toString(expr->op).c_str(), - it->second - )}, - expr->location - ); + if (!isBoolean(follow(*ret))) + { + reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location); + } + + return builtinTypes->booleanType; } else { - reportError( - GenericError{format( - "Operator %s is not applicable for '%s' and '%s' because neither type's metatable has a '%s' metamethod", - toString(expr->op).c_str(), - toString(leftType).c_str(), - toString(rightType).c_str(), - it->second - )}, - expr->location - ); + return follow(*ret); } - - return builtinTypes->errorRecoveryType(); } - else if (!leftMt && !rightMt && (get(leftType) || get(rightType))) + else { if (isComparison) { - reportError( - GenericError{format( - "Types '%s' and '%s' cannot be compared with %s because neither type has a metatable", - toString(leftType).c_str(), - toString(rightType).c_str(), - toString(expr->op).c_str() - )}, - expr->location - ); + reportError(GenericError{format("Metamethod '%s' must return a boolean", it->second)}, expr->location); } else { - reportError( - GenericError{format( - "Operator %s is not applicable for '%s' and '%s' because neither type has a metatable", - toString(expr->op).c_str(), - toString(leftType).c_str(), - toString(rightType).c_str() - )}, - expr->location - ); + reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location); } return builtinTypes->errorRecoveryType(); } } - } - - switch (expr->op) - { - case AstExprBinary::Op::Add: - case AstExprBinary::Op::Sub: - case AstExprBinary::Op::Mul: - case AstExprBinary::Op::Div: - case AstExprBinary::Op::FloorDiv: - case AstExprBinary::Op::Pow: - case AstExprBinary::Op::Mod: - testIsSubtype(leftType, builtinTypes->numberType, expr->left->location); - testIsSubtype(rightType, builtinTypes->numberType, expr->right->location); - - return builtinTypes->numberType; - case AstExprBinary::Op::Concat: - testIsSubtype(leftType, builtinTypes->stringType, expr->left->location); - testIsSubtype(rightType, builtinTypes->stringType, expr->right->location); - - return builtinTypes->stringType; - case AstExprBinary::Op::CompareGe: - case AstExprBinary::Op::CompareGt: - case AstExprBinary::Op::CompareLe: - case AstExprBinary::Op::CompareLt: - { - if (normLeft && normLeft->shouldSuppressErrors()) - return builtinTypes->booleanType; - - // if we're comparing against an uninhabited type, it's unobservable that the comparison did not run - if (normLeft && normalizer.isInhabited(normLeft.get()) == NormalizationResult::False) - return builtinTypes->booleanType; - - if (normLeft && normLeft->isExactlyNumber()) - { - testIsSubtype(rightType, builtinTypes->numberType, expr->right->location); - return builtinTypes->booleanType; - } - - if (normLeft && normLeft->isSubtypeOfString()) + else { - testIsSubtype(rightType, builtinTypes->stringType, expr->right->location); - return builtinTypes->booleanType; + reportError(CannotCallNonFunction{*mm}, expr->location); } - reportError( - GenericError{format( - "Types '%s' and '%s' cannot be compared with relational operator %s", - toString(leftType).c_str(), - toString(rightType).c_str(), - toString(expr->op).c_str() - )}, - expr->location - ); return builtinTypes->errorRecoveryType(); } + // If this is a string comparison, or a concatenation of strings, we + // want to fall through to primitive behavior. + else if (!isEquality && !(isStringOperation && (expr->op == AstExprBinary::Op::Concat || isComparison))) + { + if ((leftMt && !isString(leftType)) || (rightMt && !isString(rightType))) + { + if (isComparison) + { + reportError( + GenericError{format( + "Types '%s' and '%s' cannot be compared with %s because neither type's metatable has a '%s' metamethod", + toString(leftType).c_str(), + toString(rightType).c_str(), + toString(expr->op).c_str(), + it->second + )}, + expr->location + ); + } + else + { + reportError( + GenericError{format( + "Operator %s is not applicable for '%s' and '%s' because neither type's metatable has a '%s' metamethod", + toString(expr->op).c_str(), + toString(leftType).c_str(), + toString(rightType).c_str(), + it->second + )}, + expr->location + ); + } - case AstExprBinary::Op::And: - case AstExprBinary::Op::Or: - case AstExprBinary::Op::CompareEq: - case AstExprBinary::Op::CompareNe: - // Ugly case: we don't care about this possibility, because a - // compound assignment will never exist with one of these operators. - return builtinTypes->anyType; - default: - // Unhandled AstExprBinary::Op possibility. - LUAU_ASSERT(false); - return builtinTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); + } + else if (!leftMt && !rightMt && (get(leftType) || get(rightType))) + { + if (isComparison) + { + reportError( + GenericError{format( + "Types '%s' and '%s' cannot be compared with %s because neither type has a metatable", + toString(leftType).c_str(), + toString(rightType).c_str(), + toString(expr->op).c_str() + )}, + expr->location + ); + } + else + { + reportError( + GenericError{format( + "Operator %s is not applicable for '%s' and '%s' because neither type has a metatable", + toString(expr->op).c_str(), + toString(leftType).c_str(), + toString(rightType).c_str() + )}, + expr->location + ); + } + + return builtinTypes->errorRecoveryType(); + } } } - void visit(AstExprTypeAssertion* expr) + switch (expr->op) { - visit(expr->expr, ValueContext::RValue); - visit(expr->annotation); + case AstExprBinary::Op::Add: + case AstExprBinary::Op::Sub: + case AstExprBinary::Op::Mul: + case AstExprBinary::Op::Div: + case AstExprBinary::Op::FloorDiv: + case AstExprBinary::Op::Pow: + case AstExprBinary::Op::Mod: + testIsSubtype(leftType, builtinTypes->numberType, expr->left->location); + testIsSubtype(rightType, builtinTypes->numberType, expr->right->location); - TypeId annotationType = lookupAnnotation(expr->annotation); - TypeId computedType = lookupType(expr->expr); + return builtinTypes->numberType; + case AstExprBinary::Op::Concat: + testIsSubtype(leftType, builtinTypes->stringType, expr->left->location); + testIsSubtype(rightType, builtinTypes->stringType, expr->right->location); - switch (shouldSuppressErrors(NotNull{&normalizer}, computedType).orElse(shouldSuppressErrors(NotNull{&normalizer}, annotationType))) - { - case ErrorSuppression::Suppress: - return; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, expr->location); - return; - case ErrorSuppression::DoNotSuppress: - break; - } + return builtinTypes->stringType; + case AstExprBinary::Op::CompareGe: + case AstExprBinary::Op::CompareGt: + case AstExprBinary::Op::CompareLe: + case AstExprBinary::Op::CompareLt: + { + if (normLeft && normLeft->shouldSuppressErrors()) + return builtinTypes->booleanType; + + // if we're comparing against an uninhabited type, it's unobservable that the comparison did not run + if (normLeft && normalizer.isInhabited(normLeft.get()) == NormalizationResult::False) + return builtinTypes->booleanType; - switch (normalizer.isInhabited(computedType)) + if (normLeft && normLeft->isExactlyNumber()) { - case NormalizationResult::True: - break; - case NormalizationResult::False: - return; - case NormalizationResult::HitLimits: - reportError(NormalizationTooComplex{}, expr->location); - return; + testIsSubtype(rightType, builtinTypes->numberType, expr->right->location); + return builtinTypes->booleanType; } - switch (normalizer.isIntersectionInhabited(computedType, annotationType)) + if (normLeft && normLeft->isSubtypeOfString()) { - case NormalizationResult::True: - return; - case NormalizationResult::False: - reportError(TypesAreUnrelated{computedType, annotationType}, expr->location); - break; - case NormalizationResult::HitLimits: - reportError(NormalizationTooComplex{}, expr->location); - break; - } + testIsSubtype(rightType, builtinTypes->stringType, expr->right->location); + return builtinTypes->booleanType; + } + + reportError( + GenericError{format( + "Types '%s' and '%s' cannot be compared with relational operator %s", + toString(leftType).c_str(), + toString(rightType).c_str(), + toString(expr->op).c_str() + )}, + expr->location + ); + return builtinTypes->errorRecoveryType(); + } + + case AstExprBinary::Op::And: + case AstExprBinary::Op::Or: + case AstExprBinary::Op::CompareEq: + case AstExprBinary::Op::CompareNe: + // Ugly case: we don't care about this possibility, because a + // compound assignment will never exist with one of these operators. + return builtinTypes->anyType; + default: + // Unhandled AstExprBinary::Op possibility. + LUAU_ASSERT(false); + return builtinTypes->errorRecoveryType(); } +} - void visit(AstExprIfElse* expr) +void TypeChecker2::visit(AstExprTypeAssertion* expr) +{ + visit(expr->expr, ValueContext::RValue); + visit(expr->annotation); + + TypeId annotationType = lookupAnnotation(expr->annotation); + TypeId computedType = lookupType(expr->expr); + + switch (shouldSuppressErrors(NotNull{&normalizer}, computedType).orElse(shouldSuppressErrors(NotNull{&normalizer}, annotationType))) { - // TODO! - visit(expr->condition, ValueContext::RValue); - visit(expr->trueExpr, ValueContext::RValue); - visit(expr->falseExpr, ValueContext::RValue); + case ErrorSuppression::Suppress: + return; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, expr->location); + return; + case ErrorSuppression::DoNotSuppress: + break; } - void visit(AstExprInterpString* interpString) + switch (normalizer.isInhabited(computedType)) { - for (AstExpr* expr : interpString->expressions) - visit(expr, ValueContext::RValue); + case NormalizationResult::True: + break; + case NormalizationResult::False: + return; + case NormalizationResult::HitLimits: + reportError(NormalizationTooComplex{}, expr->location); + return; } - void visit(AstExprError* expr) + switch (normalizer.isIntersectionInhabited(computedType, annotationType)) { - // TODO! - for (AstExpr* e : expr->expressions) - visit(e, ValueContext::RValue); + case NormalizationResult::True: + return; + case NormalizationResult::False: + reportError(TypesAreUnrelated{computedType, annotationType}, expr->location); + break; + case NormalizationResult::HitLimits: + reportError(NormalizationTooComplex{}, expr->location); + break; } +} - /** Extract a TypeId for the first type of the provided pack. - * - * Note that this may require modifying some types. I hope this doesn't cause problems! - */ - TypeId flattenPack(TypePackId pack) - { - pack = follow(pack); +void TypeChecker2::visit(AstExprIfElse* expr) +{ + // TODO! + visit(expr->condition, ValueContext::RValue); + visit(expr->trueExpr, ValueContext::RValue); + visit(expr->falseExpr, ValueContext::RValue); +} - if (auto fst = first(pack, /*ignoreHiddenVariadics*/ false)) - return *fst; - else if (auto ftp = get(pack)) - { - TypeId result = module->internalTypes.addType(FreeType{ftp->scope}); - TypePackId freeTail = module->internalTypes.addTypePack(FreeTypePack{ftp->scope}); +void TypeChecker2::visit(AstExprInterpString* interpString) +{ + for (AstExpr* expr : interpString->expressions) + visit(expr, ValueContext::RValue); +} - TypePack* resultPack = emplaceTypePack(asMutable(pack)); - resultPack->head.assign(1, result); - resultPack->tail = freeTail; +void TypeChecker2::visit(AstExprError* expr) +{ + // TODO! + for (AstExpr* e : expr->expressions) + visit(e, ValueContext::RValue); +} - return result; - } - else if (get(pack)) - return builtinTypes->errorRecoveryType(); - else if (finite(pack) && size(pack) == 0) - return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil` - else - ice->ice("flattenPack got a weird pack!"); - } +TypeId TypeChecker2::flattenPack(TypePackId pack) +{ + pack = follow(pack); - void visitGenerics(AstArray generics, AstArray genericPacks) + if (auto fst = first(pack, /*ignoreHiddenVariadics*/ false)) + return *fst; + else if (auto ftp = get(pack)) { - DenseHashSet seen{AstName{}}; + TypeId result = module->internalTypes.addType(FreeType{ftp->scope}); + TypePackId freeTail = module->internalTypes.addTypePack(FreeTypePack{ftp->scope}); - for (const auto& g : generics) - { - if (seen.contains(g.name)) - reportError(DuplicateGenericParameter{g.name.value}, g.location); - else - seen.insert(g.name); + TypePack* resultPack = emplaceTypePack(asMutable(pack)); + resultPack->head.assign(1, result); + resultPack->tail = freeTail; - if (g.defaultValue) - visit(g.defaultValue); - } + return result; + } + else if (get(pack)) + return builtinTypes->errorRecoveryType(); + else if (finite(pack) && size(pack) == 0) + return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil` + else + ice->ice("flattenPack got a weird pack!"); +} - for (const auto& g : genericPacks) - { - if (seen.contains(g.name)) - reportError(DuplicateGenericParameter{g.name.value}, g.location); - else - seen.insert(g.name); +void TypeChecker2::visitGenerics(AstArray generics, AstArray genericPacks) +{ + DenseHashSet seen{AstName{}}; - if (g.defaultValue) - visit(g.defaultValue); - } + for (const auto& g : generics) + { + if (seen.contains(g.name)) + reportError(DuplicateGenericParameter{g.name.value}, g.location); + else + seen.insert(g.name); + + if (g.defaultValue) + visit(g.defaultValue); } - void visit(AstType* ty) + for (const auto& g : genericPacks) { - TypeId* resolvedTy = module->astResolvedTypes.find(ty); - if (resolvedTy) - checkForTypeFunctionInhabitance(follow(*resolvedTy), ty->location); + if (seen.contains(g.name)) + reportError(DuplicateGenericParameter{g.name.value}, g.location); + else + seen.insert(g.name); - if (auto t = ty->as()) - return visit(t); - else if (auto t = ty->as()) - return visit(t); - else if (auto t = ty->as()) - return visit(t); - else if (auto t = ty->as()) - return visit(t); - else if (auto t = ty->as()) - return visit(t); - else if (auto t = ty->as()) - return visit(t); + if (g.defaultValue) + visit(g.defaultValue); } +} - void visit(AstTypeReference* ty) - { - // No further validation is necessary in this case. The main logic for - // _luau_print is contained in lookupAnnotation. - if (FFlag::DebugLuauMagicTypes && ty->name == "_luau_print") - return; +void TypeChecker2::visit(AstType* ty) +{ + TypeId* resolvedTy = module->astResolvedTypes.find(ty); + if (resolvedTy) + checkForTypeFunctionInhabitance(follow(*resolvedTy), ty->location); + + if (auto t = ty->as()) + return visit(t); + else if (auto t = ty->as()) + return visit(t); + else if (auto t = ty->as()) + return visit(t); + else if (auto t = ty->as()) + return visit(t); + else if (auto t = ty->as()) + return visit(t); + else if (auto t = ty->as()) + return visit(t); +} - for (const AstTypeOrPack& param : ty->parameters) - { - if (param.type) - visit(param.type); - else - visit(param.typePack); - } +void TypeChecker2::visit(AstTypeReference* ty) +{ + // No further validation is necessary in this case. The main logic for + // _luau_print is contained in lookupAnnotation. + if (FFlag::DebugLuauMagicTypes && ty->name == "_luau_print") + return; + + for (const AstTypeOrPack& param : ty->parameters) + { + if (param.type) + visit(param.type); + else + visit(param.typePack); + } - Scope* scope = findInnermostScope(ty->location); - LUAU_ASSERT(scope); + Scope* scope = findInnermostScope(ty->location); + LUAU_ASSERT(scope); - std::optional alias = - (ty->prefix) ? scope->lookupImportedType(ty->prefix->value, ty->name.value) : scope->lookupType(ty->name.value); + std::optional alias = (ty->prefix) ? scope->lookupImportedType(ty->prefix->value, ty->name.value) : scope->lookupType(ty->name.value); - if (alias.has_value()) - { - size_t typesRequired = alias->typeParams.size(); - size_t packsRequired = alias->typePackParams.size(); + if (alias.has_value()) + { + size_t typesRequired = alias->typeParams.size(); + size_t packsRequired = alias->typePackParams.size(); - bool hasDefaultTypes = std::any_of( - alias->typeParams.begin(), - alias->typeParams.end(), - [](auto&& el) - { - return el.defaultValue.has_value(); - } - ); + bool hasDefaultTypes = std::any_of( + alias->typeParams.begin(), + alias->typeParams.end(), + [](auto&& el) + { + return el.defaultValue.has_value(); + } + ); - bool hasDefaultPacks = std::any_of( - alias->typePackParams.begin(), - alias->typePackParams.end(), - [](auto&& el) - { - return el.defaultValue.has_value(); - } - ); + bool hasDefaultPacks = std::any_of( + alias->typePackParams.begin(), + alias->typePackParams.end(), + [](auto&& el) + { + return el.defaultValue.has_value(); + } + ); - if (!ty->hasParameterList) + if (!ty->hasParameterList) + { + if ((!alias->typeParams.empty() && !hasDefaultTypes) || (!alias->typePackParams.empty() && !hasDefaultPacks)) { - if ((!alias->typeParams.empty() && !hasDefaultTypes) || (!alias->typePackParams.empty() && !hasDefaultPacks)) - { - reportError(GenericError{"Type parameter list is required"}, ty->location); - } + reportError(GenericError{"Type parameter list is required"}, ty->location); } + } - size_t typesProvided = 0; - size_t extraTypes = 0; - size_t packsProvided = 0; + size_t typesProvided = 0; + size_t extraTypes = 0; + size_t packsProvided = 0; - for (const AstTypeOrPack& p : ty->parameters) + for (const AstTypeOrPack& p : ty->parameters) + { + if (p.type) { - if (p.type) + if (packsProvided != 0) { - if (packsProvided != 0) - { - reportError(GenericError{"Type parameters must come before type pack parameters"}, ty->location); - continue; - } + reportError(GenericError{"Type parameters must come before type pack parameters"}, ty->location); + continue; + } - if (typesProvided < typesRequired) - { - typesProvided += 1; - } - else - { - extraTypes += 1; - } + if (typesProvided < typesRequired) + { + typesProvided += 1; } - else if (p.typePack) + else { - std::optional tp = lookupPackAnnotation(p.typePack); - if (!tp.has_value()) - continue; - - if (typesProvided < typesRequired && size(*tp) == 1 && finite(*tp) && first(*tp)) - { - typesProvided += 1; - } - else - { - packsProvided += 1; - } + extraTypes += 1; } } - - if (extraTypes != 0 && packsProvided == 0) + else if (p.typePack) { - // Extra types are only collected into a pack if a pack is expected - if (packsRequired != 0) - packsProvided += 1; - else - typesProvided += extraTypes; - } + std::optional tp = lookupPackAnnotation(p.typePack); + if (!tp.has_value()) + continue; - for (size_t i = typesProvided; i < typesRequired; ++i) - { - if (alias->typeParams[i].defaultValue) + if (typesProvided < typesRequired && size(*tp) == 1 && finite(*tp) && first(*tp)) { typesProvided += 1; } - } - - for (size_t i = packsProvided; i < packsRequired; ++i) - { - if (alias->typePackParams[i].defaultValue) + else { packsProvided += 1; } } + } - if (extraTypes == 0 && packsProvided + 1 == packsRequired) - { + if (extraTypes != 0 && packsProvided == 0) + { + // Extra types are only collected into a pack if a pack is expected + if (packsRequired != 0) packsProvided += 1; - } + else + typesProvided += extraTypes; + } - if (typesProvided != typesRequired || packsProvided != packsRequired) + for (size_t i = typesProvided; i < typesRequired; ++i) + { + if (alias->typeParams[i].defaultValue) { - reportError( - IncorrectGenericParameterCount{ - /* name */ ty->name.value, - /* typeFun */ *alias, - /* actualParameters */ typesProvided, - /* actualPackParameters */ packsProvided, - }, - ty->location - ); + typesProvided += 1; } } - else + + for (size_t i = packsProvided; i < packsRequired; ++i) { - if (scope->lookupPack(ty->name.value)) + if (alias->typePackParams[i].defaultValue) { - reportError( - SwappedGenericTypeParameter{ - ty->name.value, - SwappedGenericTypeParameter::Kind::Type, - }, - ty->location - ); - } - else - { - std::string symbol = ""; - if (ty->prefix) - { - symbol += (*(ty->prefix)).value; - symbol += "."; - } - symbol += ty->name.value; - - reportError(UnknownSymbol{symbol, UnknownSymbol::Context::Type}, ty->location); + packsProvided += 1; } } - } - - void visit(AstTypeTable* table) - { - // TODO! - for (const AstTableProp& prop : table->props) - visit(prop.type); + if (extraTypes == 0 && packsProvided + 1 == packsRequired) + { + packsProvided += 1; + } - if (table->indexer) + if (typesProvided != typesRequired || packsProvided != packsRequired) { - visit(table->indexer->indexType); - visit(table->indexer->resultType); + reportError( + IncorrectGenericParameterCount{ + /* name */ ty->name.value, + /* typeFun */ *alias, + /* actualParameters */ typesProvided, + /* actualPackParameters */ packsProvided, + }, + ty->location + ); } } - - void visit(AstTypeFunction* ty) + else { - visitGenerics(ty->generics, ty->genericPacks); - visit(ty->argTypes); - visit(ty->returnTypes); - } + if (scope->lookupPack(ty->name.value)) + { + reportError( + SwappedGenericTypeParameter{ + ty->name.value, + SwappedGenericTypeParameter::Kind::Type, + }, + ty->location + ); + } + else + { + std::string symbol = ""; + if (ty->prefix) + { + symbol += (*(ty->prefix)).value; + symbol += "."; + } + symbol += ty->name.value; - void visit(AstTypeTypeof* ty) - { - visit(ty->expr, ValueContext::RValue); + reportError(UnknownSymbol{symbol, UnknownSymbol::Context::Type}, ty->location); + } } +} - void visit(AstTypeUnion* ty) - { - // TODO! - for (AstType* type : ty->types) - visit(type); - } +void TypeChecker2::visit(AstTypeTable* table) +{ + // TODO! - void visit(AstTypeIntersection* ty) - { - // TODO! - for (AstType* type : ty->types) - visit(type); - } + for (const AstTableProp& prop : table->props) + visit(prop.type); - void visit(AstTypePack* pack) + if (table->indexer) { - if (auto p = pack->as()) - return visit(p); - else if (auto p = pack->as()) - return visit(p); - else if (auto p = pack->as()) - return visit(p); + visit(table->indexer->indexType); + visit(table->indexer->resultType); } +} - void visit(AstTypePackExplicit* tp) - { - // TODO! - for (AstType* type : tp->typeList.types) - visit(type); - - if (tp->typeList.tailType) - visit(tp->typeList.tailType); - } +void TypeChecker2::visit(AstTypeFunction* ty) +{ + visitGenerics(ty->generics, ty->genericPacks); + visit(ty->argTypes); + visit(ty->returnTypes); +} - void visit(AstTypePackVariadic* tp) - { - // TODO! - visit(tp->variadicType); - } +void TypeChecker2::visit(AstTypeTypeof* ty) +{ + visit(ty->expr, ValueContext::RValue); +} - void visit(AstTypePackGeneric* tp) - { - Scope* scope = findInnermostScope(tp->location); - LUAU_ASSERT(scope); +void TypeChecker2::visit(AstTypeUnion* ty) +{ + // TODO! + for (AstType* type : ty->types) + visit(type); +} - std::optional alias = scope->lookupPack(tp->genericName.value); - if (!alias.has_value()) - { - if (scope->lookupType(tp->genericName.value)) - { - reportError( - SwappedGenericTypeParameter{ - tp->genericName.value, - SwappedGenericTypeParameter::Kind::Pack, - }, - tp->location - ); - } - else - { - reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location); - } - } - } +void TypeChecker2::visit(AstTypeIntersection* ty) +{ + // TODO! + for (AstType* type : ty->types) + visit(type); +} - struct Reasonings - { - // the list of reasons - std::vector reasons; +void TypeChecker2::visit(AstTypePack* pack) +{ + if (auto p = pack->as()) + return visit(p); + else if (auto p = pack->as()) + return visit(p); + else if (auto p = pack->as()) + return visit(p); +} - // this should be true if _all_ of the reasons have an error suppressing type, and false otherwise. - bool suppressed; +void TypeChecker2::visit(AstTypePackExplicit* tp) +{ + // TODO! + for (AstType* type : tp->typeList.types) + visit(type); - std::string toString() - { - // DenseHashSet ordering is entirely undefined, so we want to - // sort the reasons here to achieve a stable error - // stringification. - std::sort(reasons.begin(), reasons.end()); - std::string allReasons; - bool first = true; - for (const std::string& reason : reasons) - { - if (first) - first = false; - else - allReasons += "\n\t"; + if (tp->typeList.tailType) + visit(tp->typeList.tailType); +} - allReasons += reason; - } +void TypeChecker2::visit(AstTypePackVariadic* tp) +{ + // TODO! + visit(tp->variadicType); +} - return allReasons; - } - }; +void TypeChecker2::visit(AstTypePackGeneric* tp) +{ + Scope* scope = findInnermostScope(tp->location); + LUAU_ASSERT(scope); - template - Reasonings explainReasonings(TID subTy, TID superTy, Location location, const SubtypingResult& r) + std::optional alias = scope->lookupPack(tp->genericName.value); + if (!alias.has_value()) { - if (r.reasoning.empty()) - return {}; - - std::vector reasons; - bool suppressed = true; - for (const SubtypingReasoning& reasoning : r.reasoning) + if (scope->lookupType(tp->genericName.value)) { - if (reasoning.subPath.empty() && reasoning.superPath.empty()) - continue; - - std::optional optSubLeaf = traverse(subTy, reasoning.subPath, builtinTypes); - std::optional optSuperLeaf = traverse(superTy, reasoning.superPath, builtinTypes); + reportError( + SwappedGenericTypeParameter{ + tp->genericName.value, + SwappedGenericTypeParameter::Kind::Pack, + }, + tp->location + ); + } + else + { + reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location); + } + } +} - if (!optSubLeaf || !optSuperLeaf) - ice->ice("Subtyping test returned a reasoning with an invalid path", location); +template +Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location location, const SubtypingResult& r) +{ + if (r.reasoning.empty()) + return {}; - const TypeOrPack& subLeaf = *optSubLeaf; - const TypeOrPack& superLeaf = *optSuperLeaf; + std::vector reasons; + bool suppressed = true; + for (const SubtypingReasoning& reasoning : r.reasoning) + { + if (reasoning.subPath.empty() && reasoning.superPath.empty()) + continue; - auto subLeafTy = get(subLeaf); - auto superLeafTy = get(superLeaf); + std::optional optSubLeaf = traverse(subTy, reasoning.subPath, builtinTypes); + std::optional optSuperLeaf = traverse(superTy, reasoning.superPath, builtinTypes); - auto subLeafTp = get(subLeaf); - auto superLeafTp = get(superLeaf); + if (!optSubLeaf || !optSuperLeaf) + ice->ice("Subtyping test returned a reasoning with an invalid path", location); - if (!subLeafTy && !superLeafTy && !subLeafTp && !superLeafTp) - ice->ice("Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack.", location); + const TypeOrPack& subLeaf = *optSubLeaf; + const TypeOrPack& superLeaf = *optSuperLeaf; - std::string relation = "a subtype of"; - if (reasoning.variance == SubtypingVariance::Invariant) - relation = "exactly"; - else if (reasoning.variance == SubtypingVariance::Contravariant) - relation = "a supertype of"; + auto subLeafTy = get(subLeaf); + auto superLeafTy = get(superLeaf); - std::string reason; - if (reasoning.subPath == reasoning.superPath) - reason = "at " + toString(reasoning.subPath) + ", " + toString(subLeaf) + " is not " + relation + " " + toString(superLeaf); - else - reason = "type " + toString(subTy) + toString(reasoning.subPath, /* prefixDot */ true) + " (" + toString(subLeaf) + ") is not " + - relation + " " + toString(superTy) + toString(reasoning.superPath, /* prefixDot */ true) + " (" + toString(superLeaf) + ")"; + auto subLeafTp = get(subLeaf); + auto superLeafTp = get(superLeaf); - reasons.push_back(reason); + if (!subLeafTy && !superLeafTy && !subLeafTp && !superLeafTp) + ice->ice("Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack.", location); - // if we haven't already proved this isn't suppressing, we have to keep checking. - if (suppressed) - { - if (subLeafTy && superLeafTy) - suppressed &= isErrorSuppressing(location, *subLeafTy) || isErrorSuppressing(location, *superLeafTy); - else - suppressed &= isErrorSuppressing(location, *subLeafTp) || isErrorSuppressing(location, *superLeafTp); - } - } + std::string relation = "a subtype of"; + if (reasoning.variance == SubtypingVariance::Invariant) + relation = "exactly"; + else if (reasoning.variance == SubtypingVariance::Contravariant) + relation = "a supertype of"; - return {std::move(reasons), suppressed}; - } + std::string reason; + if (reasoning.subPath == reasoning.superPath) + reason = "at " + toString(reasoning.subPath) + ", " + toString(subLeaf) + " is not " + relation + " " + toString(superLeaf); + else + reason = "type " + toString(subTy) + toString(reasoning.subPath, /* prefixDot */ true) + " (" + toString(subLeaf) + ") is not " + + relation + " " + toString(superTy) + toString(reasoning.superPath, /* prefixDot */ true) + " (" + toString(superLeaf) + ")"; + reasons.push_back(reason); - void explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& result) - { - switch (shouldSuppressErrors(NotNull{&normalizer}, subTy).orElse(shouldSuppressErrors(NotNull{&normalizer}, superTy))) + // if we haven't already proved this isn't suppressing, we have to keep checking. + if (suppressed) { - case ErrorSuppression::Suppress: - return; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, location); - case ErrorSuppression::DoNotSuppress: - break; + if (subLeafTy && superLeafTy) + suppressed &= isErrorSuppressing(location, *subLeafTy) || isErrorSuppressing(location, *superLeafTy); + else + suppressed &= isErrorSuppressing(location, *subLeafTp) || isErrorSuppressing(location, *superLeafTp); } + } - Reasonings reasonings = explainReasonings(subTy, superTy, location, result); + return {std::move(reasons), suppressed}; +} - if (!reasonings.suppressed) - reportError(TypeMismatch{superTy, subTy, reasonings.toString()}, location); - } +Reasonings TypeChecker2::explainReasonings(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& r) +{ + return explainReasonings_(subTy, superTy, location, r); +} + +Reasonings TypeChecker2::explainReasonings(TypePackId subTp, TypePackId superTp, Location location, const SubtypingResult& r) +{ + return explainReasonings_(subTp, superTp, location, r); +} - void explainError(TypePackId subTy, TypePackId superTy, Location location, const SubtypingResult& result) +void TypeChecker2::explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& result) +{ + switch (shouldSuppressErrors(NotNull{&normalizer}, subTy).orElse(shouldSuppressErrors(NotNull{&normalizer}, superTy))) { - switch (shouldSuppressErrors(NotNull{&normalizer}, subTy).orElse(shouldSuppressErrors(NotNull{&normalizer}, superTy))) - { - case ErrorSuppression::Suppress: - return; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, location); - case ErrorSuppression::DoNotSuppress: - break; - } + case ErrorSuppression::Suppress: + return; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, location); + break; + case ErrorSuppression::DoNotSuppress: + break; + } - Reasonings reasonings = explainReasonings(subTy, superTy, location, result); + Reasonings reasonings = explainReasonings(subTy, superTy, location, result); - if (!reasonings.suppressed) - reportError(TypePackMismatch{superTy, subTy, reasonings.toString()}, location); - } + if (!reasonings.suppressed) + reportError(TypeMismatch{superTy, subTy, reasonings.toString()}, location); +} - bool testIsSubtype(TypeId subTy, TypeId superTy, Location location) +void TypeChecker2::explainError(TypePackId subTy, TypePackId superTy, Location location, const SubtypingResult& result) +{ + switch (shouldSuppressErrors(NotNull{&normalizer}, subTy).orElse(shouldSuppressErrors(NotNull{&normalizer}, superTy))) { - SubtypingResult r = subtyping->isSubtype(subTy, superTy); + case ErrorSuppression::Suppress: + return; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, location); + break; + case ErrorSuppression::DoNotSuppress: + break; + } - if (r.normalizationTooComplex) - reportError(NormalizationTooComplex{}, location); + Reasonings reasonings = explainReasonings(subTy, superTy, location, result); - if (!r.isSubtype) - explainError(subTy, superTy, location, r); + if (!reasonings.suppressed) + reportError(TypePackMismatch{superTy, subTy, reasonings.toString()}, location); +} - return r.isSubtype; - } +bool TypeChecker2::testIsSubtype(TypeId subTy, TypeId superTy, Location location) +{ + NotNull scope{findInnermostScope(location)}; + SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope); - bool testIsSubtype(TypePackId subTy, TypePackId superTy, Location location) - { - SubtypingResult r = subtyping->isSubtype(subTy, superTy); + if (r.normalizationTooComplex) + reportError(NormalizationTooComplex{}, location); - if (r.normalizationTooComplex) - reportError(NormalizationTooComplex{}, location); + if (!r.isSubtype) + explainError(subTy, superTy, location, r); - if (!r.isSubtype) - explainError(subTy, superTy, location, r); + return r.isSubtype; +} - return r.isSubtype; - } +bool TypeChecker2::testIsSubtype(TypePackId subTy, TypePackId superTy, Location location) +{ + NotNull scope{findInnermostScope(location)}; + SubtypingResult r = subtyping->isSubtype(subTy, superTy, scope); - void reportError(TypeErrorData data, const Location& location) - { - if (auto utk = get_if(&data)) - diagnoseMissingTableKey(utk, data); + if (r.normalizationTooComplex) + reportError(NormalizationTooComplex{}, location); - module->errors.emplace_back(location, module->name, std::move(data)); + if (!r.isSubtype) + explainError(subTy, superTy, location, r); - if (logger) - logger->captureTypeCheckError(module->errors.back()); - } + return r.isSubtype; +} - void reportError(TypeError e) - { - reportError(std::move(e.data), e.location); - } +void TypeChecker2::reportError(TypeErrorData data, const Location& location) +{ + if (auto utk = get_if(&data)) + diagnoseMissingTableKey(utk, data); - void reportErrors(ErrorVec errors) - { - for (TypeError e : errors) - reportError(std::move(e)); - } + module->errors.emplace_back(location, module->name, std::move(data)); - struct PropertyTypes - { - // a vector of all the types assigned to the given property. - std::vector typesOfProp; + if (logger) + logger->captureTypeCheckError(module->errors.back()); +} - // a vector of all the types that are missing the given property. - std::vector missingProp; +void TypeChecker2::reportError(TypeError e) +{ + reportError(std::move(e.data), e.location); +} - bool foundOneProp() const - { - return !typesOfProp.empty(); - } +void TypeChecker2::reportErrors(ErrorVec errors) +{ + for (TypeError e : errors) + reportError(std::move(e)); +} - bool noneMissingProp() const - { - return missingProp.empty(); - } +/* A helper for checkIndexTypeFromType. + * + * Returns a pair: + * * A boolean indicating that at least one of the constituent types + * contains the prop, and + * * A vector of types that do not contain the prop. + */ +PropertyTypes TypeChecker2::lookupProp( + const NormalizedType* norm, + const std::string& prop, + ValueContext context, + const Location& location, + TypeId astIndexExprType, + std::vector& errors +) +{ + std::vector typesOfProp; + std::vector typesMissingTheProp; - bool foundMissingProp() const - { - return !missingProp.empty(); - } - }; + // this is `false` if we ever hit the resource limits during any of our uses of `fetch`. + bool normValid = true; - /* A helper for checkIndexTypeFromType. - * - * Returns a pair: - * * A boolean indicating that at least one of the constituent types - * contains the prop, and - * * A vector of types that do not contain the prop. - */ - PropertyTypes lookupProp( - const NormalizedType* norm, - const std::string& prop, - ValueContext context, - const Location& location, - TypeId astIndexExprType, - std::vector& errors - ) + auto fetch = [&](TypeId ty) { - std::vector typesOfProp; - std::vector typesMissingTheProp; + NormalizationResult result = normalizer.isInhabited(ty); + if (result == NormalizationResult::HitLimits) + normValid = false; + if (result != NormalizationResult::True) + return; - // this is `false` if we ever hit the resource limits during any of our uses of `fetch`. - bool normValid = true; + DenseHashSet seen{nullptr}; + PropertyType res = hasIndexTypeFromType(ty, prop, context, location, seen, astIndexExprType, errors); - auto fetch = [&](TypeId ty) + if (res.present == NormalizationResult::HitLimits) { - NormalizationResult result = normalizer.isInhabited(ty); - if (result == NormalizationResult::HitLimits) - normValid = false; - if (result != NormalizationResult::True) - return; - - DenseHashSet seen{nullptr}; - PropertyType res = hasIndexTypeFromType(ty, prop, context, location, seen, astIndexExprType, errors); - - if (res.present == NormalizationResult::HitLimits) - { - normValid = false; - return; - } + normValid = false; + return; + } - if (res.present == NormalizationResult::True && res.result) - typesOfProp.emplace_back(*res.result); + if (res.present == NormalizationResult::True && res.result) + typesOfProp.emplace_back(*res.result); - if (res.present == NormalizationResult::False) - typesMissingTheProp.push_back(ty); - }; + if (res.present == NormalizationResult::False) + typesMissingTheProp.push_back(ty); + }; - if (normValid) - fetch(norm->tops); - if (normValid) - fetch(norm->booleans); + if (normValid) + fetch(norm->tops); + if (normValid) + fetch(norm->booleans); - if (normValid) + if (normValid) + { + for (const auto& [ty, _negations] : norm->classes.classes) { - for (const auto& [ty, _negations] : norm->classes.classes) - { - fetch(ty); + fetch(ty); - if (!normValid) - break; - } + if (!normValid) + break; } + } - if (normValid) - fetch(norm->errors); - if (normValid) - fetch(norm->nils); - if (normValid) - fetch(norm->numbers); - if (normValid && !norm->strings.isNever()) - fetch(builtinTypes->stringType); - if (normValid) - fetch(norm->threads); - if (normValid) - fetch(norm->buffers); + if (normValid) + fetch(norm->errors); + if (normValid) + fetch(norm->nils); + if (normValid) + fetch(norm->numbers); + if (normValid && !norm->strings.isNever()) + fetch(builtinTypes->stringType); + if (normValid) + fetch(norm->threads); + if (normValid) + fetch(norm->buffers); - if (normValid) + if (normValid) + { + for (TypeId ty : norm->tables) { - for (TypeId ty : norm->tables) - { - fetch(ty); + fetch(ty); - if (!normValid) - break; - } + if (!normValid) + break; } + } - if (normValid && norm->functions.isTop) - fetch(builtinTypes->functionType); - else if (normValid && !norm->functions.isNever()) + if (normValid && norm->functions.isTop) + fetch(builtinTypes->functionType); + else if (normValid && !norm->functions.isNever()) + { + if (norm->functions.parts.size() == 1) + fetch(norm->functions.parts.front()); + else { - if (norm->functions.parts.size() == 1) - fetch(norm->functions.parts.front()); - else - { - std::vector parts; - parts.insert(parts.end(), norm->functions.parts.begin(), norm->functions.parts.end()); - fetch(module->internalTypes.addType(IntersectionType{std::move(parts)})); - } + std::vector parts; + parts.insert(parts.end(), norm->functions.parts.begin(), norm->functions.parts.end()); + fetch(module->internalTypes.addType(IntersectionType{std::move(parts)})); } + } - if (normValid) + if (normValid) + { + for (const auto& [tyvar, intersect] : norm->tyvars) { - for (const auto& [tyvar, intersect] : norm->tyvars) + if (get(intersect->tops)) { - if (get(intersect->tops)) - { - TypeId ty = normalizer.typeFromNormal(*intersect); - fetch(module->internalTypes.addType(IntersectionType{{tyvar, ty}})); - } - else - fetch(follow(tyvar)); - - if (!normValid) - break; + TypeId ty = normalizer.typeFromNormal(*intersect); + fetch(module->internalTypes.addType(IntersectionType{{tyvar, ty}})); } - } + else + fetch(follow(tyvar)); - return {typesOfProp, typesMissingTheProp}; + if (!normValid) + break; + } } - // If the provided type does not have the named property, report an error. - void checkIndexTypeFromType(TypeId tableTy, const std::string& prop, ValueContext context, const Location& location, TypeId astIndexExprType) + return {typesOfProp, typesMissingTheProp}; +} + + +void TypeChecker2::checkIndexTypeFromType( + TypeId tableTy, + const std::string& prop, + ValueContext context, + const Location& location, + TypeId astIndexExprType +) +{ + std::shared_ptr norm = normalizer.normalize(tableTy); + if (!norm) { - std::shared_ptr norm = normalizer.normalize(tableTy); - if (!norm) - { - reportError(NormalizationTooComplex{}, location); - return; - } + reportError(NormalizationTooComplex{}, location); + return; + } - // if the type is error suppressing, we don't actually have any work left to do. - if (norm->shouldSuppressErrors()) - return; + // if the type is error suppressing, we don't actually have any work left to do. + if (norm->shouldSuppressErrors()) + return; - std::vector dummy; - const auto propTypes = lookupProp(norm.get(), prop, context, location, astIndexExprType, module->errors); + std::vector dummy; + const auto propTypes = lookupProp(norm.get(), prop, context, location, astIndexExprType, module->errors); - if (propTypes.foundMissingProp()) + if (propTypes.foundMissingProp()) + { + if (propTypes.foundOneProp()) + reportError(MissingUnionProperty{tableTy, propTypes.missingProp, prop}, location); + // For class LValues, we don't want to report an extension error, + // because classes come into being with full knowledge of their + // shape. We instead want to report the unknown property error of + // the `else` branch. + else if (context == ValueContext::LValue && !get(tableTy)) { - if (propTypes.foundOneProp()) - reportError(MissingUnionProperty{tableTy, propTypes.missingProp, prop}, location); - // For class LValues, we don't want to report an extension error, - // because classes come into being with full knowledge of their - // shape. We instead want to report the unknown property error of - // the `else` branch. - else if (context == ValueContext::LValue && !get(tableTy)) - { - const auto lvPropTypes = lookupProp(norm.get(), prop, ValueContext::RValue, location, astIndexExprType, dummy); - if (lvPropTypes.foundOneProp() && lvPropTypes.noneMissingProp()) - reportError(PropertyAccessViolation{tableTy, prop, PropertyAccessViolation::CannotWrite}, location); - else if (get(tableTy) || get(tableTy)) - reportError(NotATable{tableTy}, location); - else - reportError(CannotExtendTable{tableTy, CannotExtendTable::Property, prop}, location); - } - else if (context == ValueContext::RValue && !get(tableTy)) - { - const auto rvPropTypes = lookupProp(norm.get(), prop, ValueContext::LValue, location, astIndexExprType, dummy); - if (rvPropTypes.foundOneProp() && rvPropTypes.noneMissingProp()) - reportError(PropertyAccessViolation{tableTy, prop, PropertyAccessViolation::CannotRead}, location); - else - reportError(UnknownProperty{tableTy, prop}, location); - } + const auto lvPropTypes = lookupProp(norm.get(), prop, ValueContext::RValue, location, astIndexExprType, dummy); + if (lvPropTypes.foundOneProp() && lvPropTypes.noneMissingProp()) + reportError(PropertyAccessViolation{tableTy, prop, PropertyAccessViolation::CannotWrite}, location); + else if (get(tableTy) || get(tableTy)) + reportError(NotATable{tableTy}, location); + else + reportError(CannotExtendTable{tableTy, CannotExtendTable::Property, prop}, location); + } + else if (context == ValueContext::RValue && !get(tableTy)) + { + const auto rvPropTypes = lookupProp(norm.get(), prop, ValueContext::LValue, location, astIndexExprType, dummy); + if (rvPropTypes.foundOneProp() && rvPropTypes.noneMissingProp()) + reportError(PropertyAccessViolation{tableTy, prop, PropertyAccessViolation::CannotRead}, location); else reportError(UnknownProperty{tableTy, prop}, location); } + else + reportError(UnknownProperty{tableTy, prop}, location); } +} - struct PropertyType - { - NormalizationResult present; - std::optional result; - }; +PropertyType TypeChecker2::hasIndexTypeFromType( + TypeId ty, + const std::string& prop, + ValueContext context, + const Location& location, + DenseHashSet& seen, + TypeId astIndexExprType, + std::vector& errors +) +{ + // If we have already encountered this type, we must assume that some + // other codepath will do the right thing and signal false if the + // property is not present. + if (seen.contains(ty)) + return {NormalizationResult::True, {}}; + seen.insert(ty); - PropertyType hasIndexTypeFromType( - TypeId ty, - const std::string& prop, - ValueContext context, - const Location& location, - DenseHashSet& seen, - TypeId astIndexExprType, - std::vector& errors - ) + if (get(ty) || get(ty) || get(ty)) + return {NormalizationResult::True, {ty}}; + + if (isString(ty)) { - // If we have already encountered this type, we must assume that some - // other codepath will do the right thing and signal false if the - // property is not present. - if (seen.contains(ty)) - return {NormalizationResult::True, {}}; - seen.insert(ty); + std::optional mtIndex = Luau::findMetatableEntry(builtinTypes, errors, builtinTypes->stringType, "__index", location); + LUAU_ASSERT(mtIndex); + ty = *mtIndex; + } - if (get(ty) || get(ty) || get(ty)) - return {NormalizationResult::True, {ty}}; + if (auto tt = getTableType(ty)) + { + if (auto resTy = findTablePropertyRespectingMeta(builtinTypes, errors, ty, prop, context, location)) + return {NormalizationResult::True, resTy}; - if (isString(ty)) + if (tt->indexer) { - std::optional mtIndex = Luau::findMetatableEntry(builtinTypes, errors, builtinTypes->stringType, "__index", location); - LUAU_ASSERT(mtIndex); - ty = *mtIndex; + TypeId indexType = follow(tt->indexer->indexType); + if (isPrim(indexType, PrimitiveType::String)) + return {NormalizationResult::True, {tt->indexer->indexResultType}}; + // If the indexer looks like { [any] : _} - the prop lookup should be allowed! + else if (get(indexType) || get(indexType)) + return {NormalizationResult::True, {tt->indexer->indexResultType}}; } - if (auto tt = getTableType(ty)) - { - if (auto resTy = findTablePropertyRespectingMeta(builtinTypes, errors, ty, prop, context, location)) - return {NormalizationResult::True, resTy}; - - if (tt->indexer) - { - TypeId indexType = follow(tt->indexer->indexType); - if (isPrim(indexType, PrimitiveType::String)) - return {NormalizationResult::True, {tt->indexer->indexResultType}}; - // If the indexer looks like { [any] : _} - the prop lookup should be allowed! - else if (get(indexType) || get(indexType)) - return {NormalizationResult::True, {tt->indexer->indexResultType}}; - } - - // if we are in a conditional context, we treat the property as present and `unknown` because - // we may be _refining_ `tableTy` to include that property. we will want to revisit this a bit - // in the future once luau has support for exact tables since this only applies when inexact. - return {inConditional(typeContext) ? NormalizationResult::True : NormalizationResult::False, {builtinTypes->unknownType}}; - } - else if (const ClassType* cls = get(ty)) + // if we are in a conditional context, we treat the property as present and `unknown` because + // we may be _refining_ `tableTy` to include that property. we will want to revisit this a bit + // in the future once luau has support for exact tables since this only applies when inexact. + return {inConditional(typeContext) ? NormalizationResult::True : NormalizationResult::False, {builtinTypes->unknownType}}; + } + else if (const ClassType* cls = get(ty)) + { + // If the property doesn't exist on the class, we consult the indexer + // We need to check if the type of the index expression foo (x[foo]) + // is compatible with the indexer's indexType + // Construct the intersection and test inhabitedness! + if (auto property = lookupClassProp(cls, prop)) + return {NormalizationResult::True, context == ValueContext::LValue ? property->writeTy : property->readTy}; + if (cls->indexer) { - // If the property doesn't exist on the class, we consult the indexer - // We need to check if the type of the index expression foo (x[foo]) - // is compatible with the indexer's indexType - // Construct the intersection and test inhabitedness! - if (auto property = lookupClassProp(cls, prop)) - return {NormalizationResult::True, context == ValueContext::LValue ? property->writeTy : property->readTy}; - if (cls->indexer) - { - TypeId inhabitatedTestType = module->internalTypes.addType(IntersectionType{{cls->indexer->indexType, astIndexExprType}}); - return {normalizer.isInhabited(inhabitatedTestType), {cls->indexer->indexResultType}}; - } - return {NormalizationResult::False, {}}; + TypeId inhabitatedTestType = module->internalTypes.addType(IntersectionType{{cls->indexer->indexType, astIndexExprType}}); + return {normalizer.isInhabited(inhabitatedTestType), {cls->indexer->indexResultType}}; } - else if (const UnionType* utv = get(ty)) - { - std::vector parts; - parts.reserve(utv->options.size()); - - for (TypeId part : utv) - { - PropertyType result = hasIndexTypeFromType(part, prop, context, location, seen, astIndexExprType, errors); - - if (result.present != NormalizationResult::True) - return {result.present, {}}; - if (result.result) - parts.emplace_back(*result.result); - } - - if (parts.size() == 0) - return {NormalizationResult::False, {}}; - - if (parts.size() == 1) - return {NormalizationResult::True, {parts[0]}}; - - TypeId propTy; - if (context == ValueContext::LValue) - propTy = module->internalTypes.addType(IntersectionType{parts}); - else - propTy = module->internalTypes.addType(UnionType{parts}); + return {NormalizationResult::False, {}}; + } + else if (const UnionType* utv = get(ty)) + { + std::vector parts; + parts.reserve(utv->options.size()); - return {NormalizationResult::True, propTy}; - } - else if (const IntersectionType* itv = get(ty)) + for (TypeId part : utv) { - for (TypeId part : itv) - { - PropertyType result = hasIndexTypeFromType(part, prop, context, location, seen, astIndexExprType, errors); - if (result.present != NormalizationResult::False) - return result; - } + PropertyType result = hasIndexTypeFromType(part, prop, context, location, seen, astIndexExprType, errors); - return {NormalizationResult::False, {}}; + if (result.present != NormalizationResult::True) + return {result.present, {}}; + if (result.result) + parts.emplace_back(*result.result); } - else if (const PrimitiveType* pt = get(ty)) - return {(inConditional(typeContext) && pt->type == PrimitiveType::Table) ? NormalizationResult::True : NormalizationResult::False, {ty}}; - else + + if (parts.size() == 0) return {NormalizationResult::False, {}}; - } - void diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& data) const - { - std::string_view sv(utk->key); - std::set candidates; + if (parts.size() == 1) + return {NormalizationResult::True, {parts[0]}}; - auto accumulate = [&](const TableType::Props& props) - { - for (const auto& [name, ty] : props) - { - if (sv != name && equalsLower(sv, name)) - candidates.insert(name); - } - }; + TypeId propTy; + if (context == ValueContext::LValue) + propTy = module->internalTypes.addType(IntersectionType{parts}); + else + propTy = module->internalTypes.addType(UnionType{parts}); - if (auto ttv = getTableType(utk->table)) - accumulate(ttv->props); - else if (auto ctv = get(follow(utk->table))) + return {NormalizationResult::True, propTy}; + } + else if (const IntersectionType* itv = get(ty)) + { + for (TypeId part : itv) { - while (ctv) - { - accumulate(ctv->props); - - if (!ctv->parent) - break; - - ctv = get(*ctv->parent); - LUAU_ASSERT(ctv); - } + PropertyType result = hasIndexTypeFromType(part, prop, context, location, seen, astIndexExprType, errors); + if (result.present != NormalizationResult::False) + return result; } - if (!candidates.empty()) - data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, candidates}); + return {NormalizationResult::False, {}}; } + else if (const PrimitiveType* pt = get(ty)) + return {(inConditional(typeContext) && pt->type == PrimitiveType::Table) ? NormalizationResult::True : NormalizationResult::False, {ty}}; + else + return {NormalizationResult::False, {}}; +} - bool isErrorSuppressing(Location loc, TypeId ty) - { - switch (shouldSuppressErrors(NotNull{&normalizer}, ty)) - { - case ErrorSuppression::DoNotSuppress: - return false; - case ErrorSuppression::Suppress: - return true; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, loc); - return false; - }; - LUAU_ASSERT(false); - return false; // UNREACHABLE - } - bool isErrorSuppressing(Location loc1, TypeId ty1, Location loc2, TypeId ty2) +void TypeChecker2::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& data) const +{ + std::string_view sv(utk->key); + std::set candidates; + + auto accumulate = [&](const TableType::Props& props) { - return isErrorSuppressing(loc1, ty1) || isErrorSuppressing(loc2, ty2); - } + for (const auto& [name, ty] : props) + { + if (sv != name && equalsLower(sv, name)) + candidates.insert(name); + } + }; - bool isErrorSuppressing(Location loc, TypePackId tp) + if (auto ttv = getTableType(utk->table)) + accumulate(ttv->props); + else if (auto ctv = get(follow(utk->table))) { - switch (shouldSuppressErrors(NotNull{&normalizer}, tp)) + while (ctv) { - case ErrorSuppression::DoNotSuppress: - return false; - case ErrorSuppression::Suppress: - return true; - case ErrorSuppression::NormalizationFailed: - reportError(NormalizationTooComplex{}, loc); - return false; - }; + accumulate(ctv->props); - LUAU_ASSERT(false); - return false; // UNREACHABLE - } + if (!ctv->parent) + break; - bool isErrorSuppressing(Location loc1, TypePackId tp1, Location loc2, TypePackId tp2) - { - return isErrorSuppressing(loc1, tp1) || isErrorSuppressing(loc2, tp2); + ctv = get(*ctv->parent); + LUAU_ASSERT(ctv); + } } -}; -void check( - NotNull builtinTypes, - NotNull unifierState, - NotNull limits, - DcrLogger* logger, - const SourceModule& sourceModule, - Module* module -) + if (!candidates.empty()) + data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, candidates}); +} + +bool TypeChecker2::isErrorSuppressing(Location loc, TypeId ty) { - LUAU_TIMETRACE_SCOPE("check", "Typechecking"); + switch (shouldSuppressErrors(NotNull{&normalizer}, ty)) + { + case ErrorSuppression::DoNotSuppress: + return false; + case ErrorSuppression::Suppress: + return true; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, loc); + return false; + }; - TypeChecker2 typeChecker{builtinTypes, unifierState, limits, logger, &sourceModule, module}; + LUAU_ASSERT(false); + return false; // UNREACHABLE +} - typeChecker.visit(sourceModule.root); +bool TypeChecker2::isErrorSuppressing(Location loc1, TypeId ty1, Location loc2, TypeId ty2) +{ + return isErrorSuppressing(loc1, ty1) || isErrorSuppressing(loc2, ty2); +} - // if the only error we're producing is one about constraint solving being incomplete, we can silence it. - // this means we won't give this warning if types seem totally nonsensical, but there are no other errors. - // this is probably, on the whole, a good decision to not annoy users though. - if (module->errors.size() == 1 && get(module->errors[0])) - module->errors.clear(); +bool TypeChecker2::isErrorSuppressing(Location loc, TypePackId tp) +{ + switch (shouldSuppressErrors(NotNull{&normalizer}, tp)) + { + case ErrorSuppression::DoNotSuppress: + return false; + case ErrorSuppression::Suppress: + return true; + case ErrorSuppression::NormalizationFailed: + reportError(NormalizationTooComplex{}, loc); + return false; + }; - unfreeze(module->interfaceTypes); - copyErrors(module->errors, module->interfaceTypes, builtinTypes); - freeze(module->interfaceTypes); + LUAU_ASSERT(false); + return false; // UNREACHABLE } +bool TypeChecker2::isErrorSuppressing(Location loc1, TypePackId tp1, Location loc2, TypePackId tp2) +{ + return isErrorSuppressing(loc1, tp1) || isErrorSuppressing(loc2, tp2); +} + + } // namespace Luau diff --git a/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp b/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp index e8d3764e..9ae57fd1 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeFunction.cpp @@ -701,8 +701,8 @@ TypeFunctionReductionResult lenTypeFunction( if (!u2.unify(inferredArgPack, instantiatedMmFtv->argTypes)) return {std::nullopt, true, {}, {}}; // occurs check failed - Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice, ctx->scope}; - if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes).isSubtype) // TODO: is this the right variance? + Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice}; + if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes, ctx->scope).isSubtype) // TODO: is this the right variance? return {std::nullopt, true, {}, {}}; // `len` must return a `number`. @@ -790,8 +790,8 @@ TypeFunctionReductionResult unmTypeFunction( if (!u2.unify(inferredArgPack, instantiatedMmFtv->argTypes)) return {std::nullopt, true, {}, {}}; // occurs check failed - Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice, ctx->scope}; - if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes).isSubtype) // TODO: is this the right variance? + Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice}; + if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes, ctx->scope).isSubtype) // TODO: is this the right variance? return {std::nullopt, true, {}, {}}; if (std::optional ret = first(instantiatedMmFtv->retTypes)) @@ -1138,8 +1138,8 @@ TypeFunctionReductionResult concatTypeFunction( if (!u2.unify(inferredArgPack, instantiatedMmFtv->argTypes)) return {std::nullopt, true, {}, {}}; // occurs check failed - Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice, ctx->scope}; - if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes).isSubtype) // TODO: is this the right variance? + Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice}; + if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes, ctx->scope).isSubtype) // TODO: is this the right variance? return {std::nullopt, true, {}, {}}; return {ctx->builtins->stringType, false, {}, {}}; @@ -1392,8 +1392,8 @@ static TypeFunctionReductionResult comparisonTypeFunction( if (!u2.unify(inferredArgPack, instantiatedMmFtv->argTypes)) return {std::nullopt, true, {}, {}}; // occurs check failed - Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice, ctx->scope}; - if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes).isSubtype) // TODO: is this the right variance? + Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice}; + if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes, ctx->scope).isSubtype) // TODO: is this the right variance? return {std::nullopt, true, {}, {}}; return {ctx->builtins->booleanType, false, {}, {}}; @@ -1536,8 +1536,8 @@ TypeFunctionReductionResult eqTypeFunction( if (!u2.unify(inferredArgPack, instantiatedMmFtv->argTypes)) return {std::nullopt, true, {}, {}}; // occurs check failed - Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice, ctx->scope}; - if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes).isSubtype) // TODO: is this the right variance? + Subtyping subtyping{ctx->builtins, ctx->arena, ctx->normalizer, ctx->ice}; + if (!subtyping.isSubtype(inferredArgPack, instantiatedMmFtv->argTypes, ctx->scope).isSubtype) // TODO: is this the right variance? return {std::nullopt, true, {}, {}}; return {ctx->builtins->booleanType, false, {}, {}}; @@ -1897,7 +1897,30 @@ bool computeKeysOf(TypeId ty, Set& result, DenseHashSet& se return res; } - // this should not be reachable since the type should be a valid tables part from normalization. + if (auto classTy = get(ty)) + { + for (auto [key, _] : classTy->props) + result.insert(key); + + bool res = true; + if (classTy->metatable && !isRaw) + { + // findMetatableEntry demands the ability to emit errors, so we must give it + // the necessary state to do that, even if we intend to just eat the errors. + ErrorVec dummy; + + std::optional mmType = findMetatableEntry(ctx->builtins, dummy, ty, "__index", Location{}); + if (mmType) + res = res && computeKeysOf(*mmType, result, seen, isRaw, ctx); + } + + if (classTy->parent) + res = res && computeKeysOf(follow(*classTy->parent), result, seen, isRaw, ctx); + + return res; + } + + // this should not be reachable since the type should be a valid tables or classes part from normalization. LUAU_ASSERT(false); return false; } @@ -1941,34 +1964,32 @@ TypeFunctionReductionResult keyofFunctionImpl( { LUAU_ASSERT(!normTy->hasTables()); + // seen set for key computation for classes + DenseHashSet seen{{}}; + auto classesIter = normTy->classes.ordering.begin(); auto classesIterEnd = normTy->classes.ordering.end(); - LUAU_ASSERT(classesIter != classesIterEnd); // should be guaranteed by the `hasClasses` check - - auto classTy = get(*classesIter); - if (!classTy) - { - LUAU_ASSERT(false); // this should not be possible according to normalization's spec - return {std::nullopt, true, {}, {}}; - } + LUAU_ASSERT(classesIter != classesIterEnd); // should be guaranteed by the `hasClasses` check earlier - for (auto [key, _] : classTy->props) - keys.insert(key); + // collect all the properties from the first class type + if (!computeKeysOf(*classesIter, keys, seen, isRaw, ctx)) + return {ctx->builtins->stringType, false, {}, {}}; // if it failed, we have a top type! // we need to look at each class to remove any keys that are not common amongst them all while (++classesIter != classesIterEnd) { - auto classTy = get(*classesIter); - if (!classTy) - { - LUAU_ASSERT(false); // this should not be possible according to normalization's spec - return {std::nullopt, true, {}, {}}; - } + seen.clear(); // we'll reuse the same seen set + + Set localKeys{{}}; + + // we can skip to the next class if this one is a top type + if (!computeKeysOf(*classesIter, localKeys, seen, isRaw, ctx)) + continue; for (auto key : keys) { // remove any keys that are not present in each class - if (classTy->props.find(key) == classTy->props.end()) + if (!localKeys.contains(key)) keys.erase(key); } } @@ -2020,6 +2041,12 @@ TypeFunctionReductionResult keyofFunctionImpl( for (std::string key : keys) singletons.push_back(ctx->arena->addType(SingletonType{StringSingleton{key}})); + // If there's only one entry, we don't need a UnionType. + // We can take straight take it from the first entry + // because it was added into the type arena already. + if (singletons.size() == 1) + return {singletons.front(), false, {}, {}}; + return {ctx->arena->addType(UnionType{singletons}), false, {}, {}}; } @@ -2179,6 +2206,12 @@ TypeFunctionReductionResult indexFunctionImpl( return {std::nullopt, true, {}, {}}; TypeId indexerTy = follow(typeParams.at(1)); + + if (isPending(indexerTy, ctx->solver)) + { + return {std::nullopt, false, {indexerTy}, {}}; + } + std::shared_ptr indexerNormTy = ctx->normalizer->normalize(indexerTy); // if the indexer failed to normalize, we can't reduce, but know nothing about inhabitance. @@ -2222,6 +2255,19 @@ TypeFunctionReductionResult indexFunctionImpl( if (searchPropsAndIndexer(ty, classTy->props, classTy->indexer, properties, ctx)) continue; // Indexer was found in this class, so we can move on to the next + auto parent = classTy->parent; + bool foundInParent = false; + while (parent && !foundInParent) + { + auto parentClass = get(follow(*parent)); + foundInParent = searchPropsAndIndexer(ty, parentClass->props, parentClass->indexer, properties, ctx); + parent = parentClass->parent; + } + + // we move on to the next type if any of the parents we went through had the property. + if (foundInParent) + continue; + // If code reaches here,that means the property not found -> check in the metatable's __index // findMetatableEntry demands the ability to emit errors, so we must give it diff --git a/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp b/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp index c0a43df8..6b2e861d 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeInfer.cpp @@ -34,6 +34,7 @@ LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false) LUAU_FASTFLAG(LuauInstantiateInSubtyping) LUAU_FASTFLAGVARIABLE(LuauRemoveBadRelationalOperatorWarning, false) LUAU_FASTFLAGVARIABLE(LuauOkWithIteratingOverTableProperties, false) +LUAU_FASTFLAGVARIABLE(LuauAcceptIndexingTableUnionsIntersections, false) namespace Luau { @@ -2750,7 +2751,7 @@ TypeId TypeChecker::checkRelationalOperation( if (lhsIsAny || rhsIsAny) return booleanType; - // Fallthrough here is intentional + [[fallthrough]]; } case AstExprBinary::CompareLt: case AstExprBinary::CompareGt: @@ -3506,54 +3507,207 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex } } - TableType* exprTable = getMutableTableType(exprType); - - if (!exprTable) + if (FFlag::LuauAcceptIndexingTableUnionsIntersections) { - reportError(TypeError{expr.expr->location, NotATable{exprType}}); - return errorRecoveryType(scope); - } + // We're going to have a whole vector. + std::vector tableTypes{}; + bool isUnion = true; - if (value) - { - const auto& it = exprTable->props.find(value->value.data); - if (it != exprTable->props.end()) + // We'd like for normalization eventually to deal with this sort of thing, but as a tactical affordance, we will + // attempt to deal with _one_ level of unions or intersections. + if (auto exprUnion = get(exprType)) { - return it->second.type(); + tableTypes.reserve(exprUnion->options.size()); + + for (auto option : exprUnion) + { + TableType* optionTable = getMutableTableType(option); + + if (!optionTable) + { + // TODO: we could do better here and report `option` is not a table as reasoning for the error + reportError(TypeError{expr.expr->location, NotATable{exprType}}); + return errorRecoveryType(scope); + } + + tableTypes.push_back(optionTable); + } } - else if ((ctx == ValueContext::LValue && exprTable->state == TableState::Unsealed) || exprTable->state == TableState::Free) + else if (auto exprIntersection = get(exprType)) + { + tableTypes.reserve(exprIntersection->parts.size()); + isUnion = false; + + for (auto part : exprIntersection) + { + TableType* partTable = getMutableTableType(part); + + if (!partTable) + { + // TODO: we could do better here and report `part` is not a table as reasoning for the error + reportError(TypeError{expr.expr->location, NotATable{exprType}}); + return errorRecoveryType(scope); + } + + tableTypes.push_back(partTable); + } + } + else if (auto exprTable = getMutableTableType(exprType)) { - TypeId resultType = freshType(scope); - Property& property = exprTable->props[value->value.data]; - property.setType(resultType); - property.location = expr.index->location; - return resultType; + tableTypes.push_back(exprTable); + } + else + { + reportError(TypeError{expr.expr->location, NotATable{exprType}}); + return errorRecoveryType(scope); } - } - if (exprTable->indexer) - { - const TableIndexer& indexer = *exprTable->indexer; - unify(indexType, indexer.indexType, scope, expr.index->location); - return indexer.indexResultType; - } - else if ((ctx == ValueContext::LValue && exprTable->state == TableState::Unsealed) || exprTable->state == TableState::Free) - { - TypeId indexerType = freshType(exprTable->level); - unify(indexType, indexerType, scope, expr.location); - TypeId indexResultType = freshType(exprTable->level); + if (value) + { + DenseHashSet propTypes{{}}; + + for (auto table : tableTypes) + { + const auto& it = table->props.find(value->value.data); + if (it != table->props.end()) + { + propTypes.insert(it->second.type()); + } + else if ((ctx == ValueContext::LValue && table->state == TableState::Unsealed) || table->state == TableState::Free) + { + TypeId resultType = freshType(scope); + Property& property = table->props[value->value.data]; + property.setType(resultType); + property.location = expr.index->location; + propTypes.insert(resultType); + } + } + + if (propTypes.size() == 1) + return *propTypes.begin(); + + if (!propTypes.empty()) + { + if (isUnion) + { + std::vector options = reduceUnion({propTypes.begin(), propTypes.end()}); + + if (options.empty()) + return neverType; + + if (options.size() == 1) + return options[0]; - exprTable->indexer = TableIndexer{anyIfNonstrict(indexerType), anyIfNonstrict(indexResultType)}; - return indexResultType; + return addType(UnionType{options}); + } + + return addType(IntersectionType{{propTypes.begin(), propTypes.end()}}); + } + } + + DenseHashSet resultTypes{{}}; + + for (auto table : tableTypes) + { + if (table->indexer) + { + const TableIndexer& indexer = *table->indexer; + unify(indexType, indexer.indexType, scope, expr.index->location); + resultTypes.insert(indexer.indexResultType); + } + else if ((ctx == ValueContext::LValue && table->state == TableState::Unsealed) || table->state == TableState::Free) + { + TypeId indexerType = freshType(table->level); + unify(indexType, indexerType, scope, expr.location); + TypeId indexResultType = freshType(table->level); + + table->indexer = TableIndexer{anyIfNonstrict(indexerType), anyIfNonstrict(indexResultType)}; + resultTypes.insert(indexResultType); + } + else + { + /* + * If we use [] indexing to fetch a property from a sealed table that + * has no indexer, we have no idea if it will work so we just return any + * and hope for the best. + */ + + // if this is a union, it's going to be equivalent to `any` no matter what at this point, so we'll just call it done. + if (isUnion) + return anyType; + + resultTypes.insert(anyType); + } + } + + if (resultTypes.size() == 1) + return *resultTypes.begin(); + + if (isUnion) + { + std::vector options = reduceUnion({resultTypes.begin(), resultTypes.end()}); + + if (options.empty()) + return neverType; + + if (options.size() == 1) + return options[0]; + + return addType(UnionType{options}); + } + + return addType(IntersectionType{{resultTypes.begin(), resultTypes.end()}}); } else { - /* - * If we use [] indexing to fetch a property from a sealed table that - * has no indexer, we have no idea if it will work so we just return any - * and hope for the best. - */ - return anyType; + TableType* exprTable = getMutableTableType(exprType); + if (!exprTable) + { + reportError(TypeError{expr.expr->location, NotATable{exprType}}); + return errorRecoveryType(scope); + } + + if (value) + { + const auto& it = exprTable->props.find(value->value.data); + if (it != exprTable->props.end()) + { + return it->second.type(); + } + else if ((ctx == ValueContext::LValue && exprTable->state == TableState::Unsealed) || exprTable->state == TableState::Free) + { + TypeId resultType = freshType(scope); + Property& property = exprTable->props[value->value.data]; + property.setType(resultType); + property.location = expr.index->location; + return resultType; + } + } + + if (exprTable->indexer) + { + const TableIndexer& indexer = *exprTable->indexer; + unify(indexType, indexer.indexType, scope, expr.index->location); + return indexer.indexResultType; + } + else if ((ctx == ValueContext::LValue && exprTable->state == TableState::Unsealed) || exprTable->state == TableState::Free) + { + TypeId indexerType = freshType(exprTable->level); + unify(indexType, indexerType, scope, expr.location); + TypeId indexResultType = freshType(exprTable->level); + + exprTable->indexer = TableIndexer{anyIfNonstrict(indexerType), anyIfNonstrict(indexResultType)}; + return indexResultType; + } + else + { + /* + * If we use [] indexing to fetch a property from a sealed table that + * has no indexer, we have no idea if it will work so we just return any + * and hope for the best. + */ + return anyType; + } } } diff --git a/Dependencies/luau/Luau/Analysis/src/TypePack.cpp b/Dependencies/luau/Luau/Analysis/src/TypePack.cpp index 9f3924f0..7e11d462 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypePack.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypePack.cpp @@ -6,7 +6,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { diff --git a/Dependencies/luau/Luau/Analysis/src/TypePath.cpp b/Dependencies/luau/Luau/Analysis/src/TypePath.cpp index 29f5cfb5..d2113ee3 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypePath.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypePath.cpp @@ -13,7 +13,7 @@ #include #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); // Maximum number of steps to follow when traversing a path. May not always // equate to the number of components in a path, depending on the traversal @@ -29,7 +29,7 @@ namespace TypePath Property::Property(std::string name) : name(std::move(name)) { - LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(!FFlag::LuauSolverV2); } Property Property::read(std::string name) @@ -156,21 +156,21 @@ Path PathBuilder::build() PathBuilder& PathBuilder::readProp(std::string name) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); components.push_back(Property{std::move(name), true}); return *this; } PathBuilder& PathBuilder::writeProp(std::string name) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); components.push_back(Property{std::move(name), false}); return *this; } PathBuilder& PathBuilder::prop(std::string name) { - LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(!FFlag::LuauSolverV2); components.push_back(Property{std::move(name)}); return *this; } @@ -343,7 +343,7 @@ struct TraversalState if (prop) { std::optional maybeType; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) maybeType = property.isRead ? prop->readTy : prop->writeTy; else maybeType = prop->type(); @@ -540,7 +540,7 @@ std::string toString(const TypePath::Path& path, bool prefixDot) if constexpr (std::is_same_v) { result << '['; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (c.isRead) result << "read "; diff --git a/Dependencies/luau/Luau/Analysis/src/TypeUtils.cpp b/Dependencies/luau/Luau/Analysis/src/TypeUtils.cpp index b40805e9..f1c60f06 100644 --- a/Dependencies/luau/Luau/Analysis/src/TypeUtils.cpp +++ b/Dependencies/luau/Luau/Analysis/src/TypeUtils.cpp @@ -9,7 +9,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { @@ -153,7 +153,7 @@ std::optional findTablePropertyRespectingMeta( const auto& it = tableType->props.find(name); if (it != tableType->props.end()) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { switch (context) { @@ -301,6 +301,8 @@ TypePack extendTypePack( TypePack newPack; newPack.tail = arena.freshTypePack(ftp->scope); + if (FFlag::LuauSolverV2) + result.tail = newPack.tail; size_t overridesIndex = 0; while (result.head.size() < length) { @@ -311,7 +313,7 @@ TypePack extendTypePack( } else { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { FreeType ft{ftp->scope, builtinTypes->neverType, builtinTypes->unknownType}; t = arena.addType(ft); @@ -424,7 +426,7 @@ TypeId stripNil(NotNull builtinTypes, TypeArena& arena, TypeId ty) ErrorSuppression shouldSuppressErrors(NotNull normalizer, TypeId ty) { - LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(FFlag::LuauSolverV2); std::shared_ptr normType = normalizer->normalize(ty); if (!normType) diff --git a/Dependencies/luau/Luau/Analysis/src/Unifier.cpp b/Dependencies/luau/Luau/Analysis/src/Unifier.cpp index 3dc66d1d..fa7ff876 100644 --- a/Dependencies/luau/Luau/Analysis/src/Unifier.cpp +++ b/Dependencies/luau/Luau/Analysis/src/Unifier.cpp @@ -19,7 +19,7 @@ LUAU_FASTINT(LuauTypeInferTypePackLoopLimit) LUAU_FASTFLAG(LuauErrorRecoveryType) LUAU_FASTFLAGVARIABLE(LuauInstantiateInSubtyping, false) LUAU_FASTFLAGVARIABLE(LuauTransitiveSubtyping, false) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAGVARIABLE(LuauFixIndexerSubtypingOrdering, false) LUAU_FASTFLAGVARIABLE(LuauUnifierShouldNotCopyError, false) LUAU_FASTFLAGVARIABLE(LuauUnifierRecursionOnRestart, false) @@ -405,7 +405,7 @@ Unifier::Unifier(NotNull normalizer, NotNull scope, const Loc LUAU_ASSERT(sharedState.iceHandler); // Unifier is not usable when this flag is enabled! Please consider using Subtyping instead. - LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution); + LUAU_ASSERT(!FFlag::LuauSolverV2); } void Unifier::tryUnify(TypeId subTy, TypeId superTy, bool isFunctionCall, bool isIntersection, const LiteralProperties* literalProperties) @@ -1646,7 +1646,7 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal auto mkFreshType = [this](Scope* scope, TypeLevel level) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return freshType(NotNull{types}, builtinTypes, scope); else return types->freshType(scope, level); diff --git a/Dependencies/luau/Luau/Ast/src/Parser.cpp b/Dependencies/luau/Luau/Ast/src/Parser.cpp index 59533bae..4b9eddda 100644 --- a/Dependencies/luau/Luau/Ast/src/Parser.cpp +++ b/Dependencies/luau/Luau/Ast/src/Parser.cpp @@ -16,7 +16,7 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100) // Warning: If you are introducing new syntax, ensure that it is behind a separate // flag so that we don't break production games by reverting syntax changes. // See docs/SyntaxChanges.md for an explanation. -LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false) +LUAU_FASTFLAGVARIABLE(LuauSolverV2, false) LUAU_FASTFLAGVARIABLE(LuauNativeAttribute, false) LUAU_FASTFLAGVARIABLE(LuauAttributeSyntaxFunExpr, false) LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctions, false) @@ -784,6 +784,7 @@ AstStat* Parser::parseAttributeStat() AstExpr* expr = parsePrimaryExpr(/* asStatement= */ true); return parseDeclaration(expr->location, attributes); } + [[fallthrough]]; default: return reportStatError( lexer.current().location, diff --git a/Dependencies/luau/Luau/CLI/Require.cpp b/Dependencies/luau/Luau/CLI/Require.cpp index 5de78a4a..b6753e96 100644 --- a/Dependencies/luau/Luau/CLI/Require.cpp +++ b/Dependencies/luau/Luau/CLI/Require.cpp @@ -204,7 +204,18 @@ void RequireResolver::substituteAliasIfPresent(std::string& path) { if (path.size() < 1 || path[0] != '@') return; - std::string potentialAlias = path.substr(1, path.find_first_of("\\/")); + + // To ignore the '@' alias prefix when processing the alias + const size_t aliasStartPos = 1; + + // If a directory separator was found, the length of the alias is the + // distance between the start of the alias and the separator. Otherwise, + // the whole string after the alias symbol is the alias. + size_t aliasLen = path.find_first_of("\\/"); + if (aliasLen != std::string::npos) + aliasLen -= aliasStartPos; + + const std::string potentialAlias = path.substr(aliasStartPos, aliasLen); // Not worth searching when potentialAlias cannot be an alias if (!Luau::isValidAlias(potentialAlias)) diff --git a/Dependencies/luau/Luau/CMakeLists.txt b/Dependencies/luau/Luau/CMakeLists.txt index 34e104e1..b18cd5c9 100644 --- a/Dependencies/luau/Luau/CMakeLists.txt +++ b/Dependencies/luau/Luau/CMakeLists.txt @@ -111,6 +111,7 @@ if(MSVC) list(APPEND LUAU_OPTIONS "/we4388") # Also signed/unsigned mismatch else() list(APPEND LUAU_OPTIONS -Wall) # All warnings + list(APPEND LUAU_OPTIONS -Wimplicit-fallthrough) list(APPEND LUAU_OPTIONS -Wsign-compare) # This looks to be included in -Wall for GCC but not clang endif() diff --git a/Dependencies/luau/Luau/CodeGen/include/Luau/IrVisitUseDef.h b/Dependencies/luau/Luau/CodeGen/include/Luau/IrVisitUseDef.h index 6744bd65..39dd6cf8 100644 --- a/Dependencies/luau/Luau/CodeGen/include/Luau/IrVisitUseDef.h +++ b/Dependencies/luau/Luau/CodeGen/include/Luau/IrVisitUseDef.h @@ -4,8 +4,6 @@ #include "Luau/Common.h" #include "Luau/IrData.h" -LUAU_FASTFLAG(LuauCodegenFastcall3) - namespace Luau { namespace CodeGen @@ -113,47 +111,16 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i break; case IrCmd::FASTCALL: - if (FFlag::LuauCodegenFastcall3) - { - visitor.use(inst.c); - - if (int nresults = function.intOp(inst.d); nresults != -1) - visitor.defRange(vmRegOp(inst.b), nresults); - } - else - { - if (int count = function.intOp(inst.e); count != -1) - { - if (count >= 3) - { - CODEGEN_ASSERT(inst.d.kind == IrOpKind::VmReg && vmRegOp(inst.d) == vmRegOp(inst.c) + 1); - - visitor.useRange(vmRegOp(inst.c), count); - } - else - { - if (count >= 1) - visitor.use(inst.c); - - if (count >= 2) - visitor.maybeUse(inst.d); // Argument can also be a VmConst - } - } - else - { - visitor.useVarargs(vmRegOp(inst.c)); - } + visitor.use(inst.c); - // Multiple return sequences (count == -1) are defined by ADJUST_STACK_TO_REG - if (int count = function.intOp(inst.f); count != -1) - visitor.defRange(vmRegOp(inst.b), count); - } + if (int nresults = function.intOp(inst.d); nresults != -1) + visitor.defRange(vmRegOp(inst.b), nresults); break; case IrCmd::INVOKE_FASTCALL: - if (int count = function.intOp(FFlag::LuauCodegenFastcall3 ? inst.f : inst.e); count != -1) + if (int count = function.intOp(inst.f); count != -1) { // Only LOP_FASTCALL3 lowering is allowed to have third optional argument - if (count >= 3 && (!FFlag::LuauCodegenFastcall3 || inst.e.kind == IrOpKind::Undef)) + if (count >= 3 && inst.e.kind == IrOpKind::Undef) { CODEGEN_ASSERT(inst.d.kind == IrOpKind::VmReg && vmRegOp(inst.d) == vmRegOp(inst.c) + 1); @@ -167,7 +134,7 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i if (count >= 2) visitor.maybeUse(inst.d); // Argument can also be a VmConst - if (FFlag::LuauCodegenFastcall3 && count >= 3) + if (count >= 3) visitor.maybeUse(inst.e); // Argument can also be a VmConst } } @@ -177,7 +144,7 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i } // Multiple return sequences (count == -1) are defined by ADJUST_STACK_TO_REG - if (int count = function.intOp(FFlag::LuauCodegenFastcall3 ? inst.g : inst.f); count != -1) + if (int count = function.intOp(inst.g); count != -1) visitor.defRange(vmRegOp(inst.b), count); break; case IrCmd::FORGLOOP: diff --git a/Dependencies/luau/Luau/CodeGen/src/BytecodeAnalysis.cpp b/Dependencies/luau/Luau/CodeGen/src/BytecodeAnalysis.cpp index 01adea34..8d2efebe 100644 --- a/Dependencies/luau/Luau/CodeGen/src/BytecodeAnalysis.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/BytecodeAnalysis.cpp @@ -11,8 +11,6 @@ #include -LUAU_FASTFLAGVARIABLE(LuauCodegenFastcall3, false) - namespace Luau { namespace CodeGen @@ -1101,8 +1099,6 @@ void analyzeBytecodeTypes(IrFunction& function, const HostIrHooks& hostHooks) } case LOP_FASTCALL3: { - CODEGEN_ASSERT(FFlag::LuauCodegenFastcall3); - int bfid = LUAU_INSN_A(*pc); int skip = LUAU_INSN_C(*pc); int aux = pc[1]; diff --git a/Dependencies/luau/Luau/CodeGen/src/CodeGenAssembly.cpp b/Dependencies/luau/Luau/CodeGen/src/CodeGenAssembly.cpp index 295e1cb8..c423a1ce 100644 --- a/Dependencies/luau/Luau/CodeGen/src/CodeGenAssembly.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/CodeGenAssembly.cpp @@ -149,7 +149,10 @@ static std::string getAssemblyImpl(AssemblyBuilder& build, const TValue* func, A Proto* root = clvalue(func)->l.p; if ((options.compilationOptions.flags & CodeGen_OnlyNativeModules) != 0 && (root->flags & LPF_NATIVE_MODULE) == 0) + { + build.finalize(); return std::string(); + } std::vector protos; if (FFlag::LuauNativeAttribute) @@ -174,7 +177,7 @@ static std::string getAssemblyImpl(AssemblyBuilder& build, const TValue* func, A if (protos.empty()) { - build.finalize(); // to avoid assertion in AssemblyBuilder dtor + build.finalize(); return std::string(); } diff --git a/Dependencies/luau/Luau/CodeGen/src/EmitBuiltinsX64.cpp b/Dependencies/luau/Luau/CodeGen/src/EmitBuiltinsX64.cpp index 15aab4b6..bee59908 100644 --- a/Dependencies/luau/Luau/CodeGen/src/EmitBuiltinsX64.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/EmitBuiltinsX64.cpp @@ -12,8 +12,6 @@ #include "lstate.h" -LUAU_FASTFLAG(LuauCodegenMathSign) - namespace Luau { namespace CodeGen @@ -57,36 +55,6 @@ static void emitBuiltinMathModf(IrRegAllocX64& regs, AssemblyBuilderX64& build, } } -static void emitBuiltinMathSign(IrRegAllocX64& regs, AssemblyBuilderX64& build, int ra, int arg) -{ - CODEGEN_ASSERT(!FFlag::LuauCodegenMathSign); - - ScopedRegX64 tmp0{regs, SizeX64::xmmword}; - ScopedRegX64 tmp1{regs, SizeX64::xmmword}; - ScopedRegX64 tmp2{regs, SizeX64::xmmword}; - ScopedRegX64 tmp3{regs, SizeX64::xmmword}; - - build.vmovsd(tmp0.reg, luauRegValue(arg)); - build.vxorpd(tmp1.reg, tmp1.reg, tmp1.reg); - - // Set tmp2 to -1 if arg < 0, else 0 - build.vcmpltsd(tmp2.reg, tmp0.reg, tmp1.reg); - build.vmovsd(tmp3.reg, build.f64(-1)); - build.vandpd(tmp2.reg, tmp2.reg, tmp3.reg); - - // Set mask bit to 1 if 0 < arg, else 0 - build.vcmpltsd(tmp0.reg, tmp1.reg, tmp0.reg); - - // Result = (mask-bit == 1) ? 1.0 : tmp2 - // If arg < 0 then tmp2 is -1 and mask-bit is 0, result is -1 - // If arg == 0 then tmp2 is 0 and mask-bit is 0, result is 0 - // If arg > 0 then tmp2 is 0 and mask-bit is 1, result is 1 - build.vblendvpd(tmp0.reg, tmp2.reg, build.f64x2(1, 1), tmp0.reg); - - build.vmovsd(luauRegValue(ra), tmp0.reg); - build.mov(luauRegTag(ra), LUA_TNUMBER); -} - void emitBuiltin(IrRegAllocX64& regs, AssemblyBuilderX64& build, int bfid, int ra, int arg, int nresults) { switch (bfid) @@ -97,10 +65,6 @@ void emitBuiltin(IrRegAllocX64& regs, AssemblyBuilderX64& build, int bfid, int r case LBF_MATH_MODF: CODEGEN_ASSERT(nresults == 1 || nresults == 2); return emitBuiltinMathModf(regs, build, ra, arg, nresults); - case LBF_MATH_SIGN: - CODEGEN_ASSERT(!FFlag::LuauCodegenMathSign); - CODEGEN_ASSERT(nresults == 1); - return emitBuiltinMathSign(regs, build, ra, arg); default: CODEGEN_ASSERT(!"Missing x64 lowering"); } diff --git a/Dependencies/luau/Luau/CodeGen/src/IrBuilder.cpp b/Dependencies/luau/Luau/CodeGen/src/IrBuilder.cpp index 53def728..3e6f85d8 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrBuilder.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrBuilder.cpp @@ -13,8 +13,6 @@ #include -LUAU_FASTFLAG(LuauCodegenFastcall3) - namespace Luau { namespace CodeGen @@ -458,8 +456,6 @@ void IrBuilder::translateInst(LuauOpcode op, const Instruction* pc, int i) handleFastcallFallback(translateFastCallN(*this, pc, i, true, 2, vmConst(pc[1]), undef()), pc, i); break; case LOP_FASTCALL3: - CODEGEN_ASSERT(FFlag::LuauCodegenFastcall3); - handleFastcallFallback(translateFastCallN(*this, pc, i, true, 3, vmReg(pc[1] & 0xff), vmReg((pc[1] >> 8) & 0xff)), pc, i); break; case LOP_FORNPREP: diff --git a/Dependencies/luau/Luau/CodeGen/src/IrLoweringA64.cpp b/Dependencies/luau/Luau/CodeGen/src/IrLoweringA64.cpp index f40faa2d..cd73bcbb 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrLoweringA64.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrLoweringA64.cpp @@ -11,8 +11,7 @@ #include "lstate.h" #include "lgc.h" -LUAU_FASTFLAG(LuauCodegenFastcall3) -LUAU_FASTFLAG(LuauCodegenMathSign) +LUAU_FASTFLAGVARIABLE(LuauCodegenArmNumToVecFix, false) namespace Luau { @@ -235,25 +234,6 @@ static bool emitBuiltin(AssemblyBuilderA64& build, IrFunction& function, IrRegAl } return true; } - case LBF_MATH_SIGN: - { - CODEGEN_ASSERT(!FFlag::LuauCodegenMathSign); - CODEGEN_ASSERT(nresults == 1); - build.ldr(d0, mem(rBase, arg * sizeof(TValue) + offsetof(TValue, value.n))); - build.fcmpz(d0); - build.fmov(d0, 0.0); - build.fmov(d1, 1.0); - build.fcsel(d0, d1, d0, getConditionFP(IrCondition::Greater)); - build.fmov(d1, -1.0); - build.fcsel(d0, d1, d0, getConditionFP(IrCondition::Less)); - build.str(d0, mem(rBase, res * sizeof(TValue) + offsetof(TValue, value.n))); - - RegisterA64 temp = regs.allocTemp(KindA64::w); - build.mov(temp, LUA_TNUMBER); - build.str(temp, mem(rBase, res * sizeof(TValue) + offsetof(TValue, tt))); - - return true; - } default: CODEGEN_ASSERT(!"Missing A64 lowering"); @@ -701,8 +681,6 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) } case IrCmd::SIGN_NUM: { - CODEGEN_ASSERT(FFlag::LuauCodegenMathSign); - inst.regA64 = regs.allocReuse(KindA64::d, index, {inst.a}); RegisterA64 temp = tempDouble(inst.a); @@ -1143,7 +1121,7 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) else { RegisterA64 tempd = tempDouble(inst.a); - RegisterA64 temps = castReg(KindA64::s, tempd); + RegisterA64 temps = FFlag::LuauCodegenArmNumToVecFix ? regs.allocTemp(KindA64::s) : castReg(KindA64::s, tempd); build.fcvt(temps, tempd); build.dup_4s(inst.regA64, castReg(KindA64::q, temps), 0); @@ -1194,87 +1172,53 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) case IrCmd::FASTCALL: regs.spill(build, index); - if (FFlag::LuauCodegenFastcall3) - error |= !emitBuiltin(build, function, regs, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.d)); - else - error |= !emitBuiltin(build, function, regs, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.f)); - + error |= !emitBuiltin(build, function, regs, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.d)); break; case IrCmd::INVOKE_FASTCALL: { - if (FFlag::LuauCodegenFastcall3) - { - // We might need a temporary and we have to preserve it over the spill - RegisterA64 temp = regs.allocTemp(KindA64::q); - regs.spill(build, index, {temp}); + // We might need a temporary and we have to preserve it over the spill + RegisterA64 temp = regs.allocTemp(KindA64::q); + regs.spill(build, index, {temp}); - build.mov(x0, rState); - build.add(x1, rBase, uint16_t(vmRegOp(inst.b) * sizeof(TValue))); - build.add(x2, rBase, uint16_t(vmRegOp(inst.c) * sizeof(TValue))); - build.mov(w3, intOp(inst.g)); // nresults - - // 'E' argument can only be produced by LOP_FASTCALL3 lowering - if (inst.e.kind != IrOpKind::Undef) - { - CODEGEN_ASSERT(intOp(inst.f) == 3); + build.mov(x0, rState); + build.add(x1, rBase, uint16_t(vmRegOp(inst.b) * sizeof(TValue))); + build.add(x2, rBase, uint16_t(vmRegOp(inst.c) * sizeof(TValue))); + build.mov(w3, intOp(inst.g)); // nresults - build.ldr(x4, mem(rState, offsetof(lua_State, top))); + // 'E' argument can only be produced by LOP_FASTCALL3 lowering + if (inst.e.kind != IrOpKind::Undef) + { + CODEGEN_ASSERT(intOp(inst.f) == 3); - build.ldr(temp, mem(rBase, vmRegOp(inst.d) * sizeof(TValue))); - build.str(temp, mem(x4, 0)); + build.ldr(x4, mem(rState, offsetof(lua_State, top))); - build.ldr(temp, mem(rBase, vmRegOp(inst.e) * sizeof(TValue))); - build.str(temp, mem(x4, sizeof(TValue))); - } - else - { - if (inst.d.kind == IrOpKind::VmReg) - build.add(x4, rBase, uint16_t(vmRegOp(inst.d) * sizeof(TValue))); - else if (inst.d.kind == IrOpKind::VmConst) - emitAddOffset(build, x4, rConstants, vmConstOp(inst.d) * sizeof(TValue)); - else - CODEGEN_ASSERT(inst.d.kind == IrOpKind::Undef); - } + build.ldr(temp, mem(rBase, vmRegOp(inst.d) * sizeof(TValue))); + build.str(temp, mem(x4, 0)); - // nparams - if (intOp(inst.f) == LUA_MULTRET) - { - // L->top - (ra + 1) - build.ldr(x5, mem(rState, offsetof(lua_State, top))); - build.sub(x5, x5, rBase); - build.sub(x5, x5, uint16_t((vmRegOp(inst.b) + 1) * sizeof(TValue))); - build.lsr(x5, x5, kTValueSizeLog2); - } - else - build.mov(w5, intOp(inst.f)); + build.ldr(temp, mem(rBase, vmRegOp(inst.e) * sizeof(TValue))); + build.str(temp, mem(x4, sizeof(TValue))); } else { - regs.spill(build, index); - build.mov(x0, rState); - build.add(x1, rBase, uint16_t(vmRegOp(inst.b) * sizeof(TValue))); - build.add(x2, rBase, uint16_t(vmRegOp(inst.c) * sizeof(TValue))); - build.mov(w3, intOp(inst.f)); // nresults - if (inst.d.kind == IrOpKind::VmReg) build.add(x4, rBase, uint16_t(vmRegOp(inst.d) * sizeof(TValue))); else if (inst.d.kind == IrOpKind::VmConst) emitAddOffset(build, x4, rConstants, vmConstOp(inst.d) * sizeof(TValue)); else CODEGEN_ASSERT(inst.d.kind == IrOpKind::Undef); + } - // nparams - if (intOp(inst.e) == LUA_MULTRET) - { - // L->top - (ra + 1) - build.ldr(x5, mem(rState, offsetof(lua_State, top))); - build.sub(x5, x5, rBase); - build.sub(x5, x5, uint16_t((vmRegOp(inst.b) + 1) * sizeof(TValue))); - build.lsr(x5, x5, kTValueSizeLog2); - } - else - build.mov(w5, intOp(inst.e)); + // nparams + if (intOp(inst.f) == LUA_MULTRET) + { + // L->top - (ra + 1) + build.ldr(x5, mem(rState, offsetof(lua_State, top))); + build.sub(x5, x5, rBase); + build.sub(x5, x5, uint16_t((vmRegOp(inst.b) + 1) * sizeof(TValue))); + build.lsr(x5, x5, kTValueSizeLog2); } + else + build.mov(w5, intOp(inst.f)); build.ldr(x6, mem(rNativeContext, offsetof(NativeContext, luauF_table) + uintOp(inst.a) * sizeof(luau_FastFunction))); build.blr(x6); diff --git a/Dependencies/luau/Luau/CodeGen/src/IrLoweringX64.cpp b/Dependencies/luau/Luau/CodeGen/src/IrLoweringX64.cpp index 76d88955..d06cef13 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrLoweringX64.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrLoweringX64.cpp @@ -15,9 +15,6 @@ #include "lstate.h" #include "lgc.h" -LUAU_FASTFLAG(LuauCodegenFastcall3) -LUAU_FASTFLAG(LuauCodegenMathSign) - namespace Luau { namespace CodeGen @@ -596,8 +593,6 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) break; case IrCmd::SIGN_NUM: { - CODEGEN_ASSERT(FFlag::LuauCodegenMathSign); - inst.regX64 = regs.allocRegOrReuse(SizeX64::xmmword, index, {inst.a}); ScopedRegX64 tmp0{regs, SizeX64::xmmword}; @@ -1038,10 +1033,7 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) case IrCmd::FASTCALL: { - if (FFlag::LuauCodegenFastcall3) - emitBuiltin(regs, build, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.d)); - else - emitBuiltin(regs, build, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.f)); + emitBuiltin(regs, build, uintOp(inst.a), vmRegOp(inst.b), vmRegOp(inst.c), intOp(inst.d)); break; } case IrCmd::INVOKE_FASTCALL: @@ -1052,7 +1044,7 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) ScopedRegX64 argsAlt{regs}; // 'E' argument can only be produced by LOP_FASTCALL3 - if (FFlag::LuauCodegenFastcall3 && inst.e.kind != IrOpKind::Undef) + if (inst.e.kind != IrOpKind::Undef) { CODEGEN_ASSERT(intOp(inst.f) == 3); @@ -1079,8 +1071,8 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) int ra = vmRegOp(inst.b); int arg = vmRegOp(inst.c); - int nparams = intOp(FFlag::LuauCodegenFastcall3 ? inst.f : inst.e); - int nresults = intOp(FFlag::LuauCodegenFastcall3 ? inst.g : inst.f); + int nparams = intOp(inst.f); + int nresults = intOp(inst.g); IrCallWrapperX64 callWrap(regs, build, index); callWrap.addArgument(SizeX64::qword, rState); @@ -1088,7 +1080,7 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next) callWrap.addArgument(SizeX64::qword, luauRegAddress(arg)); callWrap.addArgument(SizeX64::dword, nresults); - if (FFlag::LuauCodegenFastcall3 && inst.e.kind != IrOpKind::Undef) + if (inst.e.kind != IrOpKind::Undef) callWrap.addArgument(SizeX64::qword, argsAlt); else callWrap.addArgument(SizeX64::qword, args); diff --git a/Dependencies/luau/Luau/CodeGen/src/IrTranslateBuiltins.cpp b/Dependencies/luau/Luau/CodeGen/src/IrTranslateBuiltins.cpp index 7abab9f0..52efaef1 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrTranslateBuiltins.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrTranslateBuiltins.cpp @@ -8,9 +8,6 @@ #include -LUAU_FASTFLAG(LuauCodegenFastcall3) -LUAU_FASTFLAGVARIABLE(LuauCodegenMathSign, false) - // TODO: when nresults is less than our actual result count, we can skip computing/writing unused results static const int kMinMaxUnrolledParams = 5; @@ -39,33 +36,6 @@ static IrOp builtinLoadDouble(IrBuilder& build, IrOp arg) // Wrapper code for all builtins with a fixed signature and manual assembly lowering of the body -// (number, ...) -> number -static BuiltinImplResult translateBuiltinNumberToNumber( - IrBuilder& build, - LuauBuiltinFunction bfid, - int nparams, - int ra, - int arg, - IrOp args, - int nresults, - int pcpos -) -{ - CODEGEN_ASSERT(!FFlag::LuauCodegenMathSign); - - if (nparams < 1 || nresults > 1) - return {BuiltinImplType::None, -1}; - - builtinCheckDouble(build, build.vmReg(arg), pcpos); - - if (FFlag::LuauCodegenFastcall3) - build.inst(IrCmd::FASTCALL, build.constUint(bfid), build.vmReg(ra), build.vmReg(arg), build.constInt(1)); - else - build.inst(IrCmd::FASTCALL, build.constUint(bfid), build.vmReg(ra), build.vmReg(arg), args, build.constInt(1), build.constInt(1)); - - return {BuiltinImplType::Full, 1}; -} - static BuiltinImplResult translateBuiltinNumberToNumberLibm( IrBuilder& build, LuauBuiltinFunction bfid, @@ -142,18 +112,7 @@ static BuiltinImplResult translateBuiltinNumberTo2Number( builtinCheckDouble(build, build.vmReg(arg), pcpos); - if (FFlag::LuauCodegenFastcall3) - build.inst(IrCmd::FASTCALL, build.constUint(bfid), build.vmReg(ra), build.vmReg(arg), build.constInt(nresults == 1 ? 1 : 2)); - else - build.inst( - IrCmd::FASTCALL, - build.constUint(bfid), - build.vmReg(ra), - build.vmReg(arg), - build.undef(), - build.constInt(1), - build.constInt(nresults == 1 ? 1 : 2) - ); + build.inst(IrCmd::FASTCALL, build.constUint(bfid), build.vmReg(ra), build.vmReg(arg), build.constInt(nresults == 1 ? 1 : 2)); return {BuiltinImplType::Full, 2}; } @@ -250,10 +209,10 @@ static BuiltinImplResult translateBuiltinMathMinMax( builtinCheckDouble(build, build.vmReg(arg), pcpos); builtinCheckDouble(build, args, pcpos); - if (FFlag::LuauCodegenFastcall3 && nparams >= 3) + if (nparams >= 3) builtinCheckDouble(build, arg3, pcpos); - for (int i = (FFlag::LuauCodegenFastcall3 ? 4 : 3); i <= nparams; ++i) + for (int i = 4; i <= nparams; ++i) builtinCheckDouble(build, build.vmReg(vmRegOp(args) + (i - 2)), pcpos); IrOp varg1 = builtinLoadDouble(build, build.vmReg(arg)); @@ -261,13 +220,13 @@ static BuiltinImplResult translateBuiltinMathMinMax( IrOp res = build.inst(cmd, varg2, varg1); // Swapped arguments are required for consistency with VM builtins - if (FFlag::LuauCodegenFastcall3 && nparams >= 3) + if (nparams >= 3) { IrOp arg = builtinLoadDouble(build, arg3); res = build.inst(cmd, arg, res); } - for (int i = (FFlag::LuauCodegenFastcall3 ? 4 : 3); i <= nparams; ++i) + for (int i = 4; i <= nparams; ++i) { IrOp arg = builtinLoadDouble(build, build.vmReg(vmRegOp(args) + (i - 2))); res = build.inst(cmd, arg, res); @@ -302,10 +261,10 @@ static BuiltinImplResult translateBuiltinMathClamp( builtinCheckDouble(build, build.vmReg(arg), pcpos); builtinCheckDouble(build, args, pcpos); - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1), pcpos); + builtinCheckDouble(build, arg3, pcpos); IrOp min = builtinLoadDouble(build, args); - IrOp max = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1)); + IrOp max = builtinLoadDouble(build, arg3); build.inst(IrCmd::JUMP_CMP_NUM, min, max, build.cond(IrCondition::NotLessEqual), fallback, block); build.beginBlock(block); @@ -386,10 +345,10 @@ static BuiltinImplResult translateBuiltinBit32BinaryOp( builtinCheckDouble(build, build.vmReg(arg), pcpos); builtinCheckDouble(build, args, pcpos); - if (FFlag::LuauCodegenFastcall3 && nparams >= 3) + if (nparams >= 3) builtinCheckDouble(build, arg3, pcpos); - for (int i = (FFlag::LuauCodegenFastcall3 ? 4 : 3); i <= nparams; ++i) + for (int i = 4; i <= nparams; ++i) builtinCheckDouble(build, build.vmReg(vmRegOp(args) + (i - 2)), pcpos); IrOp va = builtinLoadDouble(build, build.vmReg(arg)); @@ -400,7 +359,7 @@ static BuiltinImplResult translateBuiltinBit32BinaryOp( IrOp res = build.inst(cmd, vaui, vbui); - if (FFlag::LuauCodegenFastcall3 && nparams >= 3) + if (nparams >= 3) { IrOp vc = builtinLoadDouble(build, arg3); IrOp arg = build.inst(IrCmd::NUM_TO_UINT, vc); @@ -408,7 +367,7 @@ static BuiltinImplResult translateBuiltinBit32BinaryOp( res = build.inst(cmd, res, arg); } - for (int i = (FFlag::LuauCodegenFastcall3 ? 4 : 3); i <= nparams; ++i) + for (int i = 4; i <= nparams; ++i) { IrOp vc = builtinLoadDouble(build, build.vmReg(vmRegOp(args) + (i - 2))); IrOp arg = build.inst(IrCmd::NUM_TO_UINT, vc); @@ -599,8 +558,8 @@ static BuiltinImplResult translateBuiltinBit32Extract( { IrOp f = build.inst(IrCmd::NUM_TO_INT, vb); - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(args.index + 1), pcpos); - IrOp vc = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(args.index + 1)); + builtinCheckDouble(build, arg3, pcpos); + IrOp vc = builtinLoadDouble(build, arg3); IrOp w = build.inst(IrCmd::NUM_TO_INT, vc); IrOp block1 = build.block(IrBlockKind::Internal); @@ -705,11 +664,11 @@ static BuiltinImplResult translateBuiltinBit32Replace( builtinCheckDouble(build, build.vmReg(arg), pcpos); builtinCheckDouble(build, args, pcpos); - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(args.index + 1), pcpos); + builtinCheckDouble(build, arg3, pcpos); IrOp va = builtinLoadDouble(build, build.vmReg(arg)); IrOp vb = builtinLoadDouble(build, args); - IrOp vc = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(args.index + 1)); + IrOp vc = builtinLoadDouble(build, arg3); IrOp n = build.inst(IrCmd::NUM_TO_UINT, va); IrOp v = build.inst(IrCmd::NUM_TO_UINT, vb); @@ -734,8 +693,8 @@ static BuiltinImplResult translateBuiltinBit32Replace( } else { - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? build.vmReg(vmRegOp(args) + 2) : build.vmReg(args.index + 2), pcpos); - IrOp vd = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? build.vmReg(vmRegOp(args) + 2) : build.vmReg(args.index + 2)); + builtinCheckDouble(build, build.vmReg(vmRegOp(args) + 2), pcpos); + IrOp vd = builtinLoadDouble(build, build.vmReg(vmRegOp(args) + 2)); IrOp w = build.inst(IrCmd::NUM_TO_INT, vd); IrOp block1 = build.block(IrBlockKind::Internal); @@ -781,11 +740,11 @@ static BuiltinImplResult translateBuiltinVector(IrBuilder& build, int nparams, i builtinCheckDouble(build, build.vmReg(arg), pcpos); builtinCheckDouble(build, args, pcpos); - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1), pcpos); + builtinCheckDouble(build, arg3, pcpos); IrOp x = builtinLoadDouble(build, build.vmReg(arg)); IrOp y = builtinLoadDouble(build, args); - IrOp z = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1)); + IrOp z = builtinLoadDouble(build, arg3); build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), x, y, z); build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR)); @@ -863,7 +822,7 @@ static void translateBufferArgsAndCheckBounds( builtinCheckDouble(build, args, pcpos); if (nparams == 3) - builtinCheckDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1), pcpos); + builtinCheckDouble(build, arg3, pcpos); buf = build.inst(IrCmd::LOAD_POINTER, build.vmReg(arg)); @@ -920,7 +879,7 @@ static BuiltinImplResult translateBuiltinBufferWrite( IrOp buf, intIndex; translateBufferArgsAndCheckBounds(build, nparams, arg, args, arg3, size, pcpos, buf, intIndex); - IrOp numValue = builtinLoadDouble(build, FFlag::LuauCodegenFastcall3 ? arg3 : build.vmReg(vmRegOp(args) + 1)); + IrOp numValue = builtinLoadDouble(build, arg3); build.inst(writeCmd, buf, intIndex, convCmd == IrCmd::NOP ? numValue : build.inst(convCmd, numValue)); return {BuiltinImplType::Full, 0}; @@ -982,10 +941,7 @@ BuiltinImplResult translateBuiltin( case LBF_MATH_LOG10: return translateBuiltinNumberToNumberLibm(build, LuauBuiltinFunction(bfid), nparams, ra, arg, nresults, pcpos); case LBF_MATH_SIGN: - if (FFlag::LuauCodegenMathSign) - return translateBuiltinMathUnary(build, IrCmd::SIGN_NUM, nparams, ra, arg, nresults, pcpos); - else - return translateBuiltinNumberToNumber(build, LuauBuiltinFunction(bfid), nparams, ra, arg, args, nresults, pcpos); + return translateBuiltinMathUnary(build, IrCmd::SIGN_NUM, nparams, ra, arg, nresults, pcpos); case LBF_MATH_POW: case LBF_MATH_FMOD: case LBF_MATH_ATAN2: diff --git a/Dependencies/luau/Luau/CodeGen/src/IrTranslation.cpp b/Dependencies/luau/Luau/CodeGen/src/IrTranslation.cpp index 5d6aa95a..62829766 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrTranslation.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrTranslation.cpp @@ -13,8 +13,6 @@ #include "lstate.h" #include "ltm.h" -LUAU_FASTFLAG(LuauCodegenFastcall3) - namespace Luau { namespace CodeGen @@ -767,7 +765,7 @@ IrOp translateFastCallN(IrBuilder& build, const Instruction* pc, int pcpos, bool builtinArgs = build.constDouble(protok.value.n); } - IrOp builtinArg3 = FFlag::LuauCodegenFastcall3 ? (customParams ? customArg3 : build.vmReg(ra + 3)) : IrOp{}; + IrOp builtinArg3 = customParams ? customArg3 : build.vmReg(ra + 3); IrOp fallback = build.block(IrBlockKind::Fallback); @@ -793,7 +791,7 @@ IrOp translateFastCallN(IrBuilder& build, const Instruction* pc, int pcpos, bool return build.undef(); } } - else if (FFlag::LuauCodegenFastcall3) + else { IrOp arg3 = customParams ? customArg3 : build.undef(); @@ -817,21 +815,6 @@ IrOp translateFastCallN(IrBuilder& build, const Instruction* pc, int pcpos, bool else if (nparams == LUA_MULTRET) build.inst(IrCmd::ADJUST_STACK_TO_TOP); } - else - { - // TODO: we can skip saving pc for some well-behaved builtins which we didn't inline - build.inst(IrCmd::SET_SAVEDPC, build.constUint(pcpos + getOpLength(opcode))); - - IrOp res = build.inst( - IrCmd::INVOKE_FASTCALL, build.constUint(bfid), build.vmReg(ra), build.vmReg(arg), args, build.constInt(nparams), build.constInt(nresults) - ); - build.inst(IrCmd::CHECK_FASTCALL_RES, res, fallback); - - if (nresults == LUA_MULTRET) - build.inst(IrCmd::ADJUST_STACK_TO_REG, build.vmReg(ra), res); - else if (nparams == LUA_MULTRET) - build.inst(IrCmd::ADJUST_STACK_TO_TOP); - } return fallback; } diff --git a/Dependencies/luau/Luau/CodeGen/src/IrValueLocationTracking.cpp b/Dependencies/luau/Luau/CodeGen/src/IrValueLocationTracking.cpp index 0224b49b..050b951e 100644 --- a/Dependencies/luau/Luau/CodeGen/src/IrValueLocationTracking.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/IrValueLocationTracking.cpp @@ -3,8 +3,6 @@ #include "Luau/IrUtils.h" -LUAU_FASTFLAG(LuauCodegenFastcall3) - namespace Luau { namespace CodeGen @@ -46,11 +44,11 @@ void IrValueLocationTracking::beforeInstLowering(IrInst& inst) invalidateRestoreVmRegs(vmRegOp(inst.a), -1); break; case IrCmd::FASTCALL: - invalidateRestoreVmRegs(vmRegOp(inst.b), function.intOp(FFlag::LuauCodegenFastcall3 ? inst.d : inst.f)); + invalidateRestoreVmRegs(vmRegOp(inst.b), function.intOp(inst.d)); break; case IrCmd::INVOKE_FASTCALL: // Multiple return sequences (count == -1) are defined by ADJUST_STACK_TO_REG - if (int count = function.intOp(FFlag::LuauCodegenFastcall3 ? inst.g : inst.f); count != -1) + if (int count = function.intOp(inst.g); count != -1) invalidateRestoreVmRegs(vmRegOp(inst.b), count); break; case IrCmd::DO_ARITH: diff --git a/Dependencies/luau/Luau/CodeGen/src/OptimizeConstProp.cpp b/Dependencies/luau/Luau/CodeGen/src/OptimizeConstProp.cpp index e7207731..f3271d3f 100644 --- a/Dependencies/luau/Luau/CodeGen/src/OptimizeConstProp.cpp +++ b/Dependencies/luau/Luau/CodeGen/src/OptimizeConstProp.cpp @@ -18,8 +18,6 @@ LUAU_FASTINTVARIABLE(LuauCodeGenMinLinearBlockPath, 3) LUAU_FASTINTVARIABLE(LuauCodeGenReuseSlotLimit, 64) LUAU_FASTINTVARIABLE(LuauCodeGenReuseUdataTagLimit, 64) LUAU_FASTFLAGVARIABLE(DebugLuauAbortingChecks, false) -LUAU_FASTFLAG(LuauCodegenFastcall3) -LUAU_FASTFLAG(LuauCodegenMathSign) namespace Luau { @@ -1119,7 +1117,7 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction& { LuauBuiltinFunction bfid = LuauBuiltinFunction(function.uintOp(inst.a)); int firstReturnReg = vmRegOp(inst.b); - int nresults = function.intOp(FFlag::LuauCodegenFastcall3 ? inst.d : inst.f); + int nresults = function.intOp(inst.d); // TODO: FASTCALL is more restrictive than INVOKE_FASTCALL; we should either determine the exact semantics, or rework it handleBuiltinEffects(state, bfid, firstReturnReg, nresults); @@ -1133,19 +1131,13 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction& if (nresults > 1) state.updateTag(IrOp{IrOpKind::VmReg, uint8_t(firstReturnReg + 1)}, LUA_TNUMBER); break; - case LBF_MATH_SIGN: - CODEGEN_ASSERT(!FFlag::LuauCodegenMathSign); - state.updateTag(IrOp{IrOpKind::VmReg, uint8_t(firstReturnReg)}, LUA_TNUMBER); - break; default: break; } break; } case IrCmd::INVOKE_FASTCALL: - handleBuiltinEffects( - state, LuauBuiltinFunction(function.uintOp(inst.a)), vmRegOp(inst.b), function.intOp(FFlag::LuauCodegenFastcall3 ? inst.g : inst.f) - ); + handleBuiltinEffects(state, LuauBuiltinFunction(function.uintOp(inst.a)), vmRegOp(inst.b), function.intOp(inst.g)); break; // These instructions don't have an effect on register/memory state we are tracking diff --git a/Dependencies/luau/Luau/Common/include/Luau/Bytecode.h b/Dependencies/luau/Luau/Common/include/Luau/Bytecode.h index 1603d205..82185e7f 100644 --- a/Dependencies/luau/Luau/Common/include/Luau/Bytecode.h +++ b/Dependencies/luau/Luau/Common/include/Luau/Bytecode.h @@ -441,7 +441,7 @@ enum LuauBytecodeTag // Bytecode version; runtime supports [MIN, MAX], compiler emits TARGET by default but may emit a higher version when flags are enabled LBC_VERSION_MIN = 3, LBC_VERSION_MAX = 6, - LBC_VERSION_TARGET = 5, + LBC_VERSION_TARGET = 6, // Type encoding version LBC_TYPE_VERSION_MIN = 1, LBC_TYPE_VERSION_MAX = 3, diff --git a/Dependencies/luau/Luau/Common/include/Luau/Common.h b/Dependencies/luau/Luau/Common/include/Luau/Common.h index 406f6553..2f4f1df8 100644 --- a/Dependencies/luau/Luau/Common/include/Luau/Common.h +++ b/Dependencies/luau/Luau/Common/include/Luau/Common.h @@ -20,6 +20,19 @@ #define LUAU_DEBUGBREAK() __builtin_trap() #endif +// LUAU_FALLTHROUGH is a C++11-compatible alternative to [[fallthrough]] for use in the VM library +#if defined(__clang__) && defined(__has_warning) +#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +#define LUAU_FALLTHROUGH [[clang::fallthrough]] +#else +#define LUAU_FALLTHROUGH +#endif +#elif defined(__GNUC__) && __GNUC__ >= 7 +#define LUAU_FALLTHROUGH [[gnu::fallthrough]] +#else +#define LUAU_FALLTHROUGH +#endif + #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define LUAU_BIG_ENDIAN #endif diff --git a/Dependencies/luau/Luau/Common/include/Luau/ExperimentalFlags.h b/Dependencies/luau/Luau/Common/include/Luau/ExperimentalFlags.h index f83de70b..c534bcb4 100644 --- a/Dependencies/luau/Luau/Common/include/Luau/ExperimentalFlags.h +++ b/Dependencies/luau/Luau/Common/include/Luau/ExperimentalFlags.h @@ -13,7 +13,8 @@ inline bool isFlagExperimental(const char* flag) static const char* const kList[] = { "LuauInstantiateInSubtyping", // requires some fixes to lua-apps code "LuauFixIndexerSubtypingOrdering", // requires some small fixes to lua-apps code since this fixes a false negative - "StudioReportLuauAny", // takes telemetry data for usage of any types + "StudioReportLuauAny2", // takes telemetry data for usage of any types + "LuauSolverV2", // makes sure we always have at least one entry nullptr, }; diff --git a/Dependencies/luau/Luau/Compiler/src/BytecodeBuilder.cpp b/Dependencies/luau/Luau/Compiler/src/BytecodeBuilder.cpp index 2e9bd88c..685d94fa 100644 --- a/Dependencies/luau/Luau/Compiler/src/BytecodeBuilder.cpp +++ b/Dependencies/luau/Luau/Compiler/src/BytecodeBuilder.cpp @@ -7,9 +7,6 @@ #include #include -LUAU_FASTFLAG(LuauCompileUserdataInfo) -LUAU_FASTFLAG(LuauCompileFastcall3) - namespace Luau { @@ -334,8 +331,6 @@ unsigned int BytecodeBuilder::addStringTableEntry(StringRef value) const char* BytecodeBuilder::tryGetUserdataTypeName(LuauBytecodeType type) const { - LUAU_ASSERT(FFlag::LuauCompileUserdataInfo); - unsigned index = unsigned((type & ~LBC_TYPE_OPTIONAL_BIT) - LBC_TYPE_TAGGED_USERDATA_BASE); if (index < userdataTypes.size()) @@ -575,8 +570,6 @@ void BytecodeBuilder::pushUpvalTypeInfo(LuauBytecodeType type) uint32_t BytecodeBuilder::addUserdataType(const char* name) { - LUAU_ASSERT(FFlag::LuauCompileUserdataInfo); - UserdataType ty; ty.name = name; @@ -587,8 +580,6 @@ uint32_t BytecodeBuilder::addUserdataType(const char* name) void BytecodeBuilder::useUserdataType(uint32_t index) { - LUAU_ASSERT(FFlag::LuauCompileUserdataInfo); - userdataTypes[index].used = true; } @@ -673,13 +664,10 @@ void BytecodeBuilder::finalize() { LUAU_ASSERT(bytecode.empty()); - if (FFlag::LuauCompileUserdataInfo) + for (auto& ty : userdataTypes) { - for (auto& ty : userdataTypes) - { - if (ty.used) - ty.nameRef = addStringTableEntry(StringRef({ty.name.c_str(), ty.name.length()})); - } + if (ty.used) + ty.nameRef = addStringTableEntry(StringRef({ty.name.c_str(), ty.name.length()})); } // preallocate space for bytecode blob @@ -705,7 +693,6 @@ void BytecodeBuilder::finalize() writeStringTable(bytecode); - if (FFlag::LuauCompileUserdataInfo) { // Write the mapping between used type name indices and their name for (uint32_t i = 0; i < uint32_t(userdataTypes.size()); i++) @@ -1232,19 +1219,12 @@ std::string BytecodeBuilder::getError(const std::string& message) uint8_t BytecodeBuilder::getVersion() { - // This function usually returns LBC_VERSION_TARGET but may sometimes return a higher number (within LBC_VERSION_MIN/MAX) under fast flags - if (FFlag::LuauCompileFastcall3) - return 6; - return LBC_VERSION_TARGET; } uint8_t BytecodeBuilder::getTypeEncodingVersion() { - if (FFlag::LuauCompileUserdataInfo) - return LBC_TYPE_VERSION_TARGET; - - return 2; + return LBC_TYPE_VERSION_TARGET; } #ifdef LUAU_ASSERTENABLED @@ -1617,8 +1597,6 @@ void BytecodeBuilder::validateInstructions() const break; case LOP_FASTCALL3: - LUAU_ASSERT(FFlag::LuauCompileFastcall3); - VREG(LUAU_INSN_B(insn)); VJUMP(LUAU_INSN_C(insn)); LUAU_ASSERT(LUAU_INSN_OP(insns[i + 1 + LUAU_INSN_C(insn)]) == LOP_CALL); @@ -2240,8 +2218,6 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result, break; case LOP_FASTCALL3: - LUAU_ASSERT(FFlag::LuauCompileFastcall3); - formatAppend(result, "FASTCALL3 %d R%d R%d R%d L%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), *code & 0xff, (*code >> 8) & 0xff, targetLabel); code++; break; @@ -2373,74 +2349,38 @@ std::string BytecodeBuilder::dumpCurrentFunction(std::vector& dumpinstoffs) { const std::string& typeinfo = functions.back().typeinfo; - if (FFlag::LuauCompileUserdataInfo) + // Arguments start from third byte in function typeinfo string + for (uint8_t i = 2; i < typeinfo.size(); ++i) { - // Arguments start from third byte in function typeinfo string - for (uint8_t i = 2; i < typeinfo.size(); ++i) - { - uint8_t et = typeinfo[i]; - - const char* userdata = tryGetUserdataTypeName(LuauBytecodeType(et)); - const char* name = userdata ? userdata : getBaseTypeString(et); - const char* optional = (et & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - - formatAppend(result, "R%d: %s%s [argument]\n", i - 2, name, optional); - } - - for (size_t i = 0; i < typedUpvals.size(); ++i) - { - const TypedUpval& l = typedUpvals[i]; - - const char* userdata = tryGetUserdataTypeName(l.type); - const char* name = userdata ? userdata : getBaseTypeString(l.type); - const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - - formatAppend(result, "U%d: %s%s\n", int(i), name, optional); - } - - for (size_t i = 0; i < typedLocals.size(); ++i) - { - const TypedLocal& l = typedLocals[i]; + uint8_t et = typeinfo[i]; - const char* userdata = tryGetUserdataTypeName(l.type); - const char* name = userdata ? userdata : getBaseTypeString(l.type); - const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; + const char* userdata = tryGetUserdataTypeName(LuauBytecodeType(et)); + const char* name = userdata ? userdata : getBaseTypeString(et); + const char* optional = (et & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - formatAppend(result, "R%d: %s%s from %d to %d\n", l.reg, name, optional, l.startpc, l.endpc); - } + formatAppend(result, "R%d: %s%s [argument]\n", i - 2, name, optional); } - else - { - // Arguments start from third byte in function typeinfo string - for (uint8_t i = 2; i < typeinfo.size(); ++i) - { - uint8_t et = typeinfo[i]; - - const char* base = getBaseTypeString(et); - const char* optional = (et & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - formatAppend(result, "R%d: %s%s [argument]\n", i - 2, base, optional); - } - - for (size_t i = 0; i < typedUpvals.size(); ++i) - { - const TypedUpval& l = typedUpvals[i]; + for (size_t i = 0; i < typedUpvals.size(); ++i) + { + const TypedUpval& l = typedUpvals[i]; - const char* base = getBaseTypeString(l.type); - const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; + const char* userdata = tryGetUserdataTypeName(l.type); + const char* name = userdata ? userdata : getBaseTypeString(l.type); + const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - formatAppend(result, "U%d: %s%s\n", int(i), base, optional); - } + formatAppend(result, "U%d: %s%s\n", int(i), name, optional); + } - for (size_t i = 0; i < typedLocals.size(); ++i) - { - const TypedLocal& l = typedLocals[i]; + for (size_t i = 0; i < typedLocals.size(); ++i) + { + const TypedLocal& l = typedLocals[i]; - const char* base = getBaseTypeString(l.type); - const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; + const char* userdata = tryGetUserdataTypeName(l.type); + const char* name = userdata ? userdata : getBaseTypeString(l.type); + const char* optional = (l.type & LBC_TYPE_OPTIONAL_BIT) ? "?" : ""; - formatAppend(result, "R%d: %s%s from %d to %d\n", l.reg, base, optional, l.startpc, l.endpc); - } + formatAppend(result, "R%d: %s%s from %d to %d\n", l.reg, name, optional, l.startpc, l.endpc); } } diff --git a/Dependencies/luau/Luau/Compiler/src/Compiler.cpp b/Dependencies/luau/Luau/Compiler/src/Compiler.cpp index 93c31252..7ed70d14 100644 --- a/Dependencies/luau/Luau/Compiler/src/Compiler.cpp +++ b/Dependencies/luau/Luau/Compiler/src/Compiler.cpp @@ -26,9 +26,6 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25) LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300) LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5) -LUAU_FASTFLAGVARIABLE(LuauCompileUserdataInfo, false) -LUAU_FASTFLAGVARIABLE(LuauCompileFastcall3, false) - LUAU_FASTFLAG(LuauNativeAttribute) namespace Luau @@ -469,33 +466,19 @@ struct Compiler { LUAU_ASSERT(!expr->self); LUAU_ASSERT(expr->args.size >= 1); - - if (FFlag::LuauCompileFastcall3) - LUAU_ASSERT(expr->args.size <= 3); - else - LUAU_ASSERT(expr->args.size <= 2 || (bfid == LBF_BIT32_EXTRACTK && expr->args.size == 3)); - + LUAU_ASSERT(expr->args.size <= 3); LUAU_ASSERT(bfid == LBF_BIT32_EXTRACTK ? bfK >= 0 : bfK < 0); LuauOpcode opc = LOP_NOP; - if (FFlag::LuauCompileFastcall3) - { - if (expr->args.size == 1) - opc = LOP_FASTCALL1; - else if (bfK >= 0 || (expr->args.size == 2 && isConstant(expr->args.data[1]))) - opc = LOP_FASTCALL2K; - else if (expr->args.size == 2) - opc = LOP_FASTCALL2; - else - opc = LOP_FASTCALL3; - } + if (expr->args.size == 1) + opc = LOP_FASTCALL1; + else if (bfK >= 0 || (expr->args.size == 2 && isConstant(expr->args.data[1]))) + opc = LOP_FASTCALL2K; + else if (expr->args.size == 2) + opc = LOP_FASTCALL2; else - { - opc = expr->args.size == 1 ? LOP_FASTCALL1 - : (bfK >= 0 || (expr->args.size == 2 && isConstant(expr->args.data[1]))) ? LOP_FASTCALL2K - : LOP_FASTCALL2; - } + opc = LOP_FASTCALL3; uint32_t args[3] = {}; @@ -524,7 +507,7 @@ struct Compiler bytecode.emitABC(opc, uint8_t(bfid), uint8_t(args[0]), 0); - if (FFlag::LuauCompileFastcall3 && opc == LOP_FASTCALL3) + if (opc == LOP_FASTCALL3) { LUAU_ASSERT(bfK < 0); bytecode.emitAux(args[1] | (args[2] << 8)); @@ -886,7 +869,7 @@ struct Compiler unsigned maxFastcallArgs = 2; // Fastcall with 3 arguments is only used if it can help save one or more move instructions - if (FFlag::LuauCompileFastcall3 && bfid >= 0 && expr->args.size == 3) + if (bfid >= 0 && expr->args.size == 3) { for (size_t i = 0; i < expr->args.size; ++i) { @@ -899,7 +882,7 @@ struct Compiler } // Optimization: for 1/2/3 argument fast calls use specialized opcodes - if (bfid >= 0 && expr->args.size >= 1 && expr->args.size <= (FFlag::LuauCompileFastcall3 ? maxFastcallArgs : 2u)) + if (bfid >= 0 && expr->args.size >= 1 && expr->args.size <= maxFastcallArgs) { if (!isExprMultRet(expr->args.data[expr->args.size - 1])) { @@ -4231,20 +4214,17 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c predictTableShapes(compiler.tableShapes, root); } - if (FFlag::LuauCompileUserdataInfo) + if (const char* const* ptr = options.userdataTypes) { - if (const char* const* ptr = options.userdataTypes) + for (; *ptr; ++ptr) { - for (; *ptr; ++ptr) - { - // Type will only resolve to an AstName if it is actually mentioned in the source - if (AstName name = names.get(*ptr); name.value) - compiler.userdataTypes[name] = bytecode.addUserdataType(name.value); - } - - if (uintptr_t(ptr - options.userdataTypes) > (LBC_TYPE_TAGGED_USERDATA_END - LBC_TYPE_TAGGED_USERDATA_BASE)) - CompileError::raise(root->location, "Exceeded userdata type limit in the compilation options"); + // Type will only resolve to an AstName if it is actually mentioned in the source + if (AstName name = names.get(*ptr); name.value) + compiler.userdataTypes[name] = bytecode.addUserdataType(name.value); } + + if (uintptr_t(ptr - options.userdataTypes) > (LBC_TYPE_TAGGED_USERDATA_END - LBC_TYPE_TAGGED_USERDATA_BASE)) + CompileError::raise(root->location, "Exceeded userdata type limit in the compilation options"); } // computes type information for all functions based on type annotations diff --git a/Dependencies/luau/Luau/Compiler/src/Types.cpp b/Dependencies/luau/Luau/Compiler/src/Types.cpp index 0e7a3242..18dc248f 100644 --- a/Dependencies/luau/Luau/Compiler/src/Types.cpp +++ b/Dependencies/luau/Luau/Compiler/src/Types.cpp @@ -3,8 +3,6 @@ #include "Luau/BytecodeBuilder.h" -LUAU_FASTFLAG(LuauCompileUserdataInfo) - namespace Luau { @@ -70,13 +68,10 @@ static LuauBytecodeType getType( if (LuauBytecodeType prim = getPrimitiveType(ref->name); prim != LBC_TYPE_INVALID) return prim; - if (FFlag::LuauCompileUserdataInfo) + if (const uint8_t* userdataIndex = userdataTypes.find(ref->name)) { - if (const uint8_t* userdataIndex = userdataTypes.find(ref->name)) - { - bytecode.useUserdataType(*userdataIndex); - return LuauBytecodeType(LBC_TYPE_TAGGED_USERDATA_BASE + *userdataIndex); - } + bytecode.useUserdataType(*userdataIndex); + return LuauBytecodeType(LBC_TYPE_TAGGED_USERDATA_BASE + *userdataIndex); } // not primitive or alias or generic => host-provided, we assume userdata for now diff --git a/Dependencies/luau/Luau/EqSat/include/Luau/EGraph.h b/Dependencies/luau/Luau/EqSat/include/Luau/EGraph.h index 8344b0e5..480aa07d 100644 --- a/Dependencies/luau/Luau/EqSat/include/Luau/EGraph.h +++ b/Dependencies/luau/Luau/EqSat/include/Luau/EGraph.h @@ -5,7 +5,6 @@ #include "Luau/Id.h" #include "Luau/Language.h" #include "Luau/UnionFind.h" -#include "Luau/VecDeque.h" #include #include @@ -145,7 +144,7 @@ struct EGraph final /// The hashcons 𝐻 is a map from e-nodes to e-class ids. std::unordered_map hashcons; - VecDeque> worklist; + std::vector> worklist; private: void canonicalize(L& enode) @@ -183,7 +182,7 @@ struct EGraph final for (Id operand : enode.operands()) get(operand).parents.push_back({enode, id}); - worklist.push_back({enode, id}); + worklist.emplace_back(enode, id); hashcons.insert_or_assign(enode, id); return id; diff --git a/Dependencies/luau/Luau/EqSat/include/Luau/Language.h b/Dependencies/luau/Luau/EqSat/include/Luau/Language.h index 4aeb6c32..8855d851 100644 --- a/Dependencies/luau/Luau/EqSat/include/Luau/Language.h +++ b/Dependencies/luau/Luau/EqSat/include/Luau/Language.h @@ -7,7 +7,6 @@ #include "Luau/Variant.h" #include -#include #include #include @@ -233,12 +232,6 @@ struct Language final { } - Language(const Language&) noexcept = default; - Language& operator=(const Language&) noexcept = default; - - Language(Language&&) noexcept = default; - Language& operator=(Language&&) noexcept = default; - int index() const noexcept { return v.index(); diff --git a/Dependencies/luau/Luau/EqSat/include/Luau/LanguageHash.h b/Dependencies/luau/Luau/EqSat/include/Luau/LanguageHash.h index 7226132c..506f352b 100644 --- a/Dependencies/luau/Luau/EqSat/include/Luau/LanguageHash.h +++ b/Dependencies/luau/Luau/EqSat/include/Luau/LanguageHash.h @@ -3,6 +3,7 @@ #include #include +#include namespace Luau::EqSat { diff --git a/Dependencies/luau/Luau/EqSat/src/UnionFind.cpp b/Dependencies/luau/Luau/EqSat/src/UnionFind.cpp index 3c4825be..619c3f47 100644 --- a/Dependencies/luau/Luau/EqSat/src/UnionFind.cpp +++ b/Dependencies/luau/Luau/EqSat/src/UnionFind.cpp @@ -11,6 +11,7 @@ Id UnionFind::makeSet() Id id{parents.size()}; parents.push_back(id); ranks.push_back(0); + return id; } @@ -32,6 +33,7 @@ Id UnionFind::find(Id id) parents[size_t(id)] = set; id = parent; } + return set; } @@ -47,6 +49,7 @@ void UnionFind::merge(Id a, Id b) std::swap(aSet, bSet); parents[size_t(bSet)] = aSet; + if (ranks[size_t(aSet)] == ranks[size_t(bSet)]) ranks[size_t(aSet)]++; } diff --git a/Dependencies/luau/Luau/Makefile b/Dependencies/luau/Luau/Makefile index b86ec2a6..3e6b85ad 100644 --- a/Dependencies/luau/Luau/Makefile +++ b/Dependencies/luau/Luau/Makefile @@ -181,8 +181,7 @@ coverage: $(TESTS_TARGET) $(COMPILE_CLI_TARGET) mv default.profraw tests.profraw $(TESTS_TARGET) --fflags=true mv default.profraw tests-flags.profraw - # new solver is expected to fail tests at the moment, remove '!' once tests are fixed and this starts to fail - ! $(TESTS_TARGET) --fflags=true,DebugLuauDeferredConstraintResolution=true + $(TESTS_TARGET) --fflags=true,DebugLuauDeferredConstraintResolution=true mv default.profraw tests-dcr.profraw $(TESTS_TARGET) -ts=Conformance --codegen mv default.profraw codegen.profraw diff --git a/Dependencies/luau/Luau/VM/src/lstrlib.cpp b/Dependencies/luau/Luau/VM/src/lstrlib.cpp index 85669e97..b5a4bd13 100644 --- a/Dependencies/luau/Luau/VM/src/lstrlib.cpp +++ b/Dependencies/luau/Luau/VM/src/lstrlib.cpp @@ -552,9 +552,9 @@ static const char* match(MatchState* ms, const char* s, const char* p) } break; } - case '+': // 1 or more repetitions - s++; // 1 match already done - // go through + case '+': // 1 or more repetitions + s++; // 1 match already done + LUAU_FALLTHROUGH; // go through case '*': // 0 or more repetitions s = max_expand(ms, s, p, ep); break; @@ -1480,7 +1480,8 @@ static int str_pack(lua_State* L) break; } case Kpadding: - luaL_addchar(&b, LUAL_PACKPADBYTE); // FALLTHROUGH + luaL_addchar(&b, LUAL_PACKPADBYTE); + LUAU_FALLTHROUGH; case Kpaddalign: case Knop: arg--; // undo increment diff --git a/Dependencies/luau/Luau/VM/src/ltable.cpp b/Dependencies/luau/Luau/VM/src/ltable.cpp index c963ac8d..dafb2b3f 100644 --- a/Dependencies/luau/Luau/VM/src/ltable.cpp +++ b/Dependencies/luau/Luau/VM/src/ltable.cpp @@ -659,7 +659,7 @@ const TValue* luaH_get(Table* t, const TValue* key) luai_num2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) // index is int? return luaH_getnum(t, k); // use specialized version - // else go through + LUAU_FALLTHROUGH; // else go through } default: { diff --git a/Dependencies/luau/Luau/fuzz/proto.cpp b/Dependencies/luau/Luau/fuzz/proto.cpp index 9114f824..9c2ab35c 100644 --- a/Dependencies/luau/Luau/fuzz/proto.cpp +++ b/Dependencies/luau/Luau/fuzz/proto.cpp @@ -56,7 +56,7 @@ LUAU_FASTINT(LuauTypeInferIterationLimit) LUAU_FASTINT(LuauTarjanChildLimit) LUAU_FASTFLAG(DebugLuauFreezeArena) LUAU_FASTFLAG(DebugLuauAbortingChecks) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) std::chrono::milliseconds kInterruptTimeout(10); std::chrono::time_point interruptDeadline; @@ -247,7 +247,7 @@ DEFINE_PROTO_FUZZER(const luau::ModuleSet& message) FFlag::DebugLuauFreezeArena.value = true; FFlag::DebugLuauAbortingChecks.value = true; - FFlag::DebugLuauDeferredConstraintResolution.value = kFuzzUseNewSolver; + FFlag::LuauSolverV2.value = kFuzzUseNewSolver; std::vector sources = protoprint(message, kFuzzTypes); diff --git a/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp b/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp index aed7b7e5..5c3b4aa3 100644 --- a/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp +++ b/Dependencies/luau/Luau/tests/AnyTypeSummary.test.cpp @@ -5,6 +5,7 @@ #include "Fixture.h" +#include "ScopedFlags.h" #include "doctest.h" #include @@ -13,15 +14,14 @@ using namespace Luau; using Pattern = AnyTypeSummary::Pattern; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) -LUAU_FASTFLAG(DebugLuauFreezeArena); -LUAU_FASTFLAG(DebugLuauMagicTypes); +LUAU_FASTFLAG(LuauSolverV2) +LUAU_FASTFLAG(DebugLuauFreezeArena) +LUAU_FASTFLAG(DebugLuauMagicTypes) +LUAU_FASTFLAG(StudioReportLuauAny2) -LUAU_FASTFLAG(StudioReportLuauAny); struct ATSFixture : BuiltinsFixture { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; ATSFixture() { @@ -34,6 +34,11 @@ TEST_SUITE_BEGIN("AnyTypeSummaryTest"); TEST_CASE_FIXTURE(ATSFixture, "var_typepack_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( type A = (number, string) -> ...any )"; @@ -43,16 +48,18 @@ type A = (number, string) -> ...any ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type A = (number, string)->( ...any)"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type A = (number, string)->( ...any)"); } TEST_CASE_FIXTURE(ATSFixture, "export_alias") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( export type t8 = t0 &((true | any)->('')) )"; @@ -62,16 +69,18 @@ export type t8 = t0 &((true | any)->('')) ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "export type t8 = t0 &((true | any)->(''))"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "export type t8 = t0 &((true | any)->(''))"); } TEST_CASE_FIXTURE(ATSFixture, "typepacks") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function fallible(t: number): ...any if t > 0 then @@ -86,16 +95,18 @@ end ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::TypePk); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function fallible(t: number): ...any\n if t > 0 then\n return true, t\n end\n return false, 'must be positive'\nend"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::TypePk); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function fallible(t: number): ...any\n if t > 0 then\n return true, t\n end\n return false, 'must be positive'\nend"); } TEST_CASE_FIXTURE(ATSFixture, "typepacks_no_ret") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( -- TODO: if partially typed, we'd want to know too local function fallible(t: number) @@ -111,14 +122,16 @@ end ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 0); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 0); } TEST_CASE_FIXTURE(ATSFixture, "var_typepack_any_gen_table") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( type Pair = {first: T, second: any} )"; @@ -128,16 +141,18 @@ type Pair = {first: T, second: any} ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type Pair = {first: T, second: any}"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type Pair = {first: T, second: any}"); } TEST_CASE_FIXTURE(ATSFixture, "assign_uneq") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/B"] = R"( local function greetings(name: string) return "Hello, " .. name, nil @@ -152,14 +167,16 @@ local x, y, z = greetings("Dibri") -- mismatch LUAU_REQUIRE_ERROR_COUNT(1, result1); ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/B"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 0); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 0); } TEST_CASE_FIXTURE(ATSFixture, "var_typepack_any_gen") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( -- type Pair = (boolean, string, ...any) -> {T} -- type aliases with generics/pack do not seem to be processed? type Pair = (boolean, T) -> ...any @@ -170,16 +187,18 @@ type Pair = (boolean, T) -> ...any ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type Pair = (boolean, T)->( ...any)"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type Pair = (boolean, T)->( ...any)"); } TEST_CASE_FIXTURE(ATSFixture, "typeof_any_in_func") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function f() local a: any = 1 @@ -192,16 +211,18 @@ TEST_CASE_FIXTURE(ATSFixture, "typeof_any_in_func") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f()\n local a: any = 1\n local b: typeof(a) = 1\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f()\n local a: any = 1\n local b: typeof(a) = 1\n end"); } TEST_CASE_FIXTURE(ATSFixture, "generic_types") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function foo(a: (...A) -> any, ...: A) return a(...) @@ -220,16 +241,18 @@ foo(addNumbers) ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::FuncApp); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function foo(a: (...A)->( any),...: A)\n return a(...)\nend"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::FuncApp); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function foo(a: (...A)->( any),...: A)\n return a(...)\nend"); } TEST_CASE_FIXTURE(ATSFixture, "no_annot") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local character = script.Parent )"; @@ -239,14 +262,16 @@ local character = script.Parent ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 0); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 0); } TEST_CASE_FIXTURE(ATSFixture, "if_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( function f(x: any) if not x then @@ -266,22 +291,24 @@ end ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT( - module->ats.typeInfo[0].node == "function f(x: any)\nif not x then\nx = {\n y = math.random(0, 2^31-1),\n left = nil,\n right = " - "nil\n}\nelse\n local expected = x * 5\nend\nend" - ); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT( + module->ats.typeInfo[0].node == "function f(x: any)\nif not x then\nx = {\n y = math.random(0, 2^31-1),\n left = nil,\n right = " + "nil\n}\nelse\n local expected = x * 5\nend\nend" + ); } TEST_CASE_FIXTURE(ATSFixture, "variadic_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function f(): (number, ...any) - return 1, 5 + return 1, 5 --catching this end local x, y, z = f() -- not catching this any because no annot @@ -292,16 +319,18 @@ TEST_CASE_FIXTURE(ATSFixture, "variadic_any") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(): (number, ...any)\n return 1, 5\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(): (number, ...any)\n return 1, 5\n end"); } TEST_CASE_FIXTURE(ATSFixture, "type_alias_intersection") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( type XCoord = {x: number} type YCoord = {y: any} @@ -314,16 +343,18 @@ TEST_CASE_FIXTURE(ATSFixture, "type_alias_intersection") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[2].code == Pattern::VarAnnot); - LUAU_ASSERT(module->ats.typeInfo[2].node == "local vec2: Vector2 = {x = 1, y = 2}"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[2].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[2].node == "local vec2: Vector2 = {x = 1, y = 2}"); } TEST_CASE_FIXTURE(ATSFixture, "var_func_arg") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function f(...: any) end @@ -340,16 +371,18 @@ TEST_CASE_FIXTURE(ATSFixture, "var_func_arg") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 4); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 4); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); } TEST_CASE_FIXTURE(ATSFixture, "var_func_apps") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function f(...: any) end @@ -362,17 +395,19 @@ TEST_CASE_FIXTURE(ATSFixture, "var_func_apps") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAny); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function f(...: any)\n end"); } TEST_CASE_FIXTURE(ATSFixture, "CannotExtendTable") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local CAR_COLLISION_GROUP = "Car" @@ -390,14 +425,16 @@ end ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 0); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 0); } TEST_CASE_FIXTURE(ATSFixture, "unknown_symbol") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local function manageRace(raceContainer: Model) RaceManager.new(raceContainer) @@ -410,16 +447,18 @@ end ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function manageRace(raceContainer: Model)\n RaceManager.new(raceContainer)\nend"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function manageRace(raceContainer: Model)\n RaceManager.new(raceContainer)\nend"); } TEST_CASE_FIXTURE(ATSFixture, "racing_3_short") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local CollectionService = game:GetService("CollectionService") @@ -449,16 +488,18 @@ initialize() ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 5); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local function manageRace(raceContainer: Model)\n RaceManager.new(raceContainer)\nend"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 5); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local function manageRace(raceContainer: Model)\n RaceManager.new(raceContainer)\nend"); } TEST_CASE_FIXTURE(ATSFixture, "racing_collision_2") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local PhysicsService = game:GetService("PhysicsService") local ReplicatedStorage = game:GetService("ReplicatedStorage") @@ -524,22 +565,24 @@ initialize() ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 11); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT( - module->ats.typeInfo[0].node == - "local function onCharacterAdded(character: Model)\n\n character.DescendantAdded:Connect(function(descendant)\n if " - "descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n end)\n\n\n for _, descendant in " - "character:GetDescendants()do\n if descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n " - "end\nend" - ); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 11); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT( + module->ats.typeInfo[0].node == + "local function onCharacterAdded(character: Model)\n\n character.DescendantAdded:Connect(function(descendant)\n if " + "descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n end)\n\n\n for _, descendant in " + "character:GetDescendants()do\n if descendant:IsA('BasePart')then\n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP\n end\n " + "end\nend" + ); } TEST_CASE_FIXTURE(ATSFixture, "racing_spawning_1") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local CollectionService = game:GetService("CollectionService") local Players = game:GetService("Players") @@ -593,23 +636,25 @@ initialize() ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 7); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT( - module->ats.typeInfo[0].node == - "local function setupKiosk(kiosk: Model)\n local spawnLocation = kiosk:FindFirstChild('SpawnLocation')\n assert(spawnLocation, " - "`{kiosk:GetFullName()} has no SpawnLocation part`)\n local promptPart = kiosk:FindFirstChild('Prompt')\n assert(promptPart, " - "`{kiosk:GetFullName()} has no Prompt part`)\n\n\n spawnLocation.Transparency = 1\n\n\n local spawnPrompt = " - "spawnPromptTemplate:Clone()\n spawnPrompt.Parent = promptPart\n\n spawnPrompt.Triggered:Connect(function(player: Player)\n\n " - "destroyPlayerCars(player)\n\n spawnCar(spawnLocation.CFrame, player)\n end)\nend" - ); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 7); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT( + module->ats.typeInfo[0].node == + "local function setupKiosk(kiosk: Model)\n local spawnLocation = kiosk:FindFirstChild('SpawnLocation')\n assert(spawnLocation, " + "`{kiosk:GetFullName()} has no SpawnLocation part`)\n local promptPart = kiosk:FindFirstChild('Prompt')\n assert(promptPart, " + "`{kiosk:GetFullName()} has no Prompt part`)\n\n\n spawnLocation.Transparency = 1\n\n\n local spawnPrompt = " + "spawnPromptTemplate:Clone()\n spawnPrompt.Parent = promptPart\n\n spawnPrompt.Triggered:Connect(function(player: Player)\n\n " + "destroyPlayerCars(player)\n\n spawnCar(spawnLocation.CFrame, player)\n end)\nend" + ); } TEST_CASE_FIXTURE(ATSFixture, "mutually_recursive_generic") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( --!strict type T = { f: a, g: U } @@ -625,14 +670,16 @@ TEST_CASE_FIXTURE(ATSFixture, "mutually_recursive_generic") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 0); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 0); } TEST_CASE_FIXTURE(ATSFixture, "explicit_pack") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( type Foo = (T...) -> () -- also want to see how these are used. type Bar = Foo<(number, any)> @@ -643,16 +690,39 @@ type Bar = Foo<(number, any)> ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type Bar = Foo<(number, any)>"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type Bar = Foo<(number, any)>"); +} + +TEST_CASE_FIXTURE(ATSFixture, "local_val") +{ + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + + fileResolver.source["game/Gui/Modules/A"] = R"( +local a, b, c = 1 :: any +)"; + + CheckResult result1 = frontend.check("game/Gui/Modules/A"); + LUAU_REQUIRE_NO_ERRORS(result1); + + ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); + + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Casts); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local a, b, c = 1 :: any"); } TEST_CASE_FIXTURE(ATSFixture, "var_any_local") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local x = 2 local x: any = 2, 3 @@ -665,16 +735,18 @@ local x: number, y: any, z, h: nil = 1, nil ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: any = 2, 3"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: any = 2, 3"); } TEST_CASE_FIXTURE(ATSFixture, "table_uses_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local x: any = 0 local y: number @@ -686,16 +758,18 @@ TEST_CASE_FIXTURE(ATSFixture, "table_uses_any") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: any = 0"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: any = 0"); } TEST_CASE_FIXTURE(ATSFixture, "typeof_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local x: any = 0 function some1(x: typeof(x)) @@ -707,16 +781,18 @@ TEST_CASE_FIXTURE(ATSFixture, "typeof_any") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function some1(x: typeof(x))\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].node == "function some1(x: typeof(x))\n end"); } TEST_CASE_FIXTURE(ATSFixture, "table_type_assigned") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( local x: { x: any?} = {x = 1} local z: { x : any, y : number? } -- not catching this @@ -729,16 +805,18 @@ TEST_CASE_FIXTURE(ATSFixture, "table_type_assigned") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Assign); - LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: { x: any?} = {x = 1}"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Assign); + LUAU_ASSERT(module->ats.typeInfo[0].node == "local x: { x: any?} = {x = 1}"); } TEST_CASE_FIXTURE(ATSFixture, "simple_func_wo_ret") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( function some(x: any) end @@ -749,16 +827,18 @@ TEST_CASE_FIXTURE(ATSFixture, "simple_func_wo_ret") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function some(x: any)\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].node == "function some(x: any)\n end"); } TEST_CASE_FIXTURE(ATSFixture, "simple_func_w_ret") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( function other(y: number): any return "gotcha!" @@ -770,16 +850,18 @@ TEST_CASE_FIXTURE(ATSFixture, "simple_func_w_ret") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function other(y: number): any\n return 'gotcha!'\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncRet); + LUAU_ASSERT(module->ats.typeInfo[0].node == "function other(y: number): any\n return 'gotcha!'\n end"); } TEST_CASE_FIXTURE(ATSFixture, "nested_local") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( function cool(y: number): number local g: any = "gratatataaa" @@ -792,16 +874,18 @@ TEST_CASE_FIXTURE(ATSFixture, "nested_local") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function cool(y: number): number\n local g: any = 'gratatataaa'\n return y\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::VarAnnot); + LUAU_ASSERT(module->ats.typeInfo[0].node == "function cool(y: number): number\n local g: any = 'gratatataaa'\n return y\n end"); } TEST_CASE_FIXTURE(ATSFixture, "generic_func") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( function reverse(a: {T}, b: any): {T} return a @@ -813,16 +897,18 @@ TEST_CASE_FIXTURE(ATSFixture, "generic_func") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 1); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); - LUAU_ASSERT(module->ats.typeInfo[0].node == "function reverse(a: {T}, b: any): {T}\n return a\n end"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 1); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg); + LUAU_ASSERT(module->ats.typeInfo[0].node == "function reverse(a: {T}, b: any): {T}\n return a\n end"); } TEST_CASE_FIXTURE(ATSFixture, "type_alias_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/Gui/Modules/A"] = R"( type Clear = any local z: Clear = "zip" @@ -833,16 +919,18 @@ TEST_CASE_FIXTURE(ATSFixture, "type_alias_any") ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); } TEST_CASE_FIXTURE(ATSFixture, "multi_module_any") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/A"] = R"( export type MyFunction = (number, string) -> (any) )"; @@ -864,16 +952,18 @@ TEST_CASE_FIXTURE(ATSFixture, "multi_module_any") ModulePtr module = frontend.moduleResolver.getModule("game/B"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 2); - LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 2); + LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[0].node == "type Clear = any"); } TEST_CASE_FIXTURE(ATSFixture, "cast_on_cyclic_req") { + ScopedFastFlag sff[] = { + {FFlag::LuauSolverV2, true}, + {FFlag::StudioReportLuauAny2, true}, + }; + fileResolver.source["game/A"] = R"( local a = require(script.Parent.B) -- not resolving this module export type MyFunction = (number, string) -> (any) @@ -890,12 +980,9 @@ TEST_CASE_FIXTURE(ATSFixture, "cast_on_cyclic_req") ModulePtr module = frontend.moduleResolver.getModule("game/B"); - if (FFlag::StudioReportLuauAny) - { - LUAU_ASSERT(module->ats.typeInfo.size() == 3); - LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Alias); - LUAU_ASSERT(module->ats.typeInfo[1].node == "type Clear = any"); - } + LUAU_ASSERT(module->ats.typeInfo.size() == 3); + LUAU_ASSERT(module->ats.typeInfo[1].code == Pattern::Alias); + LUAU_ASSERT(module->ats.typeInfo[1].node == "type Clear = any"); } diff --git a/Dependencies/luau/Luau/tests/AstQuery.test.cpp b/Dependencies/luau/Luau/tests/AstQuery.test.cpp index ec32c5f1..6822ce6d 100644 --- a/Dependencies/luau/Luau/tests/AstQuery.test.cpp +++ b/Dependencies/luau/Luau/tests/AstQuery.test.cpp @@ -6,8 +6,6 @@ #include "doctest.h" #include "Fixture.h" -LUAU_FASTFLAG(LuauFixBindingForGlobalPos); - using namespace Luau; struct DocumentationSymbolFixture : BuiltinsFixture @@ -171,7 +169,7 @@ TEST_SUITE_BEGIN("AstQuery"); TEST_CASE_FIXTURE(Fixture, "last_argument_function_call_type") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; check(R"( local function foo() return 2 end @@ -353,7 +351,7 @@ TEST_CASE_FIXTURE(Fixture, "find_expr_ancestry") TEST_CASE_FIXTURE(BuiltinsFixture, "find_binding_at_position_global_start_of_file") { - ScopedFastFlag sff{FFlag::LuauFixBindingForGlobalPos, true}; + check("local x = string.char(1)"); const Position pos(0, 12); diff --git a/Dependencies/luau/Luau/tests/Autocomplete.test.cpp b/Dependencies/luau/Luau/tests/Autocomplete.test.cpp index c1b62d7a..7f020b18 100644 --- a/Dependencies/luau/Luau/tests/Autocomplete.test.cpp +++ b/Dependencies/luau/Luau/tests/Autocomplete.test.cpp @@ -110,7 +110,7 @@ struct ACFixtureImpl : BaseType ); freeze(globals.globalTypes); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { GlobalTypes& globals = this->frontend.globals; unfreeze(globals.globalTypes); @@ -1607,6 +1607,9 @@ return target(a.@1 TEST_CASE_FIXTURE(ACFixture, "type_correct_suggestion_in_table") { + if (FFlag::LuauSolverV2) // CLI-116815 Autocomplete cannot suggest keys while autocompleting inside of a table + return; + check(R"( type Foo = { a: number, b: string } local a = { one = 4, two = "hello" } @@ -2210,7 +2213,7 @@ local fp: @1= f auto ac = autocomplete('1'); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) REQUIRE_EQ("({ x: number, y: number }) -> number", toString(requireType("f"))); else REQUIRE_EQ("({| x: number, y: number |}) -> number", toString(requireType("f"))); @@ -2261,6 +2264,9 @@ local ec = e(f@5) TEST_CASE_FIXTURE(ACFixture, "type_correct_suggestion_for_overloads") { + if (FFlag::LuauSolverV2) // CLI-116814 Autocomplete needs to populate expected types for function arguments correctly + // (overloads and singletons) + return; check(R"( local target: ((number) -> string) & ((string) -> number)) @@ -2608,6 +2614,10 @@ end TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys") { + if (FFlag::LuauSolverV2) // CLI-116812 AutocompleteTest.suggest_table_keys needs to populate expected types for nested + // tables without an annotation + return; + check(R"( type Test = { first: number, second: number } local t: Test = { f@1 } @@ -3091,6 +3101,10 @@ TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_on_string_singletons") TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons") { + if (FFlag::LuauSolverV2) // CLI-116814 Autocomplete needs to populate expected types for function arguments correctly + // (overloads and singletons) + return; + check(R"( type tag = "cat" | "dog" local function f(a: tag) end @@ -3196,7 +3210,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_singleton_as_table_key") TEST_CASE_FIXTURE(ACFixture, "string_singleton_in_if_statement") { ScopedFastFlag sff[]{ - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; check(R"( @@ -3280,7 +3294,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_singleton_in_if_statement") TEST_CASE_FIXTURE(ACFixture, "string_singleton_in_if_statement2") { // don't run this when the DCR flag isn't set - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; check(R"( @@ -3564,7 +3578,7 @@ t.@1 REQUIRE(ac.entryMap.count("m")); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(ac.entryMap["m"].wrongIndexType); else CHECK(!ac.entryMap["m"].wrongIndexType); @@ -3746,7 +3760,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_contents_is_available_to_callback") declare function require(path: string): any )"); - GlobalTypes& globals = FFlag::DebugLuauDeferredConstraintResolution ? frontend.globals : frontend.globalsForAutocomplete; + GlobalTypes& globals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete; std::optional require = globals.globalScope->linearSearchForBinding("require"); REQUIRE(require); @@ -3773,7 +3787,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_contents_is_available_to_callback") TEST_CASE_FIXTURE(ACFixture, "autocomplete_response_perf1" * doctest::timeout(0.5)) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; // FIXME: This test is just barely at the threshhold which makes it very flaky under the new solver // Build a function type with a large overload set @@ -3855,7 +3869,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_completion_outside_quotes") declare function require(path: string): any )"); - GlobalTypes& globals = FFlag::DebugLuauDeferredConstraintResolution ? frontend.globals : frontend.globalsForAutocomplete; + GlobalTypes& globals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete; std::optional require = globals.globalScope->linearSearchForBinding("require"); REQUIRE(require); @@ -4247,6 +4261,9 @@ foo(@1) TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_generic_type_pack_vararg") { + // CLI-116932 - Autocomplete on a anonymous function in a function argument should not recommend a function with a generic parameter. + if (FFlag::LuauSolverV2) + return; check(R"( local function foo(a: (...A) -> number, ...: A) return a(...) @@ -4276,7 +4293,8 @@ end foo(@1) )"); - const std::optional EXPECTED_INSERT = "function(...): number end"; + const std::optional EXPECTED_INSERT = + FFlag::LuauSolverV2 ? "function(...: number): number end" : "function(...): number end"; auto ac = autocomplete('1'); diff --git a/Dependencies/luau/Luau/tests/Compiler.test.cpp b/Dependencies/luau/Luau/tests/Compiler.test.cpp index 58f52a08..48bd45d7 100644 --- a/Dependencies/luau/Luau/tests/Compiler.test.cpp +++ b/Dependencies/luau/Luau/tests/Compiler.test.cpp @@ -22,9 +22,6 @@ LUAU_FASTINT(LuauCompileLoopUnrollThreshold) LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost) LUAU_FASTINT(LuauRecursionLimit) -LUAU_FASTFLAG(LuauCompileUserdataInfo) -LUAU_FASTFLAG(LuauCompileFastcall3) - using namespace Luau; static std::string compileFunction(const char* source, uint32_t id, int optimizationLevel = 1, bool enableVectors = false) @@ -3330,8 +3327,6 @@ RETURN R0 0 TEST_CASE("DebugTypes") { - ScopedFastFlag luauCompileUserdataInfo{FFlag::LuauCompileUserdataInfo, true}; - const char* source = R"( local up: number = 2 @@ -3591,8 +3586,6 @@ RETURN R1 -1 TEST_CASE("Fastcall3") { - ScopedFastFlag luauCompileFastcall3{FFlag::LuauCompileFastcall3, true}; - CHECK_EQ( "\n" + compileFunction0(R"( local a, b, c = ... @@ -4898,8 +4891,6 @@ L0: RETURN R0 -1 TEST_CASE("VectorFastCall3") { - ScopedFastFlag luauCompileFastcall3{FFlag::LuauCompileFastcall3, true}; - const char* source = R"( local a, b, c = ... return Vector3.new(a, b, c) diff --git a/Dependencies/luau/Luau/tests/Conformance.test.cpp b/Dependencies/luau/Luau/tests/Conformance.test.cpp index 59f862cb..376caa44 100644 --- a/Dependencies/luau/Luau/tests/Conformance.test.cpp +++ b/Dependencies/luau/Luau/tests/Conformance.test.cpp @@ -35,6 +35,7 @@ LUAU_FASTFLAG(DebugLuauAbortingChecks) LUAU_FASTINT(CodegenHeuristicsInstructionLimit) LUAU_FASTFLAG(LuauNativeAttribute) LUAU_FASTFLAG(LuauPreserveLudataRenaming) +LUAU_FASTFLAG(LuauCodegenArmNumToVecFix) static lua_CompileOptions defaultOptions() { @@ -132,7 +133,12 @@ static int lua_vector_cross(lua_State* L) const float* a = luaL_checkvector(L, 1); const float* b = luaL_checkvector(L, 2); +#if LUA_VECTOR_SIZE == 4 + lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0f); +#else lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]); +#endif + return 1; } @@ -143,15 +149,25 @@ static int lua_vector_index(lua_State* L) if (strcmp(name, "Magnitude") == 0) { +#if LUA_VECTOR_SIZE == 4 + lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3])); +#else lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])); +#endif return 1; } if (strcmp(name, "Unit") == 0) { +#if LUA_VECTOR_SIZE == 4 + float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]); + + lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, v[3] * invSqrt); +#else float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt); +#endif return 1; } @@ -809,6 +825,8 @@ TEST_CASE("Pack") TEST_CASE("Vector") { + ScopedFastFlag luauCodegenArmNumToVecFix{FFlag::LuauCodegenArmNumToVecFix, true}; + lua_CompileOptions copts = defaultOptions(); Luau::CodeGen::CompilationOptions nativeOpts = defaultCodegenOptions(); diff --git a/Dependencies/luau/Luau/tests/ConstraintGeneratorFixture.cpp b/Dependencies/luau/Luau/tests/ConstraintGeneratorFixture.cpp index 5c16258e..7f168465 100644 --- a/Dependencies/luau/Luau/tests/ConstraintGeneratorFixture.cpp +++ b/Dependencies/luau/Luau/tests/ConstraintGeneratorFixture.cpp @@ -2,7 +2,7 @@ #include "ConstraintGeneratorFixture.h" #include "ScopedFlags.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); namespace Luau { @@ -10,7 +10,7 @@ namespace Luau ConstraintGeneratorFixture::ConstraintGeneratorFixture() : Fixture() , mainModule(new Module) - , forceTheFlag{FFlag::DebugLuauDeferredConstraintResolution, true} + , forceTheFlag{FFlag::LuauSolverV2, true} { mainModule->name = "MainModule"; mainModule->humanReadableName = "MainModule"; diff --git a/Dependencies/luau/Luau/tests/ConstraintSolver.test.cpp b/Dependencies/luau/Luau/tests/ConstraintSolver.test.cpp index 170510bd..b83fb345 100644 --- a/Dependencies/luau/Luau/tests/ConstraintSolver.test.cpp +++ b/Dependencies/luau/Luau/tests/ConstraintSolver.test.cpp @@ -4,7 +4,7 @@ #include "Fixture.h" #include "doctest.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); using namespace Luau; diff --git a/Dependencies/luau/Luau/tests/DataFlowGraph.test.cpp b/Dependencies/luau/Luau/tests/DataFlowGraph.test.cpp index 07d64e96..4ea656ee 100644 --- a/Dependencies/luau/Luau/tests/DataFlowGraph.test.cpp +++ b/Dependencies/luau/Luau/tests/DataFlowGraph.test.cpp @@ -11,12 +11,12 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); struct DataFlowGraphFixture { // Only needed to fix the operator== reflexivity of an empty Symbol. - ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag dcr{FFlag::LuauSolverV2, true}; InternalErrorReporter handle; diff --git a/Dependencies/luau/Luau/tests/Differ.test.cpp b/Dependencies/luau/Luau/tests/Differ.test.cpp index a10056a7..a2b2280b 100644 --- a/Dependencies/luau/Luau/tests/Differ.test.cpp +++ b/Dependencies/luau/Luau/tests/Differ.test.cpp @@ -15,7 +15,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) TEST_SUITE_BEGIN("Differ"); @@ -234,7 +234,7 @@ TEST_CASE_FIXTURE(DifferFixture, "right_cyclic_table_left_table_property_wrong") TEST_CASE_FIXTURE(DifferFixture, "equal_table_two_cyclic_tables_are_not_different") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function id(x: a): a @@ -625,7 +625,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_table_cyclic_diamonds_unraveled") TEST_CASE_FIXTURE(DifferFixture, "equal_function_cyclic") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo() @@ -646,7 +646,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_function_cyclic") TEST_CASE_FIXTURE(DifferFixture, "equal_function_table_cyclic") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo() @@ -673,7 +673,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_function_table_cyclic") TEST_CASE_FIXTURE(DifferFixture, "function_table_self_referential_cyclic") { // Old solver does not correctly infer function typepacks - // ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + // ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo() @@ -692,7 +692,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_table_self_referential_cyclic") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) compareTypesNe( "foo", "almostFoo", @@ -726,7 +726,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_union_cyclic") TEST_CASE_FIXTURE(DifferFixture, "equal_intersection_cyclic") { // Old solver does not correctly refine test types - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo1(x: number) @@ -804,7 +804,7 @@ TEST_CASE_FIXTURE(DifferFixture, "singleton_string") TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "negation") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -879,7 +879,7 @@ TEST_CASE_FIXTURE(DifferFixture, "union_missing") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) compareTypesNe( "foo", "almostFoo", @@ -931,7 +931,7 @@ TEST_CASE_FIXTURE(DifferFixture, "intersection_tables_missing_right") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) compareTypesNe( "foo", "almostFoo", @@ -953,7 +953,7 @@ TEST_CASE_FIXTURE(DifferFixture, "intersection_tables_missing_left") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) compareTypesNe( "foo", "almostFoo", @@ -970,7 +970,7 @@ TEST_CASE_FIXTURE(DifferFixture, "intersection_tables_missing_left") TEST_CASE_FIXTURE(DifferFixture, "equal_function") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number) @@ -988,7 +988,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_function") TEST_CASE_FIXTURE(DifferFixture, "equal_function_inferred_ret_length") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function bar(x: number, y: string) @@ -1012,7 +1012,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_function_inferred_ret_length") TEST_CASE_FIXTURE(DifferFixture, "equal_function_inferred_ret_length_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function bar(x: number, y: string) @@ -1033,7 +1033,7 @@ TEST_CASE_FIXTURE(DifferFixture, "equal_function_inferred_ret_length_2") TEST_CASE_FIXTURE(DifferFixture, "function_arg_normal") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: number, z: number) @@ -1055,7 +1055,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_normal") TEST_CASE_FIXTURE(DifferFixture, "function_arg_normal_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: number, z: string) @@ -1077,7 +1077,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_normal_2") TEST_CASE_FIXTURE(DifferFixture, "function_ret_normal") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: number, z: string) @@ -1099,7 +1099,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_ret_normal") TEST_CASE_FIXTURE(DifferFixture, "function_arg_length") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: number) @@ -1121,7 +1121,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_length") TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string, z: number) @@ -1143,7 +1143,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_2") TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_none") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo() @@ -1165,7 +1165,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_none") TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_none_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number) @@ -1187,7 +1187,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_arg_length_none_2") TEST_CASE_FIXTURE(DifferFixture, "function_ret_length") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: number) @@ -1209,7 +1209,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_ret_length") TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string, z: number) @@ -1231,7 +1231,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_2") TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_none") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string) @@ -1253,7 +1253,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_none") TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_none_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo() @@ -1275,7 +1275,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_ret_length_none_2") TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_normal") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string, ...: number) @@ -1297,7 +1297,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_normal") TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_missing") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string, ...: number) @@ -1319,7 +1319,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_missing") TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_missing_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: number, y: string) @@ -1341,7 +1341,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_variadic_arg_missing_2") TEST_CASE_FIXTURE(DifferFixture, "function_variadic_oversaturation") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( -- allowed to be oversaturated @@ -1363,7 +1363,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_variadic_oversaturation") TEST_CASE_FIXTURE(DifferFixture, "function_variadic_oversaturation_2") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( -- must not be oversaturated @@ -1385,7 +1385,7 @@ TEST_CASE_FIXTURE(DifferFixture, "function_variadic_oversaturation_2") TEST_CASE_FIXTURE(DifferFixture, "generic") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x, y) @@ -1407,7 +1407,7 @@ TEST_CASE_FIXTURE(DifferFixture, "generic") TEST_CASE_FIXTURE(DifferFixture, "generic_one_vs_two") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: X, y: X) @@ -1429,7 +1429,7 @@ TEST_CASE_FIXTURE(DifferFixture, "generic_one_vs_two") TEST_CASE_FIXTURE(DifferFixture, "generic_three_or_three") { // Old solver does not correctly infer function typepacks - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function foo(x: X, y: X, z: Y) @@ -1473,7 +1473,7 @@ TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "equal_metatable") TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "metatable_normal") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local metaFoo = { diff --git a/Dependencies/luau/Luau/tests/Error.test.cpp b/Dependencies/luau/Luau/tests/Error.test.cpp index cc178a83..15c317fc 100644 --- a/Dependencies/luau/Luau/tests/Error.test.cpp +++ b/Dependencies/luau/Luau/tests/Error.test.cpp @@ -6,7 +6,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) TEST_SUITE_BEGIN("ErrorTests"); @@ -47,7 +47,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "binary_op_type_function_errors") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ( "Operator '+' could not be applied to operands of types number and string; there is no corresponding overload for __add", toString(result.errors[0]) @@ -66,7 +66,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unary_op_type_function_errors") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ( diff --git a/Dependencies/luau/Luau/tests/Fixture.cpp b/Dependencies/luau/Luau/tests/Fixture.cpp index 83454aab..0b0e1b7c 100644 --- a/Dependencies/luau/Luau/tests/Fixture.cpp +++ b/Dependencies/luau/Luau/tests/Fixture.cpp @@ -3,6 +3,7 @@ #include "Luau/AstQuery.h" #include "Luau/BuiltinDefinitions.h" +#include "Luau/Common.h" #include "Luau/Constraint.h" #include "Luau/ModuleResolver.h" #include "Luau/NotNull.h" @@ -22,9 +23,10 @@ static const char* mainModuleName = "MainModule"; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(DebugLuauFreezeArena); LUAU_FASTFLAG(DebugLuauLogSolverToJsonFile) +LUAU_FASTFLAG(LuauDCRMagicFunctionTypeChecker); extern std::optional randomSeed; // tests/main.cpp @@ -150,6 +152,8 @@ const Config& TestConfigResolver::getConfig(const ModuleName& name) const Fixture::Fixture(bool freeze, bool prepareAutocomplete) : sff_DebugLuauFreezeArena(FFlag::DebugLuauFreezeArena, freeze) + // In tests, we *always* want to register the extra magic functions for typechecking `string.format`. + , sff_LuauDCRMagicFunctionTypeChecker(FFlag::LuauDCRMagicFunctionTypeChecker, true) , frontend( &fileResolver, &configResolver, @@ -204,7 +208,7 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars // if AST is available, check how lint and typecheck handle error nodes if (result.root) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { Mode mode = sourceModule->mode ? *sourceModule->mode : Mode::Strict; ModulePtr module = Luau::check( @@ -371,7 +375,7 @@ std::optional Fixture::getType(const std::string& name) if (!module->hasModuleScope()) return std::nullopt; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return linearSearchForBinding(module->getModuleScope().get(), name.c_str()); else return lookupName(module->getModuleScope(), name); diff --git a/Dependencies/luau/Luau/tests/Fixture.h b/Dependencies/luau/Luau/tests/Fixture.h index 790e6f41..f50431f3 100644 --- a/Dependencies/luau/Luau/tests/Fixture.h +++ b/Dependencies/luau/Luau/tests/Fixture.h @@ -99,6 +99,7 @@ struct Fixture TypeId requireExportedType(const ModuleName& moduleName, const std::string& name); ScopedFastFlag sff_DebugLuauFreezeArena; + ScopedFastFlag sff_LuauDCRMagicFunctionTypeChecker; TestFileResolver fileResolver; TestConfigResolver configResolver; diff --git a/Dependencies/luau/Luau/tests/Frontend.test.cpp b/Dependencies/luau/Luau/tests/Frontend.test.cpp index d7fc1956..88f91708 100644 --- a/Dependencies/luau/Luau/tests/Frontend.test.cpp +++ b/Dependencies/luau/Luau/tests/Frontend.test.cpp @@ -12,7 +12,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(DebugLuauFreezeArena); LUAU_FASTFLAG(DebugLuauMagicTypes); @@ -164,7 +164,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_dependent_scripts") auto bExports = first(bModule->returnType); REQUIRE(!!bExports); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ b_value: number }", toString(*bExports)); else CHECK_EQ("{| b_value: number |}", toString(*bExports)); @@ -311,7 +311,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked") std::optional cExports = first(cModule->returnType); REQUIRE(bool(cExports)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ a: { hello: any }, b: { hello: any } }", toString(*cExports)); else CHECK_EQ("{| a: any, b: any |}", toString(*cExports)); @@ -485,13 +485,13 @@ return {mod_b = 2} LUAU_REQUIRE_ERRORS(resultB); TypeId tyB = requireExportedType("game/B", "btype"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(tyB, opts), "{ x: number }"); else CHECK_EQ(toString(tyB, opts), "{| x: number |}"); TypeId tyA = requireExportedType("game/A", "atype"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(tyA, opts), "{ x: any }"); else CHECK_EQ(toString(tyA, opts), "{| x: any |}"); @@ -501,13 +501,13 @@ return {mod_b = 2} LUAU_REQUIRE_ERRORS(resultB); tyB = requireExportedType("game/B", "btype"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(tyB, opts), "{ x: number }"); else CHECK_EQ(toString(tyB, opts), "{| x: number |}"); tyA = requireExportedType("game/A", "atype"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(tyA, opts), "{ x: any }"); else CHECK_EQ(toString(tyA, opts), "{| x: any |}"); @@ -583,7 +583,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty") auto bExports = first(bModule->returnType); REQUIRE(!!bExports); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ b_value: string }", toString(*bExports)); else CHECK_EQ("{| b_value: string |}", toString(*bExports)); @@ -917,7 +917,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "it_should_be_safe_to_stringify_errors_when_f // When this test fails, it is because the TypeIds needed by the error have been deallocated. // It is thus basically impossible to predict what will happen when this assert is evaluated. // It could segfault, or you could see weird type names like the empty string or - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) REQUIRE_EQ( R"(Type '{ count: string }' @@ -934,7 +934,7 @@ could not be converted into TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode") { // The new non-strict mode is not currently expected to signal any errors here. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; fileResolver.source["Module/A"] = R"( @@ -1003,7 +1003,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments") CheckResult resultB = frontend.check("B"); // In the new non-strict mode, we do not currently support error reporting for unknown symbols in type positions. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(resultB); else LUAU_REQUIRE_ERROR_COUNT(1, resultB); @@ -1111,7 +1111,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "typecheck_twice_for_ast_types") TEST_CASE_FIXTURE(FrontendFixture, "imported_table_modification_2") { // This test describes non-strict mode behavior that is just not currently present in the new non-strict mode. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; frontend.options.retainFullTypeGraphs = false; @@ -1375,7 +1375,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "checked_modules_have_the_correct_mode") TEST_CASE_FIXTURE(FrontendFixture, "separate_caches_for_autocomplete") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; fileResolver.source["game/A"] = R"( --!nonstrict @@ -1405,7 +1405,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "separate_caches_for_autocomplete") TEST_CASE_FIXTURE(FrontendFixture, "no_separate_caches_with_the_new_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; fileResolver.source["game/A"] = R"( --!nonstrict diff --git a/Dependencies/luau/Luau/tests/Generalization.test.cpp b/Dependencies/luau/Luau/tests/Generalization.test.cpp index 55af4919..1388b900 100644 --- a/Dependencies/luau/Luau/tests/Generalization.test.cpp +++ b/Dependencies/luau/Luau/tests/Generalization.test.cpp @@ -14,7 +14,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) TEST_SUITE_BEGIN("Generalization"); @@ -29,7 +29,7 @@ struct GeneralizationFixture DenseHashSet generalizedTypes_{nullptr}; NotNull> generalizedTypes{&generalizedTypes_}; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; std::pair freshType() { diff --git a/Dependencies/luau/Luau/tests/IrBuilder.test.cpp b/Dependencies/luau/Luau/tests/IrBuilder.test.cpp index 2984fde1..d02fd9f1 100644 --- a/Dependencies/luau/Luau/tests/IrBuilder.test.cpp +++ b/Dependencies/luau/Luau/tests/IrBuilder.test.cpp @@ -13,8 +13,6 @@ #include LUAU_FASTFLAG(DebugLuauAbortingChecks) -LUAU_FASTFLAG(LuauCodegenFastcall3) -LUAU_FASTFLAG(LuauCodegenMathSign) using namespace Luau::CodeGen; @@ -334,8 +332,6 @@ TEST_SUITE_BEGIN("ConstantFolding"); TEST_CASE_FIXTURE(IrBuilderFixture, "Numeric") { - ScopedFastFlag luauCodegenMathSign{FFlag::LuauCodegenMathSign, true}; - IrOp block = build.block(IrBlockKind::Internal); build.beginBlock(block); @@ -2631,8 +2627,6 @@ TEST_CASE_FIXTURE(IrBuilderFixture, "ForgprepInvalidation") TEST_CASE_FIXTURE(IrBuilderFixture, "FastCallEffects1") { - ScopedFastFlag luauCodegenFastcall3{FFlag::LuauCodegenFastcall3, true}; - IrOp entry = build.block(IrBlockKind::Internal); build.beginBlock(entry); @@ -2656,8 +2650,6 @@ TEST_CASE_FIXTURE(IrBuilderFixture, "FastCallEffects1") TEST_CASE_FIXTURE(IrBuilderFixture, "FastCallEffects2") { - ScopedFastFlag luauCodegenFastcall3{FFlag::LuauCodegenFastcall3, true}; - IrOp entry = build.block(IrBlockKind::Internal); build.beginBlock(entry); @@ -2852,8 +2844,6 @@ TEST_CASE_FIXTURE(IrBuilderFixture, "ImplicitFixedRegistersInVarargCall") TEST_CASE_FIXTURE(IrBuilderFixture, "ExplicitUseOfRegisterInVarargSequence") { - ScopedFastFlag luauCodegenFastcall3{FFlag::LuauCodegenFastcall3, true}; - IrOp entry = build.block(IrBlockKind::Internal); IrOp exit = build.block(IrBlockKind::Internal); diff --git a/Dependencies/luau/Luau/tests/IrLowering.test.cpp b/Dependencies/luau/Luau/tests/IrLowering.test.cpp index 6d4aafeb..39667846 100644 --- a/Dependencies/luau/Luau/tests/IrLowering.test.cpp +++ b/Dependencies/luau/Luau/tests/IrLowering.test.cpp @@ -15,10 +15,6 @@ #include #include -LUAU_FASTFLAG(LuauCompileUserdataInfo) -LUAU_FASTFLAG(LuauCompileFastcall3) -LUAU_FASTFLAG(LuauCodegenFastcall3) - static std::string getCodegenAssembly(const char* source, bool includeIrTypes = false, int debugLevel = 1) { Luau::CodeGen::AssemblyOptions options; @@ -425,8 +421,6 @@ end TEST_CASE("DseInitialStackState2") { - ScopedFastFlag luauCodegenFastcall3{FFlag::LuauCodegenFastcall3, true}; - CHECK_EQ( "\n" + getCodegenAssembly(R"( local function foo(a) @@ -943,10 +937,9 @@ end ); } +#if LUA_VECTOR_SIZE == 3 TEST_CASE("FastcallTypeInferThroughLocal") { - ScopedFastFlag sffs[]{{FFlag::LuauCompileFastcall3, true}, {FFlag::LuauCodegenFastcall3, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -997,8 +990,6 @@ end TEST_CASE("FastcallTypeInferThroughUpvalue") { - ScopedFastFlag sffs[]{{FFlag::LuauCompileFastcall3, true}, {FFlag::LuauCodegenFastcall3, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1055,6 +1046,7 @@ end )" ); } +#endif TEST_CASE("LoadAndMoveTypePropagation") { @@ -1125,10 +1117,9 @@ end ); } +#if LUA_VECTOR_SIZE == 3 TEST_CASE("ArgumentTypeRefinement") { - ScopedFastFlag sffs[]{{FFlag::LuauCompileFastcall3, true}, {FFlag::LuauCodegenFastcall3, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1164,6 +1155,7 @@ end )" ); } +#endif TEST_CASE("InlineFunctionType") { @@ -1434,10 +1426,9 @@ end ); } +#if LUA_VECTOR_SIZE == 3 TEST_CASE("UnaryTypeResolve") { - ScopedFastFlag sffs[]{{FFlag::LuauCompileFastcall3, true}, {FFlag::LuauCodegenFastcall3, true}}; - CHECK_EQ( "\n" + getCodegenHeader(R"( local function foo(a, b: vector, c) @@ -1457,6 +1448,7 @@ end )" ); } +#endif TEST_CASE("ForInManualAnnotation") { @@ -1637,37 +1629,12 @@ end ); } -// Temporary test, when we don't compile new typeinfo, but support loading it -TEST_CASE("CustomUserdataTypesTemp") -{ - // This test requires runtime component to be present - if (!Luau::CodeGen::isSupported()) - return; - - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, false}}; - - CHECK_EQ( - "\n" + getCodegenHeader(R"( -local function foo(v: vec2, x: mat3) - return v.X * x -end -)"), - R"( -; function foo(v, x) line 2 -; R0: userdata [argument 'v'] -; R1: userdata [argument 'x'] -)" - ); -} - TEST_CASE("CustomUserdataTypes") { // This test requires runtime component to be present if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenHeader(R"( local function foo(v: vec2, x: mat3) @@ -1688,8 +1655,6 @@ TEST_CASE("CustomUserdataPropertyAccess") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1727,8 +1692,6 @@ TEST_CASE("CustomUserdataPropertyAccess2") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1768,8 +1731,6 @@ TEST_CASE("CustomUserdataNamecall1") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1818,8 +1779,6 @@ TEST_CASE("CustomUserdataNamecall2") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1871,8 +1830,6 @@ TEST_CASE("CustomUserdataMetamethodDirectFlow") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1907,8 +1864,6 @@ TEST_CASE("CustomUserdataMetamethodDirectFlow2") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1941,8 +1896,6 @@ TEST_CASE("CustomUserdataMetamethodDirectFlow3") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( @@ -1975,8 +1928,6 @@ TEST_CASE("CustomUserdataMetamethod") if (!Luau::CodeGen::isSupported()) return; - ScopedFastFlag sffs[]{{FFlag::LuauCompileUserdataInfo, true}}; - CHECK_EQ( "\n" + getCodegenAssembly( R"( diff --git a/Dependencies/luau/Luau/tests/Linter.test.cpp b/Dependencies/luau/Luau/tests/Linter.test.cpp index 6fd70626..8647777a 100644 --- a/Dependencies/luau/Luau/tests/Linter.test.cpp +++ b/Dependencies/luau/Luau/tests/Linter.test.cpp @@ -7,7 +7,7 @@ #include "doctest.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauNativeAttribute); LUAU_FASTFLAG(LintRedundantNativeAttribute); @@ -1265,7 +1265,7 @@ _ = { TEST_CASE_FIXTURE(Fixture, "read_write_table_props") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; LintResult result = lint(R"(-- line 1 type A = {x: number} @@ -1659,7 +1659,7 @@ table.create(42, {} :: {}) TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperationsIndexer") { // CLI-116824 Linter incorrectly issues false positive when taking the length of a unannotated string function argument - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; LintResult result = lint(R"( diff --git a/Dependencies/luau/Luau/tests/Module.test.cpp b/Dependencies/luau/Luau/tests/Module.test.cpp index bcad38d3..4519ba82 100644 --- a/Dependencies/luau/Luau/tests/Module.test.cpp +++ b/Dependencies/luau/Luau/tests/Module.test.cpp @@ -11,7 +11,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(DebugLuauFreezeArena); LUAU_FASTINT(LuauTypeCloneIterationLimit); @@ -111,7 +111,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") // not, but it's tangental to the core purpose of this test. ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; CheckResult result = check(R"( @@ -283,7 +283,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_class") TEST_CASE_FIXTURE(Fixture, "clone_free_types") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; TypeArena arena; TypeId freeTy = freshType(NotNull{&arena}, builtinTypes, nullptr); @@ -316,6 +316,9 @@ TEST_CASE_FIXTURE(Fixture, "clone_free_tables") TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property") { + // CLI-117082 ModuleTests.clone_self_property we don't infer self correctly, instead replacing it with unknown. + if (FFlag::LuauSolverV2) + return; fileResolver.source["Module/A"] = R"( --!nonstrict local a = {} @@ -412,7 +415,7 @@ type B = A auto it = mod->exportedTypeBindings.find("A"); REQUIRE(it != mod->exportedTypeBindings.end()); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(it->second.type) == "any"); else CHECK(toString(it->second.type) == "*error-type*"); diff --git a/Dependencies/luau/Luau/tests/NonStrictTypeChecker.test.cpp b/Dependencies/luau/Luau/tests/NonStrictTypeChecker.test.cpp index b7198a9d..ffb44049 100644 --- a/Dependencies/luau/Luau/tests/NonStrictTypeChecker.test.cpp +++ b/Dependencies/luau/Luau/tests/NonStrictTypeChecker.test.cpp @@ -67,7 +67,7 @@ struct NonStrictTypeCheckerFixture : Fixture CheckResult checkNonStrict(const std::string& code) { ScopedFastFlag flags[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; LoadDefinitionFileResult res = loadDefinition(definitions); LUAU_ASSERT(res.success); @@ -77,7 +77,7 @@ struct NonStrictTypeCheckerFixture : Fixture CheckResult checkNonStrictModule(const std::string& moduleName) { ScopedFastFlag flags[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; LoadDefinitionFileResult res = loadDefinition(definitions); LUAU_ASSERT(res.success); diff --git a/Dependencies/luau/Luau/tests/NonstrictMode.test.cpp b/Dependencies/luau/Luau/tests/NonstrictMode.test.cpp index a22e1e16..3acd3909 100644 --- a/Dependencies/luau/Luau/tests/NonstrictMode.test.cpp +++ b/Dependencies/luau/Luau/tests/NonstrictMode.test.cpp @@ -16,7 +16,7 @@ TEST_SUITE_BEGIN("NonstrictModeTests"); TEST_CASE_FIXTURE(Fixture, "infer_nullary_function") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict function foo(x, y) end @@ -39,7 +39,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function") TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_could_return") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict function getMinCardCountForWidth(width) @@ -103,7 +103,7 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok") TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict local m = 55 @@ -130,7 +130,7 @@ TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional") TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict local T = {} @@ -148,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any") TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict local T = {} @@ -163,7 +163,7 @@ TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon") TEST_CASE_FIXTURE(Fixture, "table_props_are_any") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict local T = {} @@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any") TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict local T = { @@ -261,7 +261,7 @@ TEST_CASE_FIXTURE(Fixture, "delay_function_does_not_require_its_argument_to_retu TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict diff --git a/Dependencies/luau/Luau/tests/Normalize.test.cpp b/Dependencies/luau/Luau/tests/Normalize.test.cpp index 407aaf4e..23b4f133 100644 --- a/Dependencies/luau/Luau/tests/Normalize.test.cpp +++ b/Dependencies/luau/Luau/tests/Normalize.test.cpp @@ -10,7 +10,7 @@ #include "Luau/Normalize.h" #include "Luau/BuiltinDefinitions.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauNormalizeNotUnknownIntersection) LUAU_FASTINT(LuauTypeInferRecursionLimit) using namespace Luau; @@ -142,7 +142,7 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "table_with_union_prop") TypeId a = requireType("a"); TypeId b = requireType("b"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(!isSubtype(a, b)); // table properties are invariant else CHECK(isSubtype(a, b)); @@ -159,7 +159,7 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "table_with_any_prop") TypeId a = requireType("a"); TypeId b = requireType("b"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(!isSubtype(a, b)); // table properties are invariant else CHECK(isSubtype(a, b)); @@ -219,7 +219,7 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "tables") TypeId c = requireType("c"); TypeId d = requireType("d"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(!isSubtype(a, b)); // table properties are invariant else CHECK(isSubtype(a, b)); @@ -231,7 +231,7 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "tables") CHECK(isSubtype(d, a)); CHECK(!isSubtype(a, d)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(!isSubtype(d, b)); // table properties are invariant else CHECK(isSubtype(d, b)); @@ -406,7 +406,7 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "error_suppression") // We have added this as an exception - the set of inhabitants of any is exactly the set of inhabitants of unknown (since error has no // inhabitants). any = err | unknown, so under semantic subtyping, {} U unknown = unknown - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK(isSubtype(any, unk)); } @@ -415,7 +415,15 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "error_suppression") CHECK(!isSubtype(any, unk)); } - CHECK(!isSubtype(err, str)); + if (FFlag::LuauSolverV2) + { + CHECK(isSubtype(err, str)); + } + else + { + CHECK(!isSubtype(err, str)); + } + CHECK(!isSubtype(str, err)); CHECK(!isSubtype(err, unk)); @@ -446,7 +454,7 @@ struct NormalizeFixture : Fixture CheckResult result = check("type _Res = " + annotation); LUAU_REQUIRE_ERROR_COUNT(expectedErrors, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { SourceModule* sourceModule = getMainSourceModule(); REQUIRE(sourceModule); @@ -662,7 +670,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "negated_function_is_anything_except_a_funct TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated") { - CHECK(nullptr == toNormalizedType("Not<(boolean) -> boolean>", FFlag::DebugLuauDeferredConstraintResolution ? 1 : 0)); + CHECK(nullptr == toNormalizedType("Not<(boolean) -> boolean>", FFlag::LuauSolverV2 ? 1 : 0)); } TEST_CASE_FIXTURE(NormalizeFixture, "trivial_intersection_inhabited") @@ -701,6 +709,10 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function") TEST_CASE_FIXTURE(Fixture, "higher_order_function_with_annotation") { + // CLI-117088 - Inferring the type of a higher order function with an annotation sometimes doesn't fully constrain the type (there are free types + // left over). + if (FFlag::LuauSolverV2) + return; check(R"( function apply(f: (a) -> b, x) return f(x) @@ -769,7 +781,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "narrow_union_of_classes_with_intersection") TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_metatables_where_the_metatable_is_top_or_bottom") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("{ @metatable *error-type*, { } }" == toString(normal("Mt<{}, any> & Mt<{}, err>"))); else CHECK("{ @metatable *error-type*, {| |} }" == toString(normal("Mt<{}, any> & Mt<{}, err>"))); @@ -866,7 +878,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "classes_and_never") TEST_CASE_FIXTURE(NormalizeFixture, "top_table_type") { CHECK("table" == toString(normal("{} | tbl"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("{ }" == toString(normal("{} & tbl"))); else CHECK("{| |}" == toString(normal("{} & tbl"))); @@ -875,7 +887,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "top_table_type") TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_tables") { - CHECK(nullptr == toNormalizedType("Not<{}>", FFlag::DebugLuauDeferredConstraintResolution ? 1 : 0)); + CHECK(nullptr == toNormalizedType("Not<{}>", FFlag::LuauSolverV2 ? 1 : 0)); CHECK("(boolean | buffer | class | function | number | string | thread)?" == toString(normal("Not"))); CHECK("table" == toString(normal("Not>"))); } @@ -916,7 +928,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "normalize_unknown") TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK("{ x: string }" == toString(normal("{ read x: string } & { x: string }"), {true})); CHECK("{ x: string }" == toString(normal("{ x: string } & { read x: string }"), {true})); @@ -924,7 +936,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props") TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props_2") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK(R"({ x: "hello" })" == toString(normal(R"({ x: "hello" } & { x: string })"), {true})); CHECK(R"(never)" == toString(normal(R"({ x: "hello" } & { x: "world" })"), {true})); @@ -932,7 +944,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props_2") TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props_3") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK(R"({ read x: "hello" })" == toString(normal(R"({ read x: "hello" } & { read x: string })"), {true})); CHECK("never" == toString(normal(R"({ read x: "hello" } & { read x: "world" })"), {true})); @@ -997,7 +1009,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_stack_overflow_2") TEST_CASE_FIXTURE(NormalizeFixture, "truthy_table_property_and_optional_table_with_optional_prop") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; // { x: ~(false?) } TypeId t1 = arena.addType(TableType{TableType::Props{{"x", builtinTypes->truthyType}}, std::nullopt, TypeLevel{}, TableState::Sealed}); diff --git a/Dependencies/luau/Luau/tests/Parser.test.cpp b/Dependencies/luau/Luau/tests/Parser.test.cpp index b285a318..dfcf0ded 100644 --- a/Dependencies/luau/Luau/tests/Parser.test.cpp +++ b/Dependencies/luau/Luau/tests/Parser.test.cpp @@ -15,7 +15,7 @@ LUAU_FASTFLAG(LuauLexerLookaheadRemembersBraceType); LUAU_FASTINT(LuauRecursionLimit); LUAU_FASTINT(LuauTypeLengthLimit); LUAU_FASTINT(LuauParseErrorLimit); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauAttributeSyntaxFunExpr); LUAU_FASTFLAG(LuauUserDefinedTypeFunctions); @@ -1192,7 +1192,7 @@ until false TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_local_function") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; try @@ -1229,7 +1229,7 @@ end TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_failsafe_earlier") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; try @@ -2597,7 +2597,7 @@ TEST_CASE_FIXTURE(Fixture, "recovery_of_parenthesized_expressions") }; ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; checkRecovery("function foo(a, b. c) return a + b end", "function foo(a, b) return a + b end", 1); @@ -2841,7 +2841,7 @@ TEST_CASE_FIXTURE(Fixture, "AstName_comparison") TEST_CASE_FIXTURE(Fixture, "generic_type_list_recovery") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; try diff --git a/Dependencies/luau/Luau/tests/RequireByString.test.cpp b/Dependencies/luau/Luau/tests/RequireByString.test.cpp index 7f2300a5..f76f9faf 100644 --- a/Dependencies/luau/Luau/tests/RequireByString.test.cpp +++ b/Dependencies/luau/Luau/tests/RequireByString.test.cpp @@ -436,6 +436,12 @@ TEST_CASE_FIXTURE(ReplWithPathFixture, "RequirePathWithParentAlias") assertOutputContainsAll({"true", "result from other_dependency"}); } +TEST_CASE_FIXTURE(ReplWithPathFixture, "RequirePathWithAliasPointingToDirectory") +{ + std::string path = getLuauDirectory(PathType::Relative) + "/tests/require/with_config/src/directory_alias_requirer"; + runProtectedRequire(path); + assertOutputContainsAll({"true", "result from subdirectory_dependency"}); +} TEST_CASE_FIXTURE(ReplWithPathFixture, "RequireAliasThatDoesNotExist") { diff --git a/Dependencies/luau/Luau/tests/RuntimeLimits.test.cpp b/Dependencies/luau/Luau/tests/RuntimeLimits.test.cpp index 41418aa8..b4acf138 100644 --- a/Dependencies/luau/Luau/tests/RuntimeLimits.test.cpp +++ b/Dependencies/luau/Luau/tests/RuntimeLimits.test.cpp @@ -18,7 +18,7 @@ using namespace Luau; LUAU_FASTINT(LuauTypeInferRecursionLimit) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) struct LimitFixture : BuiltinsFixture { @@ -46,7 +46,7 @@ TEST_SUITE_BEGIN("RuntimeLimits"); TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; constexpr const char* src = R"LUA( diff --git a/Dependencies/luau/Luau/tests/Simplify.test.cpp b/Dependencies/luau/Luau/tests/Simplify.test.cpp index 08b2fc4f..92ac68de 100644 --- a/Dependencies/luau/Luau/tests/Simplify.test.cpp +++ b/Dependencies/luau/Luau/tests/Simplify.test.cpp @@ -8,7 +8,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_DYNAMIC_FASTINT(LuauSimplificationComplexityLimit) namespace @@ -62,7 +62,7 @@ struct SimplifyFixture : Fixture TypeId anotherChildClassTy = nullptr; TypeId unrelatedClassTy = nullptr; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; SimplifyFixture() { diff --git a/Dependencies/luau/Luau/tests/Subtyping.test.cpp b/Dependencies/luau/Luau/tests/Subtyping.test.cpp index 01ddac0c..a59312ac 100644 --- a/Dependencies/luau/Luau/tests/Subtyping.test.cpp +++ b/Dependencies/luau/Luau/tests/Subtyping.test.cpp @@ -15,7 +15,7 @@ #include -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); using namespace Luau; @@ -67,17 +67,17 @@ struct SubtypeFixture : Fixture UnifierSharedState sharedState{&ice}; Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; ScopePtr rootScope{new Scope(builtinTypes->emptyTypePack)}; ScopePtr moduleScope{new Scope(rootScope)}; - Subtyping subtyping = mkSubtyping(rootScope); + Subtyping subtyping = mkSubtyping(); BuiltinTypeFunctions builtinTypeFunctions{}; - Subtyping mkSubtyping(const ScopePtr& scope) + Subtyping mkSubtyping() { - return Subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&iceReporter}, NotNull{scope.get()}}; + return Subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&iceReporter}}; } TypePackId pack(std::initializer_list tys) @@ -184,7 +184,7 @@ struct SubtypeFixture : Fixture SubtypingResult isSubtype(TypeId subTy, TypeId superTy) { - return subtyping.isSubtype(subTy, superTy); + return subtyping.isSubtype(subTy, superTy, NotNull{rootScope.get()}); } TypeId helloType = arena.addType(SingletonType{StringSingleton{"hello"}}); @@ -837,28 +837,28 @@ TEST_CASE_FIXTURE(SubtypeFixture, "{x: (T) -> ()} <: {x: (U) -> ()}") TEST_CASE_FIXTURE(SubtypeFixture, "{ x: number } <: { read x: number }") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK_IS_SUBTYPE(tbl({{"x", builtinTypes->numberType}}), tbl({{"x", Property::readonly(builtinTypes->numberType)}})); } TEST_CASE_FIXTURE(SubtypeFixture, "{ x: number } <: { write x: number }") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK_IS_SUBTYPE(tbl({{"x", builtinTypes->numberType}}), tbl({{"x", Property::writeonly(builtinTypes->numberType)}})); } TEST_CASE_FIXTURE(SubtypeFixture, "{ x: \"hello\" } <: { read x: string }") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK_IS_SUBTYPE(tbl({{"x", helloType}}), tbl({{"x", Property::readonly(builtinTypes->stringType)}})); } TEST_CASE_FIXTURE(SubtypeFixture, "{ x: string } <: { write x: string }") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK_IS_SUBTYPE(tbl({{"x", builtinTypes->stringType}}), tbl({{"x", Property::writeonly(builtinTypes->stringType)}})); } @@ -1210,7 +1210,7 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...any) -> () <: (T...) -> ()") TypeId anysToNothing = arena.addType(FunctionType{builtinTypes->anyTypePack, builtinTypes->emptyTypePack}); TypeId genericTToAnys = arena.addType(FunctionType{genericAs, builtinTypes->emptyTypePack}); - CHECK_MESSAGE(subtyping.isSubtype(anysToNothing, genericTToAnys).isSubtype, "(...any) -> () <: (T...) -> ()"); + CHECK_MESSAGE(isSubtype(anysToNothing, genericTToAnys).isSubtype, "(...any) -> () <: (T...) -> ()"); } // See https://github.com/luau-lang/luau/issues/767 @@ -1220,7 +1220,7 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...unknown) -> () <: (T...) -> ()") arena.addType(FunctionType{arena.addTypePack(VariadicTypePack{builtinTypes->unknownType}), builtinTypes->emptyTypePack}); TypeId genericTToAnys = arena.addType(FunctionType{genericAs, builtinTypes->emptyTypePack}); - CHECK_MESSAGE(subtyping.isSubtype(unknownsToNothing, genericTToAnys).isSubtype, "(...unknown) -> () <: (T...) -> ()"); + CHECK_MESSAGE(isSubtype(unknownsToNothing, genericTToAnys).isSubtype, "(...unknown) -> () <: (T...) -> ()"); } TEST_CASE_FIXTURE(SubtypeFixture, "bill") @@ -1233,8 +1233,8 @@ TEST_CASE_FIXTURE(SubtypeFixture, "bill") {{"a", builtinTypes->stringType}}, TableIndexer{builtinTypes->stringType, builtinTypes->numberType}, TypeLevel{}, nullptr, TableState::Sealed }); - CHECK(subtyping.isSubtype(a, b).isSubtype); - CHECK(subtyping.isSubtype(b, a).isSubtype); + CHECK(isSubtype(a, b).isSubtype); + CHECK(isSubtype(b, a).isSubtype); } // TEST_CASE_FIXTURE(SubtypeFixture, "({[string]: number, a: string}) -> () <: ({[string]: number, a: string}) -> ()") @@ -1256,7 +1256,7 @@ TEST_CASE_FIXTURE(SubtypeFixture, "fred") TypeId a = makeTheType(); TypeId b = makeTheType(); - CHECK_MESSAGE(subtyping.isSubtype(a, b).isSubtype, "({[string]: number, a: string}) -> () <: ({[string]: number, a: string}) -> ()"); + CHECK_MESSAGE(isSubtype(a, b).isSubtype, "({[string]: number, a: string}) -> () <: ({[string]: number, a: string}) -> ()"); } /* @@ -1273,17 +1273,17 @@ TEST_CASE_FIXTURE(SubtypeFixture, "unknown <: X") TypeId genericX = arena.addType(GenericType(childScope.get(), "X")); - SubtypingResult usingGlobalScope = subtyping.isSubtype(builtinTypes->unknownType, genericX); + SubtypingResult usingGlobalScope = isSubtype(builtinTypes->unknownType, genericX); CHECK_MESSAGE(!usingGlobalScope.isSubtype, "Expected " << builtinTypes->unknownType << " unknownType, genericX); + SubtypingResult usingChildScope = childSubtyping.isSubtype(builtinTypes->unknownType, genericX, NotNull{childScope.get()}); CHECK_MESSAGE(usingChildScope.isSubtype, "Expected " << builtinTypes->unknownType << " <: " << genericX); - Subtyping grandChildSubtyping{mkSubtyping(grandChildScope)}; + Subtyping grandChildSubtyping{mkSubtyping()}; - SubtypingResult usingGrandChildScope = grandChildSubtyping.isSubtype(builtinTypes->unknownType, genericX); + SubtypingResult usingGrandChildScope = grandChildSubtyping.isSubtype(builtinTypes->unknownType, genericX, NotNull{grandChildScope.get()}); CHECK_MESSAGE(usingGrandChildScope.isSubtype, "Expected " << builtinTypes->unknownType << " <: " << genericX); } diff --git a/Dependencies/luau/Luau/tests/Symbol.test.cpp b/Dependencies/luau/Luau/tests/Symbol.test.cpp index 526dd24f..83482c03 100644 --- a/Dependencies/luau/Luau/tests/Symbol.test.cpp +++ b/Dependencies/luau/Luau/tests/Symbol.test.cpp @@ -8,7 +8,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) TEST_SUITE_BEGIN("SymbolTests"); @@ -68,7 +68,7 @@ TEST_CASE("equality_and_hashing_of_locals") TEST_CASE("equality_of_empty_symbols") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; std::string s1 = "name"; std::string s2 = "name"; diff --git a/Dependencies/luau/Luau/tests/ToDot.test.cpp b/Dependencies/luau/Luau/tests/ToDot.test.cpp index 4f0ae809..fd72579b 100644 --- a/Dependencies/luau/Luau/tests/ToDot.test.cpp +++ b/Dependencies/luau/Luau/tests/ToDot.test.cpp @@ -9,7 +9,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); struct ToDotClassFixture : Fixture { @@ -145,7 +145,7 @@ local function f(a, ...: string) return a end ToDotOptions opts; opts.showPointers = false; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( R"(digraph graphname { @@ -242,7 +242,7 @@ local a: A ToDotOptions opts; opts.showPointers = false; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( R"(digraph graphname { @@ -323,7 +323,7 @@ n3 [label="TableType 3"]; TEST_CASE_FIXTURE(Fixture, "free") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; Type type{TypeVariant{FreeType{TypeLevel{0, 0}}}}; @@ -341,7 +341,7 @@ n1 [label="FreeType 1"]; TEST_CASE_FIXTURE(Fixture, "free_with_constraints") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; Type type{TypeVariant{FreeType{nullptr, builtinTypes->numberType, builtinTypes->optionalNumberType}}}; diff --git a/Dependencies/luau/Luau/tests/ToString.test.cpp b/Dependencies/luau/Luau/tests/ToString.test.cpp index 67e247f2..59d9b5fd 100644 --- a/Dependencies/luau/Luau/tests/ToString.test.cpp +++ b/Dependencies/luau/Luau/tests/ToString.test.cpp @@ -11,7 +11,7 @@ using namespace Luau; LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauAttributeSyntax); LUAU_FASTFLAG(LuauUserDefinedTypeFunctions) @@ -22,7 +22,7 @@ TEST_CASE_FIXTURE(Fixture, "primitive") CheckResult result = check("local a = nil local b = 44 local c = 'lalala' local d = true"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("nil" == toString(requireType("a"))); else { @@ -45,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "bound_types") TEST_CASE_FIXTURE(Fixture, "free_types") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check("local a"); LUAU_REQUIRE_NO_ERRORS(result); @@ -59,7 +59,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table") TableType* tableOne = getMutable(&cyclicTable); tableOne->props["self"] = {&cyclicTable}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("t1 where t1 = {| self: t1 |}", toString(&cyclicTable)); else CHECK_EQ("t1 where t1 = { self: t1 }", toString(&cyclicTable)); @@ -80,7 +80,7 @@ TEST_CASE_FIXTURE(Fixture, "empty_table") local a: {} )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ }", toString(requireType("a"))); else CHECK_EQ("{| |}", toString(requireType("a"))); @@ -88,7 +88,7 @@ TEST_CASE_FIXTURE(Fixture, "empty_table") // Should stay the same with useLineBreaks enabled ToStringOptions opts; opts.useLineBreaks = true; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ }", toString(requireType("a"), opts)); else CHECK_EQ("{| |}", toString(requireType("a"), opts)); @@ -103,7 +103,7 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break") ToStringOptions opts; opts.useLineBreaks = true; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ( "{\n" " anotherProp: number,\n" @@ -150,7 +150,7 @@ TEST_CASE_FIXTURE(Fixture, "metatable") Type table{TypeVariant(TableType())}; Type metatable{TypeVariant(TableType())}; Type mtv{TypeVariant(MetatableType{&table, &metatable})}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ @metatable {| |}, {| |} }", toString(&mtv)); else CHECK_EQ("{ @metatable { }, { } }", toString(&mtv)); @@ -166,7 +166,7 @@ TEST_CASE_FIXTURE(Fixture, "named_metatable") TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function createTbl(): NamedMetatable @@ -207,7 +207,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table") CHECK_EQ(std::string::npos, a.find("CYCLE")); CHECK_EQ(std::string::npos, a.find("TRUNCATED")); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK( "t2 where " @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded ToStringOptions o; o.exhaustive = false; o.maxTableLength = 40; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 10 more ... |}"); else CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 10 more ... }"); @@ -363,7 +363,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaust ToStringOptions o; o.exhaustive = true; o.maxTableLength = 40; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 2 more ... |}"); else CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 2 more ... }"); @@ -377,7 +377,7 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_type_when_length_is_exceeded") function f2(f) return f or f1 end function f3(f) return f or f2 end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); @@ -412,7 +412,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive") function f3(f) return f or f2 end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); @@ -448,7 +448,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table ToStringOptions o; o.maxTableLength = 40; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 5 more ... }"); else CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 5 more ... |}"); @@ -482,7 +482,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax") CHECK_EQ("{string}", toString(Type{ttv})); ttv.props["A"] = {builtinTypes->numberType}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ [number]: string, A: number }", toString(Type{ttv})); else CHECK_EQ("{| [number]: string, A: number |}", toString(Type{ttv})); @@ -594,7 +594,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed") TEST_CASE_FIXTURE(Fixture, "toStringErrorPack") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function target(callback: nil) return callback(4, "hello") end @@ -633,7 +633,7 @@ TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_T TypePackVar tpv2{TypePack{{&tv2}}}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("{ hello: number, world: number }", toString(&tpv1)); CHECK_EQ("{ hello: number, world: number }", toString(&tpv2)); @@ -680,7 +680,7 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_inters LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(() -> t1) & ((number) -> ()) where t1 = () -> t1" == toString(requireType("a"))); else CHECK_EQ("((number) -> ()) & t1 where t1 = () -> t1", toString(requireType("a"))); @@ -723,7 +723,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map") TypeId ty = requireType("map"); const FunctionType* ftv = get(follow(ty)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("map(arr: {a}, fn: (a) -> (b, ...unknown)): {b}", toStringNamedFunction("map", *ftv)); else CHECK_EQ("map(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv)); @@ -841,9 +841,9 @@ TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_ function foo(x: a, y) end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { - CHECK("(a, 'b) -> ()" == toString(requireType("foo"))); + CHECK("(a, unknown) -> ()" == toString(requireType("foo"))); } else CHECK("(a, b) -> ()" == toString(requireType("foo"))); @@ -873,7 +873,7 @@ TEST_CASE_FIXTURE(Fixture, "tostring_error_mismatch") )"); std::string expected; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) expected = R"(Type pack '{ a: number, b: string, c: { d: string } }' could not be converted into '{ a: number, b: string, c: { d: number } }'; at [0][read "c"][read "d"], string is not exactly number)"; else @@ -901,7 +901,7 @@ Type 'string' could not be converted into 'number' in an invariant context)"; TEST_CASE_FIXTURE(Fixture, "checked_fn_toString") { ScopedFastFlag flags[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; auto _result = loadDefinition(R"( @@ -920,7 +920,7 @@ local f = abs TEST_CASE_FIXTURE(Fixture, "read_only_properties") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type A = {x: string} @@ -950,7 +950,7 @@ TEST_CASE_FIXTURE(Fixture, "cycle_rooted_in_a_pack") packPtr->head[0] = theTable; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("tp1 where tp1 = { read BaseField: unknown, read BaseMethod: (tp1) -> () }, number" == toString(thePack)); else CHECK("tp1 where tp1 = {| BaseField: unknown, BaseMethod: (tp1) -> () |}, number" == toString(thePack)); @@ -969,7 +969,7 @@ TEST_CASE_FIXTURE(Fixture, "correct_stringification_user_defined_type_functions" Type tv{tftt}; - if (FFlag::DebugLuauDeferredConstraintResolution && FFlag::LuauUserDefinedTypeFunctions) + if (FFlag::LuauSolverV2 && FFlag::LuauUserDefinedTypeFunctions) CHECK_EQ(toString(&tv, {}), "woohoo"); } diff --git a/Dependencies/luau/Luau/tests/TxnLog.test.cpp b/Dependencies/luau/Luau/tests/TxnLog.test.cpp index d050fb9d..b4b18353 100644 --- a/Dependencies/luau/Luau/tests/TxnLog.test.cpp +++ b/Dependencies/luau/Luau/tests/TxnLog.test.cpp @@ -12,7 +12,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) struct TxnLogFixture { @@ -35,7 +35,7 @@ TEST_SUITE_BEGIN("TxnLog"); TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_greater_scope") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; log.replace(c, BoundType{a}); log2.replace(a, BoundType{c}); @@ -68,7 +68,7 @@ TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_greater_scop TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_lesser_scope") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; log.replace(a, BoundType{c}); log2.replace(c, BoundType{a}); @@ -101,7 +101,7 @@ TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_lesser_scope TEST_CASE_FIXTURE(TxnLogFixture, "colliding_coincident_logs_do_not_create_degenerate_unions") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; log.replace(a, BoundType{b}); log2.replace(a, BoundType{b}); diff --git a/Dependencies/luau/Luau/tests/TypeFunction.test.cpp b/Dependencies/luau/Luau/tests/TypeFunction.test.cpp index 7b45a69c..2b7b40a3 100644 --- a/Dependencies/luau/Luau/tests/TypeFunction.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeFunction.test.cpp @@ -12,7 +12,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauUserDefinedTypeFunctions) LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit) @@ -67,7 +67,7 @@ TEST_SUITE_BEGIN("TypeFunctionTests"); TEST_CASE_FIXTURE(TypeFunctionFixture, "basic_type_function") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -89,7 +89,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "basic_type_function") TEST_CASE_FIXTURE(TypeFunctionFixture, "function_as_fn_ret") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "function_as_fn_ret") TEST_CASE_FIXTURE(TypeFunctionFixture, "function_as_fn_arg") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -126,7 +126,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "function_as_fn_arg") TEST_CASE_FIXTURE(TypeFunctionFixture, "resolve_deep_functions") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -139,7 +139,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "resolve_deep_functions") TEST_CASE_FIXTURE(TypeFunctionFixture, "unsolvable_function") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -159,7 +159,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "unsolvable_function") TEST_CASE_FIXTURE(TypeFunctionFixture, "table_internal_functions") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -179,7 +179,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "table_internal_functions") TEST_CASE_FIXTURE(TypeFunctionFixture, "function_internal_functions") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -200,7 +200,7 @@ TEST_CASE_FIXTURE(TypeFunctionFixture, "function_internal_functions") TEST_CASE_FIXTURE(Fixture, "add_function_at_work") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -229,7 +229,7 @@ TEST_CASE_FIXTURE(Fixture, "add_function_at_work") TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_add_function_at_work") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -242,7 +242,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_add_function_at_work") TEST_CASE_FIXTURE(BuiltinsFixture, "mul_function_with_union_of_multiplicatives") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; loadDefinition(R"( @@ -265,7 +265,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "mul_function_with_union_of_multiplicatives") TEST_CASE_FIXTURE(BuiltinsFixture, "mul_function_with_union_of_multiplicatives_2") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; loadDefinition(R"( @@ -285,7 +285,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "mul_function_with_union_of_multiplicatives_2 TEST_CASE_FIXTURE(Fixture, "internal_functions_raise_errors") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -303,7 +303,7 @@ TEST_CASE_FIXTURE(Fixture, "internal_functions_raise_errors") TEST_CASE_FIXTURE(BuiltinsFixture, "type_functions_can_be_shadowed") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -328,7 +328,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_functions_can_be_shadowed") TEST_CASE_FIXTURE(BuiltinsFixture, "type_functions_inhabited_with_normalization") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_functions_inhabited_with_normalization" TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -367,7 +367,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works") TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works_with_metatables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -388,9 +388,28 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works_with_metatables") CHECK_EQ("\"w\" | \"x\" | \"y\" | \"z\"", toString(tpm->givenTp)); } +TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_single_entry_no_uniontype") +{ + if (!FFlag::LuauSolverV2) + return; + + CheckResult result = check(R"( + local tbl_A = { abc = "value" } + local tbl_B = { a1 = nil, ["a2"] = nil } + + type keyof_A = keyof + type keyof_B = keyof + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + + CHECK(toString(requireTypeAlias("keyof_A")) == "\"abc\""); + CHECK(toString(requireTypeAlias("keyof_B")) == "\"a1\" | \"a2\""); +} + TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_errors_if_it_has_nontable_part") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -408,7 +427,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_errors_if_it_has_nontabl TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_string_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -436,7 +455,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_string_indexer") TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_common_subset_if_union_of_differing_tables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -457,7 +476,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_common_subset_if_union_o TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_never_for_empty_table") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -472,7 +491,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_never_for_empty_table") TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_works") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -493,7 +512,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_works") TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_ignores_metatables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -516,7 +535,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_ignores_metatables") TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_errors_if_it_has_nontable_part") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -534,7 +553,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_errors_if_it_has_nont TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_common_subset_if_union_of_differing_tables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -555,7 +574,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_common_subset_if_unio TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_never_for_empty_table") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -570,7 +589,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_never_for_empty_table TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_works_on_classes") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -590,7 +609,7 @@ TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_works_on_classes") TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_errors_if_it_has_nonclass_part") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -607,7 +626,7 @@ TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_errors_if_it_has_nonclass_p TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_common_subset_if_union_of_differing_classes") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -619,9 +638,23 @@ TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_common_subset_if_union_of_d LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(ClassFixture, "keyof_type_function_works_with_parent_classes_too") +{ + if (!FFlag::LuauSolverV2) + return; + + CheckResult result = check(R"( + type KeysOfMyObject = keyof + + local function ok(idx: KeysOfMyObject): "BaseField" | "BaseMethod" | "Method" | "Touched" return idx end + )"); + + LUAU_REQUIRE_NO_ERRORS(result); +} + TEST_CASE_FIXTURE(ClassFixture, "binary_type_function_works_with_default_argument") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -636,7 +669,7 @@ TEST_CASE_FIXTURE(ClassFixture, "binary_type_function_works_with_default_argumen TEST_CASE_FIXTURE(ClassFixture, "vector2_multiply_is_overloaded") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -659,7 +692,7 @@ TEST_CASE_FIXTURE(ClassFixture, "vector2_multiply_is_overloaded") TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_rfc_example") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -690,7 +723,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_rfc_example") TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_oss_crash_gh1161") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -730,7 +763,7 @@ _(setmetatable(_,{[...]=_,})) TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_concat_function_at_work") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -743,7 +776,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_concat_function_at_work") TEST_CASE_FIXTURE(BuiltinsFixture, "exceeded_distributivity_limits") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; ScopedFastInt sfi{DFInt::LuauTypeFamilyApplicationCartesianProductLimit, 10}; @@ -776,7 +809,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exceeded_distributivity_limits") TEST_CASE_FIXTURE(BuiltinsFixture, "didnt_quite_exceed_distributivity_limits") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; // We duplicate the test here because we want to make sure the test failed @@ -810,7 +843,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "didnt_quite_exceed_distributivity_limits") TEST_CASE_FIXTURE(BuiltinsFixture, "ensure_equivalence_with_distributivity") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; loadDefinition(R"( @@ -843,7 +876,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ensure_equivalence_with_distributivity") TEST_CASE_FIXTURE(BuiltinsFixture, "we_shouldnt_warn_that_a_reducible_type_function_is_uninhabited") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -873,7 +906,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -894,9 +927,35 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works") CHECK_EQ("string", toString(tpm->givenTp)); } +TEST_CASE_FIXTURE(BuiltinsFixture, "index_wait_for_pending_no_crash") +{ + if (!FFlag::LuauSolverV2) + return; + + CheckResult result = check(R"( + local PlayerData = { + Coins = 0, + Level = 1, + Exp = 0, + MaxExp = 100 + } + + type Keys = index> + + -- This function makes it think that there's going to be a pending expansion + local function UpdateData(key: Keys, value) + PlayerData[key] = value + end + + UpdateData("Coins", 2) + )"); + + // Should not crash! +} + TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_array") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -911,7 +970,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_array") TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_generic_types") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -933,7 +992,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_generic_types") TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_errors_w_bad_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -949,7 +1008,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_errors_w_bad_indexer") TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_errors_w_var_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -966,7 +1025,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_errors_w_var_indexer") TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_union_type_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -984,7 +1043,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_union_type_index TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_union_type_indexee") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1003,7 +1062,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_union_type_index TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_rfc_alternative_section") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1021,7 +1080,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_rfc_alternative_section" TEST_CASE_FIXTURE(ClassFixture, "index_type_function_works_on_classes") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1033,9 +1092,23 @@ TEST_CASE_FIXTURE(ClassFixture, "index_type_function_works_on_classes") LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(ClassFixture, "index_type_function_works_on_classes_with_parents") +{ + if (!FFlag::LuauSolverV2) + return; + + CheckResult result = check(R"( + type KeysOfMyObject = index + + local function ok(idx: KeysOfMyObject): number return idx end + )"); + + LUAU_REQUIRE_NO_ERRORS(result); +} + TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_index_metatables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1061,7 +1134,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_index_metatables TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1083,7 +1156,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works") TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_array") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1097,7 +1170,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_array") TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_errors_w_var_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1113,7 +1186,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_errors_w_var_indexer") TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_union_type_indexer") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1129,7 +1202,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_union_type_inde TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_union_type_indexee") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1146,7 +1219,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_union_type_inde TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_index_metatables") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1166,7 +1239,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_index_metatable TEST_CASE_FIXTURE(ClassFixture, "rawget_type_function_errors_w_classes") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( diff --git a/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp index 5b689939..bb5a2cdd 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.aliases.test.cpp @@ -8,7 +8,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauUserDefinedTypeFunctions) TEST_SUITE_BEGIN("TypeAliases"); @@ -72,7 +72,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK( result.errors[0] == @@ -105,7 +105,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias") TEST_CASE_FIXTURE(Fixture, "mismatched_generic_type_param") { // We erroneously report an extra error in this case when the new solver is enabled. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type T = (A...) -> () @@ -205,7 +205,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases") TEST_CASE_FIXTURE(Fixture, "generic_aliases") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; CheckResult result = check(R"( type T = { v: a } @@ -223,7 +223,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases") TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; CheckResult result = check(R"( @@ -244,7 +244,7 @@ TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases") { // CLI-116108 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -344,7 +344,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("t1 where t1 = ({ a: t1 }) -> string", toString(tm->wantedType)); else CHECK_EQ("t1 where t1 = ({| a: t1 |}) -> string", toString(tm->wantedType)); @@ -355,7 +355,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ TEST_CASE_FIXTURE(Fixture, "cli_38393_recursive_intersection_oom") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; // FIXME CheckResult result = check(R"( @@ -417,7 +417,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_function_types") TEST_CASE_FIXTURE(Fixture, "generic_param_remap") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; const std::string code = R"( -- An example of a forwarded use of a type that has different type arguments than parameters @@ -543,7 +543,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation") TEST_CASE_FIXTURE(Fixture, "type_alias_local_mutation") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Cool = { a: number, b: string } @@ -564,7 +564,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_local_mutation") TEST_CASE_FIXTURE(Fixture, "type_alias_local_rename") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Cool = { a: number, b: string } @@ -660,7 +660,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_generic_ ty2 = lookupType("X"); REQUIRE(ty2); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK(toString(*ty1, {true}) == "t1 where t1 = { C: t1?, a: T, b: U }"); CHECK(toString(*ty2, {true}) == "t1 where t1 = { C: t1?, a: U, b: T }"); @@ -712,7 +712,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_ok") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1") { // CLI-116108 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( -- OK because forwarded types are used with their parameters. @@ -726,7 +726,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2") { // CLI-116108 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( -- Not OK because forwarded types are used with different types than their parameters. @@ -750,7 +750,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok") { // CLI-116108 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Tree1 = { data: T, children: {Tree2} } @@ -855,7 +855,7 @@ TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_uni local d: FutureType = { smth = true } -- missing error, 'd' is resolved to 'any' )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ foo: number }", toString(requireType("d"), {true})); else CHECK_EQ("{| foo: number |}", toString(requireType("d"), {true})); @@ -875,7 +875,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok") TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok") { // CLI-116108 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( -- this would be an infinite type if we allowed it @@ -888,7 +888,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok") TEST_CASE_FIXTURE(Fixture, "report_shadowed_aliases") { // CLI-116110 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; // We allow a previous type alias to depend on a future type alias. That exact feature enables a confusing example, like the following snippet, // which has the type alias FakeString point to the type alias `string` that which points to `number`. @@ -972,7 +972,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_locations") TEST_CASE_FIXTURE(BuiltinsFixture, "dont_lose_track_of_PendingExpansionTypes_after_substitution") { // CLI-114134 - We need egraphs to properly simplify these types. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; fileResolver.source["game/ReactCurrentDispatcher"] = R"( export type BasicStateAction = ((S) -> S) | S @@ -1115,7 +1115,7 @@ type Foo = Foo TEST_CASE_FIXTURE(Fixture, "recursive_type_alias_bad_pack_use_warns") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1155,7 +1155,7 @@ type Foo = Foo | string TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_adds_reduce_constraint_for_type_function") { - if (!FFlag::DebugLuauDeferredConstraintResolution || !FFlag::LuauUserDefinedTypeFunctions) + if (!FFlag::LuauSolverV2 || !FFlag::LuauUserDefinedTypeFunctions) return; CheckResult result = check(R"( diff --git a/Dependencies/luau/Luau/tests/TypeInfer.annotations.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.annotations.test.cpp index 02f34054..4029924a 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.annotations.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.annotations.test.cpp @@ -7,7 +7,7 @@ #include "doctest.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(DebugLuauMagicTypes); using namespace Luau; @@ -78,7 +78,7 @@ TEST_CASE_FIXTURE(Fixture, "assignment_cannot_transform_a_table_property_type") TEST_CASE_FIXTURE(Fixture, "assignments_to_unannotated_parameters_can_transform_the_type") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(x) @@ -94,7 +94,7 @@ TEST_CASE_FIXTURE(Fixture, "assignments_to_unannotated_parameters_can_transform_ TEST_CASE_FIXTURE(Fixture, "assignments_to_annotated_parameters_are_checked") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(x: string) @@ -264,7 +264,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_of_value_a_via_typeof_with_assignment") a = "foo" )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("string?" == toString(requireType("a"))); CHECK("nil" == toString(requireType("b"))); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.anyerror.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.anyerror.test.cpp index dc1c6199..445ce072 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.anyerror.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.anyerror.test.cpp @@ -13,7 +13,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("TypeInferAnyError"); @@ -32,7 +32,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any?" == toString(requireType("a"))); else CHECK(builtinTypes->anyType == requireType("a")); @@ -53,7 +53,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any2") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any?" == toString(requireType("a"))); else CHECK("any" == toString(requireType("a"))); @@ -72,7 +72,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any?" == toString(requireType("a"))); else CHECK("any" == toString(requireType("a"))); @@ -89,7 +89,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any2") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any?" == toString(requireType("a"))); else CHECK("any" == toString(requireType("a"))); @@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any_pack") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any?" == toString(requireType("a"))); else CHECK("any" == toString(requireType("a"))); @@ -126,7 +126,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // Bug: We do not simplify at the right time CHECK_EQ("*error-type*?", toString(requireType("a"))); @@ -148,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-97375(awe): `bar()` is returning `nil` here, which isn't wrong necessarily, // but then we're signaling an additional error for the access on `nil`. @@ -277,7 +277,7 @@ TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error") CHECK_EQ("unknown", err->name); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("any", toString(requireType("a"))); else CHECK_EQ("*error-type*", toString(requireType("a"))); @@ -289,7 +289,7 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error") local a = Utility.Create "Foo" {} )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("any", toString(requireType("a"))); else CHECK_EQ("*error-type*", toString(requireType("a"))); @@ -307,7 +307,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_comp LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("any?", toString(requireType("b"))); else CHECK_EQ("any", toString(requireType("b"))); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp index d52e6390..9912cc35 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.builtins.test.cpp @@ -8,7 +8,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("BuiltinTests"); @@ -132,7 +132,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate") TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -414,7 +414,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ [number]: boolean | number | string, n: number }", toString(requireType("t"))); else CHECK_EQ("{| [number]: boolean | number | string, n: number |}", toString(requireType("t"))); @@ -432,7 +432,7 @@ local t = table.pack(f()) )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ [number]: number | string, n: number }", toString(requireType("t"))); else CHECK_EQ("{| [number]: number | string, n: number |}", toString(requireType("t"))); @@ -445,7 +445,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_reduce") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ [number]: boolean | number, n: number }", toString(requireType("t"))); else CHECK_EQ("{| [number]: boolean | number, n: number |}", toString(requireType("t"))); @@ -455,7 +455,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_reduce") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ [number]: string, n: number }", toString(requireType("t"))); else CHECK_EQ("{| [number]: string, n: number |}", toString(requireType("t"))); @@ -512,7 +512,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "buffer_is_a_type") TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function nifty(x, y) @@ -551,7 +551,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes") TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_types") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -599,7 +599,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_count_mismatch") TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_correctly_ordered_types") { // CLI-115690 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -703,7 +703,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // Counterintuitively, the parameter l0 is unconstrained and therefore it is valid to pass nil. // The new solver therefore considers that parameter to be optional. @@ -721,7 +721,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash") TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range") { // CLI-115720 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -736,7 +736,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range") TEST_CASE_FIXTURE(BuiltinsFixture, "select_slightly_out_of_range") { // CLI-115720 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -770,7 +770,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail") TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_string_head") { // CLI-115720 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -792,10 +792,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_strin TEST_CASE_FIXTURE(Fixture, "string_format_as_method") { - // CLI-115690 - if (FFlag::DebugLuauDeferredConstraintResolution) - return; - CheckResult result = check("local _ = ('%s'):format(5)"); LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -819,10 +815,6 @@ TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument") TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2") { - // CLI-115690 - if (FFlag::DebugLuauDeferredConstraintResolution) - return; - CheckResult result = check(R"( local _ = ("%s %d").format("%d %s", "A type error", 2) )"); @@ -881,10 +873,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy") TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format") { - // CLI-115690 - if (FFlag::DebugLuauDeferredConstraintResolution) - return; - CheckResult result = check(R"( local fmt = string.format local s = fmt("%d", "oops") @@ -944,10 +932,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic") TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_correct_positions") { - // CLI-115690 - if (FFlag::DebugLuauDeferredConstraintResolution) - return; - CheckResult result = check(R"( ("%s%d%s"):format(1, "hello", true) string.format("%s%d%s", 1, "hello", true) @@ -986,7 +970,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tonumber_returns_optional_number_type") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ( "Type 'number?' could not be converted into 'number'; type number?[1] (nil) is not a subtype of number (number)", toString(result.errors[0]) @@ -1009,7 +993,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types") { // This test makes no sense with type states and I think it generally makes no sense under the new solver. // TODO: clip. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1042,7 +1026,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f"))); else CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f"))); @@ -1070,7 +1054,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types3") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f"))); else // without the annotation, the old solver doesn't infer the best return type here CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f"))); @@ -1078,7 +1062,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types3") TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pack_tail_but_only_for_the_first_type") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1093,7 +1077,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pa TEST_CASE_FIXTURE(BuiltinsFixture, "assert_returns_false_and_string_iff_it_knows_the_first_argument_cannot_be_truthy") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114134 - egraph simplification return; @@ -1128,7 +1112,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Key 'b' not found in table '{ a: number }'" == toString(result.errors[0])); else CHECK_EQ("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0])); @@ -1138,7 +1122,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") CHECK_EQ("string", toString(requireType("b"))); CHECK_EQ("boolean", toString(requireType("c"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("any", toString(requireType("d"))); else CHECK_EQ("*error-type*", toString(requireType("d"))); @@ -1147,7 +1131,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments") { // In the new solver, nil can certainly be used where a generic is required, so all generic parameters are optional. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a = {b=setmetatable} diff --git a/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp index 17b14082..16751559 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.classes.test.cpp @@ -13,7 +13,7 @@ using namespace Luau; using std::nullopt; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("TypeInferClasses"); @@ -128,7 +128,7 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_infer_that_a_parameter_must_be_a_particu TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function makeClone(o) @@ -156,7 +156,7 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_t TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class_using_new_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function makeClone(o) @@ -235,7 +235,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class_using_string") TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive") { // This is allowed in the new solver - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local v = Vector2.New(0, 5) @@ -397,7 +397,7 @@ TEST_CASE_FIXTURE(ClassFixture, "table_class_unification_reports_sane_errors_for foo(a) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK("Type 'Vector2' could not be converted into '{ Y: number, w: number, x: number }'" == toString(result.errors[0])); @@ -454,7 +454,7 @@ b(a) LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("Type 'number' could not be converted into 'string'" == toString(result.errors.at(0))); } @@ -472,7 +472,7 @@ Type 'number' could not be converted into 'string')"; TEST_CASE_FIXTURE(ClassFixture, "class_type_mismatch_with_name_conflict") { // CLI-116433 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local i = ChildClass.New() @@ -545,7 +545,7 @@ local b: B = a LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Type 'A' could not be converted into 'B'; at [read \"x\"], ChildClass is not exactly BaseClass"); else { @@ -559,7 +559,7 @@ Type 'ChildClass' could not be converted into 'BaseClass' in an invariant contex TEST_CASE_FIXTURE(ClassFixture, "optional_class_casts_work_in_new_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type A = { x: ChildClass } @@ -664,7 +664,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local y = x[true] )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( "Type 'boolean' could not be converted into 'number | string'" == toString(result.errors.at(0)) ); @@ -679,7 +679,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") x[true] = 42 )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( "Type 'boolean' could not be converted into 'number | string'" == toString(result.errors.at(0)) ); @@ -696,7 +696,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") x.key = "string value" )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // Disabled for now. CLI-115686 } @@ -724,7 +724,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local x : IndexableNumericKeyClass x["key"] = 1 )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(result.errors.at(0)), "Key 'key' not found in class 'IndexableNumericKeyClass'"); else CHECK_EQ(toString(result.errors.at(0)), "Type 'string' could not be converted into 'number'"); @@ -749,7 +749,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") local x : IndexableNumericKeyClass local y = x["key"] )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Key 'key' not found in class 'IndexableNumericKeyClass'"); else CHECK_EQ(toString(result.errors.at(0)), "Type 'string' could not be converted into 'number'"); @@ -766,7 +766,7 @@ TEST_CASE_FIXTURE(ClassFixture, "indexable_classes") TEST_CASE_FIXTURE(Fixture, "read_write_class_properties") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; TypeArena& arena = frontend.globals.globalTypes; diff --git a/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp index 773636c6..c76745c7 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.functions.test.cpp @@ -17,7 +17,7 @@ using namespace Luau; LUAU_FASTFLAG(LuauInstantiateInSubtyping); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTINT(LuauTarjanChildLimit); LUAU_DYNAMIC_FASTFLAG(LuauImproveNonFunctionCallError) @@ -79,7 +79,7 @@ TEST_CASE_FIXTURE(Fixture, "check_function_bodies") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { const TypePackMismatch* tm = get(result.errors[0]); REQUIRE(tm); @@ -238,7 +238,7 @@ TEST_CASE_FIXTURE(Fixture, "list_only_alternative_overloads_that_match_argument_ LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { GenericError* g = get(result.errors[0]); REQUIRE(g); @@ -255,7 +255,7 @@ TEST_CASE_FIXTURE(Fixture, "list_only_alternative_overloads_that_match_argument_ ExtraInformation* ei = get(result.errors[1]); REQUIRE(ei); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Available overloads: (number) -> number; (number) -> string; and (number, number) -> number" == ei->message); else CHECK_EQ("Other overloads are also not viable: (number) -> string", ei->message); @@ -312,7 +312,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type_from_selected_overload") TEST_CASE_FIXTURE(Fixture, "too_many_arguments") { // This is not part of the new non-strict specification currently. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -480,7 +480,7 @@ TEST_CASE_FIXTURE(Fixture, "another_higher_order_function") TEST_CASE_FIXTURE(Fixture, "another_other_higher_order_function") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CheckResult result = check(R"( local function f(d) @@ -490,7 +490,6 @@ TEST_CASE_FIXTURE(Fixture, "another_other_higher_order_function") )"); LUAU_REQUIRE_NO_ERRORS(result); - } else { @@ -605,7 +604,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_functions_allowed_in_nonstrict") TEST_CASE_FIXTURE(Fixture, "duplicate_functions_with_different_signatures_not_allowed_in_nonstrict") { // This is not part of the spec for the new non-strict mode currently. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -778,11 +777,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4") end )"); - // This function currently has a bug in the new solver reporting `{T} | {T}` is not a table. - if (FFlag::DebugLuauDeferredConstraintResolution) - LUAU_REQUIRE_ERRORS(result); - else - LUAU_REQUIRE_NO_ERRORS(result); + LUAU_REQUIRE_NO_ERRORS(result); /* * mergesort takes two arguments: an array of some type T and a function that takes two Ts. @@ -888,7 +883,7 @@ TEST_CASE_FIXTURE(Fixture, "another_indirect_function_case_where_it_is_ok_to_pro TEST_CASE_FIXTURE(Fixture, "report_exiting_without_return_nonstrict") { // new non-strict mode spec does not include this error yet. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -1014,7 +1009,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_lea opts.exhaustive = true; opts.maxTableLength = 0; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{string}", toString(requireType("tab"), opts)); else CHECK_EQ("{any}", toString(requireType("tab"), opts)); @@ -1023,7 +1018,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_lea TEST_CASE_FIXTURE(Fixture, "too_many_return_values") { // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -1047,7 +1042,7 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values") TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses") { // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -1071,7 +1066,7 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses") TEST_CASE_FIXTURE(Fixture, "too_many_return_values_no_function") { // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -1113,7 +1108,7 @@ TEST_CASE_FIXTURE(Fixture, "function_does_not_return_enough_values") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -1153,7 +1148,7 @@ TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language") REQUIRE(tm1); CHECK_EQ("(string) -> number", toString(tm1->wantedType)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(unknown, unknown) -> number", toString(tm1->givenType)); else CHECK_EQ("(string, *error-type*) -> number", toString(tm1->givenType)); @@ -1162,7 +1157,7 @@ TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language") REQUIRE(tm2); CHECK_EQ("(number, number) -> (number, number)", toString(tm2->wantedType)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(unknown, unknown) -> number", toString(tm1->givenType)); else CHECK_EQ("(string, *error-type*) -> number", toString(tm2->givenType)); @@ -1182,7 +1177,7 @@ TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type") LUAU_REQUIRE_NO_ERRORS(result); TypeId type = requireTypeAtPosition(Position(6, 14)); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(unknown, number, number) -> number", toString(type)); else CHECK_EQ("(tbl, number, number) -> number", toString(type)); @@ -1229,7 +1224,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_by_overload") LUAU_REQUIRE_ERRORS(result); CHECK_EQ("string", toString(requireType("x"))); // the new solver does not currently "favor" arity-matching overloads when the call itself is ill-typed. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("string", toString(requireType("y"))); else CHECK_EQ("number", toString(requireType("y"))); @@ -1240,7 +1235,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_by_overload") TEST_CASE_FIXTURE(BuiltinsFixture, "infer_anonymous_function_arguments") { // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; // Simple direct arg to arg propagation CheckResult result = check(R"( @@ -1359,7 +1354,7 @@ f(function(x) return x * 2 end) TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument") { // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function sum(x: a, y: a, f: (a, a) -> a) return f(x, y) end @@ -1390,7 +1385,7 @@ local r = foldl(a, {s=0,c=0}, function(a, b) return {s = a.s + b, c = a.c + 1} e TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded") { // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function g1(a: T, f: (T) -> T) return f(a) end @@ -1457,7 +1452,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "variadic_any_is_compatible_with_a_generic_Ty TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments_outside_call") { // FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Table = { x: number, y: number } @@ -1491,7 +1486,7 @@ end )"); // `h` regresses in the new solver, the return type is not being pushed into the body. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_ERROR_COUNT(1, result); else LUAU_REQUIRE_NO_ERRORS(result); @@ -1500,7 +1495,7 @@ end TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg_count") { // FIXME: CLI-116111 test disabled until type path stringification is improved - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = (number, number) -> string @@ -1523,7 +1518,7 @@ caused by: TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg") { // FIXME: CLI-116111 test disabled until type path stringification is improved - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = (number, number) -> string @@ -1547,7 +1542,7 @@ Type 'string' could not be converted into 'number')"; TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_count") { // FIXME: CLI-116111 test disabled until type path stringification is improved - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = (number, number) -> (number) @@ -1570,7 +1565,7 @@ caused by: TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret") { // FIXME: CLI-116111 test disabled until type path stringification is improved - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = (number, number) -> string @@ -1594,7 +1589,7 @@ Type 'string' could not be converted into 'number')"; TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_mult") { // FIXME: CLI-116111 test disabled until type path stringification is improved - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = (number, number) -> (number, string) @@ -1675,11 +1670,17 @@ t.f = function(x) end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK_EQ(toString(result.errors[0]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); - CHECK_EQ(toString(result.errors[1]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); + CHECK_EQ( + toString(result.errors[0]), + R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)" + ); + CHECK_EQ( + toString(result.errors[1]), + R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)" + ); } else { @@ -1717,8 +1718,9 @@ TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_th TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_the_right_time3") { - // This test regresses in the new solver, but is sort of nonsensical insofar as `foo` is known to be `nil`, so it's "right" to not be able to call it. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + // This test regresses in the new solver, but is sort of nonsensical insofar as `foo` is known to be `nil`, so it's "right" to not be able to call + // it. + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local foo @@ -1746,10 +1748,13 @@ t.f = function(x) end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK_EQ(toString(result.errors[0]), R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)"); + CHECK_EQ( + toString(result.errors[0]), + R"(Type function instance add depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this time)" + ); } else { @@ -1784,7 +1789,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_mode_ok_with_missing_arguments") TEST_CASE_FIXTURE(Fixture, "function_statement_sealed_table_assignment_through_indexer") { // FIXME: CLI-116122 bug where `t:b` does not check against the type from the indexer annotation on `t`. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t: {[string]: () -> number} = {} @@ -1829,7 +1834,7 @@ TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic") TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic") { // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function test(a: number, b: string, ...) @@ -1857,7 +1862,7 @@ wrapper(test) TEST_CASE_FIXTURE(BuiltinsFixture, "too_few_arguments_variadic_generic2") { // FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function test(a: number, b: string, ...) @@ -1898,7 +1903,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_failure_in_function_return_type") TEST_CASE_FIXTURE(Fixture, "free_is_not_bound_to_unknown") { // This test only makes sense for the old solver - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1932,7 +1937,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_infer_parameter_types_for_functions_from_their_ LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ("(a) -> a", toString(requireType("f"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("({ read p: { read q: unknown } }) -> ~(false?)?", toString(requireType("g"))); else CHECK_EQ("({+ p: {+ q: nil +} +}) -> nil", toString(requireType("g"))); @@ -1980,7 +1985,7 @@ u.b().foo() )"); LUAU_REQUIRE_ERROR_COUNT(9, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // These improvements to the error messages are currently regressed in the new type solver. CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function expects 1 argument, but none are specified"); @@ -2011,7 +2016,7 @@ u.b().foo() TEST_CASE_FIXTURE(BuiltinsFixture, "improved_function_arg_mismatch_error_nonstrict") { // This behavior is not part of the current specification of the new type solver. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -2026,7 +2031,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "improved_function_arg_mismatch_error_nonstri TEST_CASE_FIXTURE(Fixture, "luau_subtyping_is_np_hard") { // The case that _should_ succeed here (`z = x`) does not currently in the new solver. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -2148,7 +2153,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "dont_assert_when_the_tarjan_limit_is_exceeded_during_generalization") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; ScopedFastInt sfi{FInt::LuauTarjanChildLimit, 1}; CheckResult result = check(R"( @@ -2194,7 +2199,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiated_type_packs_must_have_a_non_null_scope") TEST_CASE_FIXTURE(Fixture, "inner_frees_become_generic_in_dcr") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -2224,7 +2229,7 @@ TEST_CASE_FIXTURE(Fixture, "function_exprs_are_generalized_at_signature_scope_no )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(requireType("foo")) == "((unknown) -> nil)?"); else { @@ -2243,7 +2248,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_bu local ret: number = foo(vec2, { x = 5 }) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -2307,7 +2312,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "param_1_and_2_both_takes_the_same_generic_bu local z: boolean = f(5, "five") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -2337,14 +2342,14 @@ TEST_CASE_FIXTURE(Fixture, "attempt_to_call_an_intersection_of_tables") if (DFFlag::LuauImproveNonFunctionCallError) { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(result.errors[0]), "Cannot call a value of type { x: number } & { y: string }"); else CHECK_EQ(toString(result.errors[0]), "Cannot call a value of type {| x: number |}"); } else { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(result.errors[0]), "Cannot call non-function { x: number } & { y: string }"); else CHECK_EQ(toString(result.errors[0]), "Cannot call non-function {| x: number |}"); @@ -2368,7 +2373,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "attempt_to_call_an_intersection_of_tables_wi TEST_CASE_FIXTURE(Fixture, "generic_packs_are_not_variadic") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function apply(f: (a, b...) -> c..., x: a) @@ -2404,7 +2409,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Type pack 'string' could not be converted into 'number'; at [0], string is not a subtype of number"); else CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); @@ -2429,7 +2434,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_after_num_or_str") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Type pack 'string' could not be converted into 'number'; at [0], string is not a subtype of number"); else CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); @@ -2477,6 +2482,9 @@ a = function(a, b) return a + b end TEST_CASE_FIXTURE(BuiltinsFixture, "simple_unannotated_mutual_recursion") { + // CLI-117118 - TypeInferFunctions.simple_unannotated_mutual_recursion relies on unstable assertions to pass. + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( function even(n) if n == 0 then @@ -2497,14 +2505,16 @@ function odd(n) end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(5, result); + // CLI-117117 Constraint solving is incomplete inTypeInferFunctions.simple_unannotated_mutual_recursion CHECK(get(result.errors[0])); - CHECK( - toString(result.errors[1]) == - "Type pack '*blocked-tp-1*' could not be converted into 'boolean'; type *blocked-tp-1*.tail() (*blocked-tp-1*) is not a subtype of boolean (boolean)" - ); + // This check is unstable between different machines and different runs of DCR because it depends on string equality between + // blocked type numbers, which is not guaranteed. + bool r = toString(result.errors[1]) == "Type pack '*blocked-tp-1*' could not be converted into 'boolean'; type *blocked-tp-1*.tail() " + "(*blocked-tp-1*) is not a subtype of boolean (boolean)"; + CHECK(r); CHECK( toString(result.errors[2]) == "Operator '-' could not be applied to operands of types unknown and number; there is no corresponding overload for __sub" @@ -2555,7 +2565,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_return_type") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( function fib(n) @@ -2573,7 +2583,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_arg_type") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( function fib(n, u) @@ -2592,7 +2602,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_arg_type_2") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; // Make sure the error types are cloned to module interface @@ -2645,7 +2655,7 @@ TEST_CASE_FIXTURE(Fixture, "bidirectional_checking_of_callback_property") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { auto tm = get(result.errors[0]); REQUIRE(tm); @@ -2717,7 +2727,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_infer_overloaded_functions") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(t1) -> () where t1 = { read FindFirstChild: (t1, string) -> (...unknown) }" == toString(requireType("getR6Attachments"))); else CHECK("(t1) -> () where t1 = {+ FindFirstChild: (t1, string) -> (a...) +}" == toString(requireType("getR6Attachments"))); @@ -2881,7 +2891,7 @@ TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // The new solver should ideally be able to do better here, but this is no worse than the old solver. diff --git a/Dependencies/luau/Luau/tests/TypeInfer.generics.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.generics.test.cpp index 8741da6a..ffd01f24 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.generics.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.generics.test.cpp @@ -7,10 +7,11 @@ #include "Fixture.h" +#include "ScopedFlags.h" #include "doctest.h" LUAU_FASTFLAG(LuauInstantiateInSubtyping); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); using namespace Luau; @@ -70,7 +71,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unions_and_generics") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("number | {number}", toString(requireType("res"))); else // in the old solver, this just totally falls apart CHECK_EQ("a", toString(requireType("res"))); @@ -142,6 +143,8 @@ TEST_CASE_FIXTURE(Fixture, "properties_can_be_polytypes") TEST_CASE_FIXTURE(Fixture, "properties_can_be_instantiated_polytypes") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( local t: { m: (number)->number } = { m = function(x:number) return x+1 end } local function id(x:a):a return x end @@ -196,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions") TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions_unannotated") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -218,7 +221,7 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions_unannotated") TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions_errors") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -256,8 +259,10 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions_errors") } } -TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types") +TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types_old_solver") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( type T = { id: (a) -> a } local x: T = { id = function(x:a):a return x end } @@ -267,8 +272,23 @@ TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types") LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types_new_solver") +{ + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; + + CheckResult result = check(R"( + type T = { read id: (a) -> a } + local x: T = { id = function(x:a):a return x end } + local y: string = x.id("hi") + local z: number = x.id(37) + )"); + LUAU_REQUIRE_NO_ERRORS(result); +} + TEST_CASE_FIXTURE(Fixture, "generic_factories") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( type T = { id: (a) -> a } type Factory = { build: () -> T } @@ -290,6 +310,8 @@ TEST_CASE_FIXTURE(Fixture, "generic_factories") TEST_CASE_FIXTURE(Fixture, "factories_of_generics") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( type T = { id: (a) -> a } type Factory = { build: () -> T } @@ -445,7 +467,14 @@ TEST_CASE_FIXTURE(Fixture, "dont_leak_generic_types") local b: boolean = f(true) )"); - LUAU_REQUIRE_ERRORS(result); + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERRORS(result); + } } TEST_CASE_FIXTURE(Fixture, "dont_leak_inferred_generic_types") @@ -461,7 +490,14 @@ TEST_CASE_FIXTURE(Fixture, "dont_leak_inferred_generic_types") local y: number = id(37) end )"); - LUAU_REQUIRE_ERRORS(result); + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERRORS(result); + } } TEST_CASE_FIXTURE(Fixture, "dont_substitute_bound_types") @@ -613,7 +649,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_type_pack_parentheses") // This should really error, but the error from the old solver is wrong. // `a...` is a generic type pack, and we don't know that it will be non-empty, thus this code may not work. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -634,7 +670,7 @@ TEST_CASE_FIXTURE(Fixture, "better_mismatch_error_messages") SwappedGenericTypeParameter* fErr; SwappedGenericTypeParameter* gErr; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(3, result); // The first error here is an unknown symbol that is redundant with the `fErr`. @@ -737,17 +773,19 @@ return exports LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names") +TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names_old_solver") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( -local function f(a: T, ...: U...) end + local function f(a: T, ...: U...) end -f(1, 2, 3) + f(1, 2, 3) )"); LUAU_REQUIRE_NO_ERRORS(result); - auto ty = findTypeAtPosition(Position(3, 0)); + auto ty = findTypeAtPosition(Position(3, 8)); REQUIRE(ty); ToStringOptions opts; opts.functionTypeArguments = true; @@ -756,6 +794,8 @@ f(1, 2, 3) TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( type C = () -> () type D = () -> () @@ -771,6 +811,8 @@ local d: D = c TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( type C = () -> () type D = () -> () @@ -825,7 +867,7 @@ y.a.c = y LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( toString(result.errors.at(0)) == R"(Type '{ a: { c: nil, d: number }, b: number }' could not be converted into 'T'; type { a: { c: nil, d: number }, b: number }[read "a"][read "c"] (nil) is not exactly T[read "a"][read "c"][0] (T))" @@ -845,6 +887,8 @@ Type 'number' could not be converted into 'string' in an invariant context)"; TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification1") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( --!strict type Dispatcher = { @@ -863,6 +907,8 @@ local TheDispatcher: Dispatcher = { TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification2") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( --!strict type Dispatcher = { @@ -881,6 +927,8 @@ local TheDispatcher: Dispatcher = { TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification3") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( --!strict type Dispatcher = { @@ -899,6 +947,8 @@ local TheDispatcher: Dispatcher = { TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( function test(a: number) return 1 @@ -916,6 +966,8 @@ wrapper(test) TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( function test2(a: number, b: string) return 1 @@ -1112,7 +1164,7 @@ local a: Self )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireType("a")), "Table
"); else CHECK_EQ(toString(requireType("a")), "Table"); @@ -1131,7 +1183,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying") std::optional t0 = lookupType("t0"); REQUIRE(t0); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("any", toString(*t0)); else CHECK_EQ("*error-type*", toString(*t0)); @@ -1151,7 +1203,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CheckResult result = check(R"( local function sum(x: a, y: a, f: (a, a) -> add) @@ -1208,7 +1260,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument_3") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) REQUIRE_EQ("{ c: number, s: number } | { c: number, s: number }", toString(requireType("r"))); else REQUIRE_EQ("{ c: number, s: number }", toString(requireType("r"))); @@ -1250,7 +1302,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions") CheckResult result; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { result = check(R"( local function sum(x: a, y: a, f: (a, a) -> a) return f(x, y) end @@ -1368,6 +1420,17 @@ TEST_CASE_FIXTURE(Fixture, "apply_type_function_nested_generics3") LUAU_REQUIRE_NO_ERRORS(result); } +TEST_CASE_FIXTURE(Fixture, "quantify_functions_with_no_generics") +{ + CheckResult result = check(R"( + function foo(f, x) + return f(x) + end + )"); + + CHECK("((a) -> (b...), a) -> (b...)" == toString(requireType("foo"))); +} + TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_generic") { CheckResult result = check(R"( @@ -1379,8 +1442,21 @@ TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_gen CHECK("((X) -> (a...), X) -> (a...)" == toString(requireType("foo"))); } +TEST_CASE_FIXTURE(Fixture, "no_extra_quantification_for_generic_functions") +{ + CheckResult result = check(R"( + function foo(f : (X) -> Y, x: X) + return f(x) + end + )"); + + CHECK("((X) -> Y, X) -> Y" == toString(requireType("foo"))); +} + TEST_CASE_FIXTURE(Fixture, "do_not_always_instantiate_generic_intersection_types") { + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + CheckResult result = check(R"( --!strict type Array = { [number]: T } @@ -1415,6 +1491,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "higher_rank_polymorphism_should_not_accept_instantiated_arguments") { ScopedFastFlag sffs[] = { + {FFlag::LuauSolverV2, false}, {FFlag::LuauInstantiateInSubtyping, true}, }; @@ -1479,9 +1556,24 @@ TEST_CASE_FIXTURE(Fixture, "missing_generic_type_parameter") REQUIRE(get(result.errors[1])); } +TEST_CASE_FIXTURE(Fixture, "generic_implicit_explicit_name_clash") +{ + ScopedFastFlag _{FFlag::LuauSolverV2, true}; + + auto result = check(R"( + function apply(func, argument: a) + return func(argument) + end + )"); + + CHECK("((a) -> (b...), a) -> (b...)" == toString(requireType("apply"))); +} + TEST_CASE_FIXTURE(BuiltinsFixture, "generic_type_functions_work_in_subtyping") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; + + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( diff --git a/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp index baef9245..50e28505 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.intersectionTypes.test.cpp @@ -9,7 +9,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("IntersectionTypes"); @@ -172,7 +172,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_property_guarante LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(A & B) -> { y: number }" == toString(requireType("f"))); else CHECK("(A & B) -> {| y: number |} & {| y: number |}" == toString(requireType("f"))); @@ -191,7 +191,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_works_at_arbitrary_dep LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(A & B) -> string", toString(requireType("f"))); else CHECK_EQ("(A & B) -> string & string", toString(requireType("f"))); @@ -210,7 +210,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_mixed_types") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(A & B) -> never", toString(requireType("f"))); else CHECK_EQ("(A & B) -> number & string", toString(requireType("f"))); @@ -333,7 +333,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed") TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect") { ScopedFastFlag dcr{ - FFlag::DebugLuauDeferredConstraintResolution, false + FFlag::LuauSolverV2, false }; // CLI-116476 Subtyping between type alias and an equivalent but not named type isn't working. CheckResult result = check(R"( type X = { x: (number) -> number } @@ -348,7 +348,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ(toString(result.errors[0]), "Cannot add property 'z' to table 'X & Y'"); @@ -372,7 +372,7 @@ caused by: TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect") { - ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, false}; // CLI- + ScopedFastFlag dcr{FFlag::LuauSolverV2, false}; // CLI- // After normalization, previous 'table_intersection_write_sealed_indirect' is identical to this one CheckResult result = check(R"( type XY = { x: (number) -> number, y: (string) -> string } @@ -430,7 +430,7 @@ Type 'number' could not be converted into 'X')"; R"(Type 'number' could not be converted into 'X & Y & Z'; type number (number) is not a subtype of X & Y & Z[0] (X) type number (number) is not a subtype of X & Y & Z[1] (Y) type number (number) is not a subtype of X & Y & Z[2] (Z))"; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(dcrExprected, toString(result.errors[0])); else CHECK_EQ(expected, toString(result.errors[0])); @@ -450,7 +450,7 @@ end )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( R"(Type pack 'X & Y & Z' could not be converted into 'number'; type X & Y & Z[0][0] (X) is not a subtype of number[0] (number) @@ -503,7 +503,7 @@ TEST_CASE_FIXTURE(Fixture, "intersect_bool_and_false") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( R"(Type 'boolean & false' could not be converted into 'true'; type boolean & false[0] (boolean) is not a subtype of true (true) @@ -528,7 +528,7 @@ TEST_CASE_FIXTURE(Fixture, "intersect_false_and_bool_and_false") LUAU_REQUIRE_ERROR_COUNT(1, result); // TODO: odd stringification of `false & (boolean & false)`.) - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ( R"(Type 'boolean & false & false' could not be converted into 'true'; type boolean & false & false[0] (false) is not a subtype of true (true) type boolean & false & false[1] (boolean) is not a subtype of true (true) @@ -550,21 +550,21 @@ TEST_CASE_FIXTURE(Fixture, "intersect_saturate_overloaded_functions") local z : (number) -> number = x -- Not OK end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); const std::string expected1 = R"(Type - '(nil) -> nil' + '((number?) -> number?) & ((string?) -> string?)' could not be converted into - '((number?) -> number?) & ((string?) -> string?)'; type (nil) -> nil.arguments()[0] (nil) is not a supertype of ((number?) -> number?) & ((string?) -> string?)[0].arguments()[0][0] (number) - type (nil) -> nil.arguments()[0] (nil) is not a supertype of ((number?) -> number?) & ((string?) -> string?)[1].arguments()[0][0] (string))"; + '(nil) -> nil'; type ((number?) -> number?) & ((string?) -> string?)[0].returns()[0][0] (number) is not a subtype of (nil) -> nil.returns()[0] (nil) + type ((number?) -> number?) & ((string?) -> string?)[1].returns()[0][0] (string) is not a subtype of (nil) -> nil.returns()[0] (nil))"; const std::string expected2 = R"(Type - '(number) -> number' + '((number?) -> number?) & ((string?) -> string?)' could not be converted into - '((number?) -> number?) & ((string?) -> string?)'; type (number) -> number.arguments()[0] (number) is not a supertype of ((number?) -> number?) & ((string?) -> string?)[0].arguments()[0][1] (nil) - type (number) -> number.arguments()[0] (number) is not a supertype of ((number?) -> number?) & ((string?) -> string?)[1].arguments()[0][0] (string) - type (number) -> number.arguments()[0] (number) is not a supertype of ((number?) -> number?) & ((string?) -> string?)[1].arguments()[0][1] (nil) - type (number) -> number.returns()[0] (number) is not a subtype of ((number?) -> number?) & ((string?) -> string?)[1].returns()[0] (string?))"; + '(number) -> number'; type ((number?) -> number?) & ((string?) -> string?)[0].returns()[0][1] (nil) is not a subtype of (number) -> number.returns()[0] (number) + type ((number?) -> number?) & ((string?) -> string?)[1].arguments()[0] (string?) is not a supertype of (number) -> number.arguments()[0] (number) + type ((number?) -> number?) & ((string?) -> string?)[1].returns()[0][0] (string) is not a subtype of (number) -> number.returns()[0] (number) + type ((number?) -> number?) & ((string?) -> string?)[1].returns()[0][1] (nil) is not a subtype of (number) -> number.returns()[0] (number))"; CHECK_EQ(expected1, toString(result.errors[0])); CHECK_EQ(expected2, toString(result.errors[1])); } @@ -582,7 +582,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_saturate_overloaded_functions") { ScopedFastFlag dcr{ - FFlag::DebugLuauDeferredConstraintResolution, false + FFlag::LuauSolverV2, false }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f(x: ((number) -> number) & ((string) -> string)) @@ -609,13 +609,12 @@ TEST_CASE_FIXTURE(Fixture, "intersection_of_tables") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = (FFlag::DebugLuauDeferredConstraintResolution) - ? "Type " - "'{ p: number?, q: number?, r: number? } & { p: number?, q: string? }'" - " could not be converted into " - "'{ p: nil }'; none of the intersection parts are compatible" - : - R"(Type + const std::string expected = + (FFlag::LuauSolverV2) + ? R"(Type '{ p: number?, q: number?, r: number? } & { p: number?, q: string? }' could not be converted into '{ p: nil }'; type { p: number?, q: number?, r: number? } & { p: number?, q: string? }[0][read "p"][0] (number) is not exactly { p: nil }[read "p"] (nil) + type { p: number?, q: number?, r: number? } & { p: number?, q: string? }[1][read "p"][0] (number) is not exactly { p: nil }[read "p"] (nil))" + : + R"(Type '{| p: number?, q: number?, r: number? |} & {| p: number?, q: string? |}' could not be converted into '{| p: nil |}'; none of the intersection parts are compatible)"; @@ -631,30 +630,20 @@ TEST_CASE_FIXTURE(Fixture, "intersection_of_tables_with_top_properties") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { - LUAU_REQUIRE_ERROR_COUNT(2, result); - - CHECK_EQ( - toString(result.errors[0]), - "Type '{| p: number?, q: string? |}' could not be converted into '{| p: string?, q: number? |}'\n" - "caused by:\n" - " Property 'p' is not compatible. Type 'number?' could not be converted into 'string?'\n" - "caused by:\n" - " Not all union options are compatible. Type 'number' could not be converted into 'string?'\n" - "caused by:\n" - " None of the union options are compatible. For example: Type 'number' could not be converted into 'string' in an invariant context" - ); - + LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ( - toString(result.errors[1]), - "Type '{| p: number?, q: string? |}' could not be converted into '{| p: string?, q: number? |}'\n" - "caused by:\n" - " Property 'q' is not compatible. Type 'string?' could not be converted into 'number?'\n" - "caused by:\n" - " Not all union options are compatible. Type 'string' could not be converted into 'number?'\n" - "caused by:\n" - " None of the union options are compatible. For example: Type 'string' could not be converted into 'number' in an invariant context" + R"(Type + '{ p: number?, q: any } & { p: unknown, q: string? }' +could not be converted into + '{ p: string?, q: number? }'; type { p: number?, q: any } & { p: unknown, q: string? }[0][read "p"] (number?) is not exactly { p: string?, q: number? }[read "p"][0] (string) + type { p: number?, q: any } & { p: unknown, q: string? }[0][read "p"][0] (number) is not exactly { p: string?, q: number? }[read "p"] (string?) + type { p: number?, q: any } & { p: unknown, q: string? }[0][read "q"] (any) is not exactly { p: string?, q: number? }[read "q"] (number?) + type { p: number?, q: any } & { p: unknown, q: string? }[1][read "p"] (unknown) is not exactly { p: string?, q: number? }[read "p"] (string?) + type { p: number?, q: any } & { p: unknown, q: string? }[1][read "q"] (string?) is not exactly { p: string?, q: number? }[read "q"][0] (number) + type { p: number?, q: any } & { p: unknown, q: string? }[1][read "q"][0] (string) is not exactly { p: string?, q: number? }[read "q"] (number?))", + toString(result.errors[0]) ); } else @@ -689,18 +678,42 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_functions_returning_intersections") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = (FFlag::DebugLuauDeferredConstraintResolution) ? - R"(Type + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ( + R"(Type + '((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })' +could not be converted into + '(nil) -> { p: number, q: number, r: number }'; type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[0].returns()[0][0] ({ p: number }) is not a subtype of (nil) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[0].returns()[0][1] ({ q: number }) is not a subtype of (nil) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[1].returns()[0][0] ({ p: number }) is not a subtype of (nil) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[1].returns()[0][1] ({ r: number }) is not a subtype of (nil) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }))", + toString(result.errors[0]) + ); + CHECK_EQ( + R"(Type '((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })' could not be converted into - '(number?) -> { p: number, q: number, r: number }'; none of the intersection parts are compatible)" - : - R"(Type + '(number?) -> { p: number, q: number, r: number }'; type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[0].returns()[0][0] ({ p: number }) is not a subtype of (number?) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[0].returns()[0][1] ({ q: number }) is not a subtype of (number?) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[1].arguments()[0] (string?) is not a supertype of (number?) -> { p: number, q: number, r: number }.arguments()[0][0] (number) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[1].returns()[0][0] ({ p: number }) is not a subtype of (number?) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }) + type ((number?) -> { p: number } & { q: number }) & ((string?) -> { p: number } & { r: number })[1].returns()[0][1] ({ r: number }) is not a subtype of (number?) -> { p: number, q: number, r: number }.returns()[0] ({ p: number, q: number, r: number }))", + toString(result.errors[1]) + ); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ( + R"(Type '((number?) -> {| p: number |} & {| q: number |}) & ((string?) -> {| p: number |} & {| r: number |})' could not be converted into - '(number?) -> {| p: number, q: number, r: number |}'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + '(number?) -> {| p: number, q: number, r: number |}'; none of the intersection parts are compatible)", + toString(result.errors[0]) + ); + } } TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generic") @@ -713,13 +726,19 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generic") end end )"); - - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_ERROR_COUNT(0, result); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '((number?) -> a | number) & ((string?) -> a | string)' could not be converted into '(number?) -> a'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generics") @@ -733,12 +752,20 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generics") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_NO_ERRORS(result); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '((a?) -> a | b) & ((c?) -> b | c)' could not be converted into '(a?) -> (a & c) | b'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generic_packs") @@ -751,19 +778,41 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_functions_mentioning_generic_packs") end end )"); - - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + CHECK_EQ( + R"(Type + '((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))' +could not be converted into + '(nil, a...) -> (nil, b...)'; type ((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))[0].returns()[0][0] (number) is not a subtype of (nil, a...) -> (nil, b...).returns()[0] (nil) + type ((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))[1].returns()[0][0] (string) is not a subtype of (nil, a...) -> (nil, b...).returns()[0] (nil))", + toString(result.errors[0]) + ); + CHECK_EQ( + R"(Type + '((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))' +could not be converted into + '(nil, b...) -> (nil, a...)'; type ((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))[0].returns()[0][0] (number) is not a subtype of (nil, b...) -> (nil, a...).returns()[0] (nil) + type ((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))[1].returns()[0][0] (string) is not a subtype of (nil, b...) -> (nil, a...).returns()[0] (nil))", + toString(result.errors[1]) + ); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '((number?, a...) -> (number?, b...)) & ((string?, a...) -> (string?, b...))' could not be converted into '(nil, b...) -> (nil, a...)'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_result") { ScopedFastFlag dcr{ - FFlag::DebugLuauDeferredConstraintResolution, false + FFlag::LuauSolverV2, false }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f() @@ -785,7 +834,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_arguments") { ScopedFastFlag dcr{ - FFlag::DebugLuauDeferredConstraintResolution, false + FFlag::LuauSolverV2, false }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f() @@ -815,7 +864,7 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_never_result") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ( @@ -858,18 +907,40 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_never_arguments") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); - const std::string expected = R"(Type + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_ERROR_COUNT(2, result); + const std::string expected1 = R"(Type + '((never) -> string?) & ((number) -> number?)' +could not be converted into + '(never) -> nil'; type ((never) -> string?) & ((number) -> number?)[0].returns()[0][0] (number) is not a subtype of (never) -> nil.returns()[0] (nil) + type ((never) -> string?) & ((number) -> number?)[1].returns()[0][0] (string) is not a subtype of (never) -> nil.returns()[0] (nil))"; + const std::string expected2 = R"(Type + '((never) -> string?) & ((number) -> number?)' +could not be converted into + '(number?) -> nil'; type ((never) -> string?) & ((number) -> number?)[0].arguments()[0] (number) is not a supertype of (number?) -> nil.arguments()[0][1] (nil) + type ((never) -> string?) & ((number) -> number?)[0].returns()[0][0] (number) is not a subtype of (number?) -> nil.returns()[0] (nil) + type ((never) -> string?) & ((number) -> number?)[1].arguments()[0] (never) is not a supertype of (number?) -> nil.arguments()[0][0] (number) + type ((never) -> string?) & ((number) -> number?)[1].arguments()[0] (never) is not a supertype of (number?) -> nil.arguments()[0][1] (nil) + type ((never) -> string?) & ((number) -> number?)[1].returns()[0][0] (string) is not a subtype of (number?) -> nil.returns()[0] (nil))"; + CHECK_EQ(expected1, toString(result.errors[0])); + CHECK_EQ(expected2, toString(result.errors[1])); + } + else + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + const std::string expected = R"(Type '((never) -> string?) & ((number) -> number?)' could not be converted into '(number?) -> nil'; none of the intersection parts are compatible)"; - CHECK_EQ(expected, toString(result.errors[0])); + CHECK_EQ(expected, toString(result.errors[0])); + } } TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_overlapping_results_and_variadics") { ScopedFastFlag dcr{ - FFlag::DebugLuauDeferredConstraintResolution, false + FFlag::LuauSolverV2, false }; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions CheckResult result = check(R"( function f(x : ((string?) -> (string | number)) & ((number?) -> ...number)) @@ -897,7 +968,7 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_1") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); } @@ -922,7 +993,7 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_2") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); } @@ -947,7 +1018,7 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_3") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); } @@ -974,7 +1045,7 @@ TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( R"(Type @@ -999,7 +1070,11 @@ could not be converted into TEST_CASE_FIXTURE(BuiltinsFixture, "intersect_metatables") { - if (FFlag::DebugLuauDeferredConstraintResolution) + // CLI-117121 - Intersection of types are not compatible with the equivalent alias + if (FFlag::LuauSolverV2) + return; + + if (FFlag::LuauSolverV2) { CheckResult result = check(R"( function f(a: string?, b: string?) @@ -1089,7 +1164,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "intersect_metatables_with_properties") TEST_CASE_FIXTURE(BuiltinsFixture, "intersect_metatable_with_table") { - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CheckResult result = check(R"( local x = setmetatable({ a = 5 }, { p = 5 }) @@ -1155,7 +1230,7 @@ TEST_CASE_FIXTURE(Fixture, "CLI-44817") TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_intersection_types") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1165,15 +1240,14 @@ TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_intersection_types") end )"); - LUAU_REQUIRE_NO_ERRORS(result); + LUAU_REQUIRE_ERROR_COUNT(3, result); - // TODO? We do not simplify types from explicit annotations. - CHECK_EQ("({| x: number |} & {| x: string |}) -> {| x: number |} & {| x: string |}", toString(requireType("f"))); + CHECK_EQ("(never) -> { x: number } & { x: string }", toString(requireType("f"))); } TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_intersection_types_2") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1219,7 +1293,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_property_table_intersection_2") TEST_CASE_FIXTURE(Fixture, "cli_80596_simplify_degenerate_intersections") { - ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag dcr{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type A = { @@ -1242,7 +1316,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_80596_simplify_degenerate_intersections") TEST_CASE_FIXTURE(Fixture, "cli_80596_simplify_more_realistic_intersections") { - ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag dcr{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type A = { diff --git a/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp index 98063d0f..de79654b 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.loops.test.cpp @@ -14,7 +14,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauOkWithIteratingOverTableProperties) LUAU_DYNAMIC_FASTFLAG(LuauImproveNonFunctionCallError) @@ -32,7 +32,7 @@ TEST_CASE_FIXTURE(Fixture, "for_loop") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // Luau cannot see that the loop must always run at least once, so we // think that q could be nil. @@ -45,10 +45,10 @@ TEST_CASE_FIXTURE(Fixture, "for_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_no_table_passed") { // This test may block CI if forced to run outside of DCR. - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type Iterable = typeof(setmetatable( @@ -72,7 +72,7 @@ for a, b in t do end TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_regression_issue_69967") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -93,7 +93,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_regression_issue_69967") TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_regression_issue_69967_alt") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -114,7 +114,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "iteration_regression_issue_69967_alt") )"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // It's possible for the loop body to execute 0 times. CHECK("number?" == toString(requireType("x"))); @@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("number?" == toString(requireType("n"))); CHECK("string?" == toString(requireType("s"))); @@ -155,7 +155,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next") { // CLI-116494 The generics K and V are leaking out of the next() function somehow. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local n @@ -222,7 +222,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_just_one_iterator_is_ok") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_zero_iterators_dcr") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function no_iter() end @@ -267,7 +267,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error") LUAU_REQUIRE_ERROR_COUNT(2, result); TypeId p = requireType("p"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("*error-type*?", toString(p)); else CHECK_EQ("*error-type*", toString(p)); @@ -276,7 +276,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error") TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") { // We report a spuriouus duplicate error here. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local bad_iter = 5 @@ -293,7 +293,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_the_right_amount_of_values") { // Spurious duplicate errors - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function hasDivisors(value: number, table) @@ -345,7 +345,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_t TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args_but_none_given") { // CLI-116496 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function prime_iter(state, index) @@ -419,7 +419,7 @@ TEST_CASE_FIXTURE(Fixture, "while_loop") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("number?" == toString(requireType("i"))); else CHECK_EQ(*builtinTypes->numberType, *requireType("i")); @@ -436,7 +436,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("string?" == toString(requireType("i"))); else CHECK_EQ(*builtinTypes->stringType, *requireType("i")); @@ -478,7 +478,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "varlist_declared_by_for_in_loop_should_be_fr end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); auto err = get(result.errors[0]); @@ -535,7 +535,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // In the new solver, we infer iter: unknown and so we warn on use of its properties. LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -585,7 +585,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("number?" == toString(requireType("key"))); else REQUIRE_EQ("number", toString(requireType("key"))); @@ -696,7 +696,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_typecheck_crash_on_empty_optional") { // CLI-116498 Sometimes you can iterate over tables with no indexers. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; ScopedFastFlag sff{FFlag::LuauOkWithIteratingOverTableProperties, true}; @@ -753,7 +753,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic") // The old solver just infers the wrong type here. // The right type for `key` is `number?` - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { TypeId keyTy = requireType("key"); CHECK("number?" == toString(keyTy)); @@ -765,7 +765,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic") TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil") { // CLI-116498 Sometimes you can iterate over tables with no indexers. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t: {string} = {} @@ -783,7 +783,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict") { // CLI-116498 Sometimes you can iterate over tables with no indexers. ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, {FFlag::LuauOkWithIteratingOverTableProperties, true} }; @@ -810,7 +810,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_nonstrict") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_nil") { // CLI-116499 Free types persisting until typechecking time. - if (1 || !FFlag::DebugLuauDeferredConstraintResolution) + if (1 || !FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -826,7 +826,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_nil") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_not_enough_returns") { // CLI-116500 - if (1 || !FFlag::DebugLuauDeferredConstraintResolution) + if (1 || !FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -848,7 +848,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_not_enough_returns") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok") { // CLI-116500 - if (1 || !FFlag::DebugLuauDeferredConstraintResolution) + if (1 || !FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -865,7 +865,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_metamethod_ok_with_inference") { // CLI-116500 - if (1 || !FFlag::DebugLuauDeferredConstraintResolution) + if (1 || !FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -916,7 +916,7 @@ TEST_CASE_FIXTURE(Fixture, "for_loop_lower_bound_is_string_3") TEST_CASE_FIXTURE(BuiltinsFixture, "cli_68448_iterators_need_not_accept_nil") { // CLI-116500 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1051,7 +1051,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_fragmented_keys") TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_xpath_candidates") { // CLI-116500 - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1071,7 +1071,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_xpath_candidates") TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1084,7 +1084,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("never?" == toString(requireType("ans"))); // CLI-114134 egraph simplification. Should just be nil. else CHECK(toString(requireType("ans")) == "never"); @@ -1093,7 +1093,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never") TEST_CASE_FIXTURE(BuiltinsFixture, "iterate_over_properties") { // CLI-116498 - Sometimes you can iterate over tables with no indexer. - ScopedFastFlag sff0{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff0{FFlag::LuauSolverV2, false}; ScopedFastFlag sff{FFlag::LuauOkWithIteratingOverTableProperties, true}; @@ -1151,7 +1151,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "pairs_should_not_retroactively_add_an_indexe print(prices.wwwww) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // We regress a little here: The old solver would typecheck the first // access to prices.wwwww on a table that had no indexer, and the second @@ -1186,7 +1186,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "iterate_array_of_singletons") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_ERRORS(result); @@ -1210,7 +1210,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "iter_mm_results_are_lvalue") TEST_CASE_FIXTURE(BuiltinsFixture, "forin_metatable_no_iter_mm") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local t = setmetatable({1, 2, 3}, {}) @@ -1228,7 +1228,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "forin_metatable_no_iter_mm") TEST_CASE_FIXTURE(BuiltinsFixture, "forin_metatable_iter_mm") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type Iterable = typeof(setmetatable({}, {} :: { diff --git a/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp index 6719f158..42f1229f 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.modules.test.cpp @@ -11,7 +11,7 @@ #include "doctest.h" LUAU_FASTFLAG(LuauInstantiateInSubtyping) -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) using namespace Luau; @@ -56,7 +56,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require") return {hooty=hooty} )"; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { fileResolver.source["game/B"] = R"( local Hooty = require(game.A) @@ -237,7 +237,7 @@ local tbl: string = require(game.A) CheckResult result = frontend.check("game/B"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("Type '{ def: number }' could not be converted into 'string'", toString(result.errors[0])); else CHECK_EQ("Type '{| def: number |}' could not be converted into 'string'", toString(result.errors[0])); @@ -424,7 +424,7 @@ local b: B.T = a CheckResult result = frontend.check("game/C"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Type 'T' could not be converted into 'T'; at [read \"x\"], number is not exactly string"); else { @@ -465,7 +465,7 @@ local b: B.T = a CheckResult result = frontend.check("game/D"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == "Type 'T' could not be converted into 'T'; at [read \"x\"], number is not exactly string"); else { diff --git a/Dependencies/luau/Luau/tests/TypeInfer.negations.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.negations.test.cpp index af73607a..a21751ec 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.negations.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.negations.test.cpp @@ -50,6 +50,9 @@ TEST_CASE_FIXTURE(NegationFixture, "string_is_not_a_subtype_of_negated_string") TEST_CASE_FIXTURE(Fixture, "cofinite_strings_can_be_compared_for_equality") { + // CLI-117082 Cofinite strings cannot be compared for equality because normalization produces a large type with cycles + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( function f(e) if e == 'strictEqual' then diff --git a/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp index 29935a08..3ccc04c1 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.oop.test.cpp @@ -12,14 +12,14 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("TypeInferOOP"); TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon") { // CLI-116571 method calls are missing arity checking? - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local someTable = {} @@ -37,7 +37,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defi TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2") { // CLI-116571 method calls are missing arity checking? - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local someTable = {} @@ -144,7 +144,7 @@ TEST_CASE_FIXTURE(Fixture, "inferring_hundreds_of_self_calls_should_not_suffocat )"); ModulePtr module = getMainModule(); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_GE(80, module->internalTypes.types.size()); else CHECK_GE(50, module->internalTypes.types.size()); @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "augmenting_an_unsealed_table_with_a_metatabl end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("{ @metatable { number: number }, { method: (unknown) -> string } }" == toString(requireType("B"), {true})); else CHECK("{ @metatable { number: number }, { method: (a) -> string } }" == toString(requireType("B"), {true})); @@ -505,7 +505,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "promise_type_error_too_complex" * doctest::t TEST_CASE_FIXTURE(Fixture, "method_should_not_create_cyclic_type") { - ScopedFastFlag sff(FFlag::DebugLuauDeferredConstraintResolution, true); + ScopedFastFlag sff(FFlag::LuauSolverV2, true); CheckResult result = check(R"( local Component = {} diff --git a/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp index e5514db0..d8bf9152 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.operators.test.cpp @@ -16,7 +16,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauRemoveBadRelationalOperatorWarning) TEST_SUITE_BEGIN("TypeInferOperators"); @@ -194,7 +194,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int CHECK("Vec3" == toString(requireType("c"))); CHECK("Vec3" == toString(requireType("d"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("mul" == toString(requireType("e"))); else CHECK_EQ("Vec3", toString(requireType("e"))); @@ -232,7 +232,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int CHECK("Vec3" == toString(requireType("c"))); CHECK("Vec3" == toString(requireType("d"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("mul" == toString(requireType("e"))); else CHECK_EQ("Vec3", toString(requireType("e"))); @@ -270,7 +270,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_m LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); @@ -300,7 +300,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_ LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); @@ -404,7 +404,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_result") s += 10 )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK_EQ(result.errors[0], (TypeError{Location{{2, 8}, {2, 9}}, TypeMismatch{builtinTypes->numberType, builtinTypes->stringType}})); @@ -441,7 +441,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_metatable") TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_metatable_with_changing_return_type") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( --!strict @@ -567,7 +567,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus") CHECK_EQ("string", toString(requireType("a"))); CHECK_EQ("number", toString(requireType("b"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); @@ -607,7 +607,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error") local a = -foo )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); @@ -631,7 +631,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error") TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error") { // CLI-116463 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -702,7 +702,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables LUAU_REQUIRE_ERROR_COUNT(3, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK(get(result.errors[0])); CHECK(Location{{2, 18}, {2, 30}} == result.errors[0].location); @@ -720,7 +720,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables GenericError* gen1 = get(result.errors[1]); REQUIRE(gen1); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(gen1->message, "Operator + is not applicable for '{ value: number }' and 'number' because neither type has a metatable"); else CHECK_EQ(gen1->message, "Binary operator '+' not supported by types 'foo' and 'number'"); @@ -753,7 +753,7 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_free_lhs_and_string_rhs") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK("(a) -> concat" == toString(requireType("f"))); @@ -775,7 +775,7 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_string_lhs_and_free_rhs") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(a) -> concat" == toString(requireType("f"))); else CHECK_EQ("(string) -> string", toString(requireType("f"))); @@ -794,7 +794,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown") CheckResult result = check(src); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(ops.size(), result); CHECK_EQ( @@ -821,7 +821,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "and_binexps_dont_unify") )"); // This infers a type for `t` of `{unknown}`, and so it makes sense that `t[1].test` would error. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_ERROR_COUNT(1, result); else LUAU_REQUIRE_NO_ERRORS(result); @@ -837,7 +837,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); @@ -860,7 +860,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato )"); // If DCR is off and the flag to remove this check in the old solver is on, the expected behavior is no errors. - if (!FFlag::DebugLuauDeferredConstraintResolution && FFlag::LuauRemoveBadRelationalOperatorWarning) + if (!FFlag::LuauSolverV2 && FFlag::LuauRemoveBadRelationalOperatorWarning) { LUAU_REQUIRE_NO_ERRORS(result); return; @@ -868,7 +868,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); @@ -885,7 +885,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union") { // There's an extra spurious warning here when the new solver is enabled. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -901,7 +901,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign") { // In non-strict mode, global definition is still allowed { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) { CheckResult result = check(R"( --!nonstrict @@ -928,7 +928,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign") // In non-strict mode, compound assignment is not a definition, it's a modification { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) { CheckResult result = check(R"( --!nonstrict @@ -1047,7 +1047,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> add"); @@ -1079,7 +1079,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_subtraction") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> sub"); @@ -1099,7 +1099,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_multiplication") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> mul"); @@ -1119,7 +1119,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_division") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> div"); @@ -1139,7 +1139,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_floor_division") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> idiv"); @@ -1159,7 +1159,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_exponentiation") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> pow"); @@ -1179,7 +1179,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_modulo") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> mod"); @@ -1199,7 +1199,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_for_generic_concat") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK(toString(requireType("f")) == "(a, b) -> concat"); @@ -1294,7 +1294,7 @@ TEST_CASE_FIXTURE(Fixture, "unrelated_primitives_cannot_be_compared") TEST_CASE_FIXTURE(BuiltinsFixture, "mm_comparisons_must_return_a_boolean") { // CLI-115687 - if (1 || !FFlag::DebugLuauDeferredConstraintResolution) + if (1 || !FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1341,12 +1341,12 @@ local w = c and 1 CHECK("number?" == toString(requireType("x"))); CHECK("number" == toString(requireType("y"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("false | number" == toString(requireType("z"))); else CHECK("boolean | number" == toString(requireType("z"))); // 'false' widened to boolean - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("number?" == toString(requireType("w"))); else CHECK("(boolean | number)?" == toString(requireType("w"))); @@ -1372,7 +1372,7 @@ local f1 = f or 'f' CHECK("number | string" == toString(requireType("a1"))); CHECK("number" == toString(requireType("b1"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("string | true" == toString(requireType("c1"))); CHECK("string | true" == toString(requireType("d1"))); @@ -1426,7 +1426,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array_simplified") TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array") { // CLI-116480 Subtyping bug: table should probably be a subtype of {[unknown]: unknown} - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -1524,7 +1524,7 @@ return startsWith TEST_CASE_FIXTURE(Fixture, "add_type_function_works") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1584,7 +1584,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "compare_singleton_string_to_string") TEST_CASE_FIXTURE(BuiltinsFixture, "no_infinite_expansion_of_free_type" * doctest::timeout(1.0)) { - ScopedFastFlag sff(FFlag::DebugLuauDeferredConstraintResolution, true); + ScopedFastFlag sff(FFlag::LuauSolverV2, true); check(R"( local tooltip = {} diff --git a/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp index 0f6d6132..c3cce9df 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.primitives.test.cpp @@ -84,7 +84,7 @@ TEST_CASE_FIXTURE(Fixture, "check_methods_of_number") LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("Expected type table, got 'number' instead" == toString(result.errors[0])); CHECK("Type 'number' could not be converted into 'string'" == toString(result.errors[1])); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp index 9107c6f4..514c31c8 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.provisional.test.cpp @@ -10,7 +10,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTINT(LuauNormalizeCacheLimit); LUAU_FASTINT(LuauTarjanChildLimit); LUAU_FASTINT(LuauTypeInferIterationLimit); @@ -65,7 +65,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete") end )"; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(expectedWithNewSolver, decorateWithTypes(code)); else CHECK_EQ(expected, decorateWithTypes(code)); @@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete") TEST_CASE_FIXTURE(BuiltinsFixture, "luau-polyfill.Array.filter") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; // This test exercises the fact that we should reduce sealed/unsealed/free tables // res is a unsealed table with type {((T & ~nil)?) & any} @@ -172,7 +172,7 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size") // For now, infer it as just a free table. TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_table") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a = {} @@ -192,7 +192,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_ // Luau currently doesn't yet know how to allow assignments when the binding was refined. TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Node = { value: T, child: Node? } @@ -217,7 +217,7 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined") // We should be type checking the metamethod at the call site of setmetatable. TEST_CASE_FIXTURE(BuiltinsFixture, "error_on_eq_metamethod_returning_a_type_other_than_boolean") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local tab = {a = 1} @@ -277,7 +277,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("{ x: string, y: number }", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ("{ x: nil, y: nil }", toString(requireTypeAtPosition({7, 28}))); @@ -359,7 +359,7 @@ TEST_CASE_FIXTURE(Fixture, "do_not_ice_when_trying_to_pick_first_of_generic_type LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("() -> ()" == toString(requireType("f"))); CHECK("() -> ()" == toString(requireType("g"))); @@ -382,7 +382,7 @@ TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early") local s2s: (string) -> string = id )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_ERRORS(result); // Should not have any errors. @@ -393,7 +393,7 @@ TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_type_pack") ScopedFastFlag sff[] = { // I'm not sure why this is broken without DCR, but it seems to be fixed // when DCR is enabled. - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; CheckResult result = check(R"( @@ -477,7 +477,7 @@ TEST_CASE_FIXTURE(Fixture, "free_is_not_bound_to_any") TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; CheckResult result = check(R"( @@ -509,7 +509,7 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") // to be solved later. This should be faster and theoretically less prone // to cyclic constraint dependencies. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(unknown, number) -> ()" == toString(requireType("prime_iter"))); else CHECK("(a, number) -> ()" == toString(requireType("prime_iter"))); @@ -517,7 +517,7 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; TypeArena arena; TypeId nilType = builtinTypes->nilType; @@ -535,7 +535,7 @@ TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together") Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; Unifier u{NotNull{&normalizer}, NotNull{scope.get()}, Location{}, Variance::Covariant}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) u.enableNewSolver(); u.tryUnify(option1, option2); @@ -553,7 +553,7 @@ TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_zero_iterators") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function no_iter() end @@ -600,7 +600,7 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->returnType); REQUIRE(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("unknown", toString(*result)); else CHECK_MESSAGE(get(*result), *result); @@ -643,7 +643,7 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->returnType); REQUIRE(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("unknown" == toString(*result)); else CHECK("any" == toString(*result)); @@ -829,7 +829,7 @@ TEST_CASE_FIXTURE(Fixture, "assign_table_with_refined_property_with_a_similar_ty end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); // This is wrong. We should be rejecting this assignment. else { @@ -847,7 +847,7 @@ Type 'number?' could not be converted into 'number' in an invariant context)"; TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function foo(t, x) @@ -864,7 +864,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{string}", toString(requireType("t"))); else { @@ -904,7 +904,7 @@ TEST_CASE_FIXTURE(Fixture, "expected_type_should_be_a_helpful_deduction_guide_fo local x: Ref = useRef(nil) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // This bug is fixed in the new solver. LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -921,7 +921,7 @@ TEST_CASE_FIXTURE(Fixture, "expected_type_should_be_a_helpful_deduction_guide_fo TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local assign : (target: T, source0: U?, source1: V?, source2: W?, ...any) -> T & U & V & W = (nil :: any) @@ -945,7 +945,7 @@ TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed") TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; TypeArena arena; TypeId nilType = builtinTypes->nilType; @@ -963,7 +963,7 @@ TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together") Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; Unifier u{NotNull{&normalizer}, NotNull{scope.get()}, Location{}, Variance::Covariant}; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) u.enableNewSolver(); u.tryUnify(option1, option2); @@ -992,7 +992,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_more_complex_unions_that_include_nil") TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_old_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; createSomeClasses(&frontend); @@ -1010,7 +1010,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_old_solver") TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_new_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; createSomeClasses(&frontend); @@ -1076,7 +1076,7 @@ end TEST_CASE_FIXTURE(BuiltinsFixture, "table_unification_infinite_recursion") { // The new solver doesn't recurse as heavily in this situation. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; #if defined(_NOOPT) || defined(_DEBUG) ScopedFastInt LuauTypeInferRecursionLimit{FInt::LuauTypeInferRecursionLimit, 100}; @@ -1113,7 +1113,7 @@ tbl:f3() TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_limit_in_unify_with_any") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; // With default limit, this test will take 10 seconds in NoOpt @@ -1148,7 +1148,7 @@ foo(1 :: any) TEST_CASE_FIXTURE(Fixture, "luau_roact_useState_nilable_state_1") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type Dispatch = (A) -> () @@ -1173,7 +1173,7 @@ TEST_CASE_FIXTURE(Fixture, "luau_roact_useState_nilable_state_1") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else { @@ -1189,7 +1189,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_roact_useState_minimization") { // We don't expect this test to work on the old solver, but it also does not yet work on the new solver. // So, we can't just put a scoped fast flag here, or it would block CI. - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -1307,12 +1307,10 @@ TEST_CASE_FIXTURE(Fixture, "we_cannot_infer_functions_that_return_inconsistently #else // This is what actually happens right now. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_CHECK_ERROR_COUNT(2, result); - - // The second argument should be unknown. CLI-111111 - CHECK("({T}, 'b) -> number" == toString(requireType("find_first"))); + CHECK("({T}, unknown) -> number" == toString(requireType("find_first"))); } else { diff --git a/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp index 37c5e8d2..9c26f165 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.refinements.test.cpp @@ -7,7 +7,7 @@ #include "doctest.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) using namespace Luau; @@ -255,7 +255,7 @@ TEST_CASE_FIXTURE(Fixture, "a_and_b_or_a_and_c") CHECK_EQ("string", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28}))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("boolean", toString(requireTypeAtPosition({5, 28}))); else CHECK_EQ("true", toString(requireTypeAtPosition({5, 28}))); // oh no! :( @@ -278,7 +278,7 @@ TEST_CASE_FIXTURE(Fixture, "type_assertion_expr_carry_its_constraints") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("number?", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("string?", toString(requireTypeAtPosition({4, 26}))); @@ -307,7 +307,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_if_condition_position") LUAU_REQUIRE_NO_ERRORS(result); // DCR changes refinements to preserve error suppression. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("*error-type* | number", toString(requireTypeAtPosition({3, 26}))); else CHECK_EQ("number", toString(requireTypeAtPosition({3, 26}))); @@ -326,7 +326,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_assert_position") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(a) -> a & number" == toString(requireType("f"))); else CHECK("(a) -> number" == toString(requireType("f"))); @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_test_a_prop") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else { @@ -376,7 +376,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_test_a_nested_p end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); const UnknownProperty* up = get(result.errors[0]); @@ -410,7 +410,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_test_a_tested_n end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else { @@ -486,7 +486,7 @@ TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 - Types produced by refinements don't always get simplified CHECK("{ x: number? } & { x: ~(false?) }" == toString(requireTypeAtPosition({4, 23}))); @@ -573,7 +573,7 @@ TEST_CASE_FIXTURE(Fixture, "term_is_equal_to_an_lvalue") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ(toString(requireTypeAtPosition({3, 28})), R"("hello")"); // a == "hello" CHECK_EQ(toString(requireTypeAtPosition({5, 28})), R"(((string & ~"hello") | number)?)"); // a ~= "hello" @@ -600,7 +600,7 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil") LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ(toString(requireTypeAtPosition({3, 28})), "number | string"); // a ~= nil - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "nil"); // a == nil :) else CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(number | string)?"); // a == nil @@ -618,7 +618,7 @@ TEST_CASE_FIXTURE(Fixture, "free_type_is_equal_to_an_lvalue") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "unknown"); // a == b else CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "a"); // a == b @@ -639,7 +639,7 @@ TEST_CASE_FIXTURE(Fixture, "unknown_lvalue_is_not_synonymous_with_other_on_not_e LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "any"); // a ~= b - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "{ x: number }?"); // a ~= b else CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "{| x: number |}?"); // a ~= b @@ -664,7 +664,7 @@ TEST_CASE_FIXTURE(Fixture, "string_not_equal_to_string_or_nil") CHECK_EQ(toString(requireTypeAtPosition({6, 29})), "string"); // a ~= b CHECK_EQ(toString(requireTypeAtPosition({6, 32})), "string?"); // a ~= b - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ(toString(requireTypeAtPosition({8, 29})), "string?"); // a == b CHECK_EQ(toString(requireTypeAtPosition({8, 32})), "string?"); // a == b @@ -703,7 +703,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_narrow_to_vector") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("never", toString(requireTypeAtPosition({3, 28}))); else CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28}))); @@ -729,7 +729,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "nonoptional_type_can_narrow_to_nil_if_sense_ LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 Types produced by refinements do not consistently get simplified CHECK_EQ("(nil & string)?", toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil" @@ -780,7 +780,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_narrows_for_table") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ x: number } | { y: boolean }", toString(requireTypeAtPosition({3, 28}))); // type(x) == "table" else CHECK_EQ("{| x: number |} | {| y: boolean |}", toString(requireTypeAtPosition({3, 28}))); // type(x) == "table" @@ -822,7 +822,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_can_filter_for_intersection_of_ta ToStringOptions opts; opts.exhaustive = true; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ x: number } & { y: number }", toString(requireTypeAtPosition({4, 28}), opts)); else CHECK_EQ("{| x: number |} & {| y: number |}", toString(requireTypeAtPosition({4, 28}), opts)); @@ -863,7 +863,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 Types produced by refinements do not consistently get simplified CHECK_EQ("{ x: number } & ~table", toString(requireTypeAtPosition({3, 28}))); @@ -955,7 +955,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "either_number_or_string") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("*error-type* | number | string", toString(requireTypeAtPosition({3, 28}))); else CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 28}))); @@ -974,7 +974,7 @@ TEST_CASE_FIXTURE(Fixture, "not_t_or_some_prop_of_t") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 Types produced by refinements do not consistently get simplified CHECK_EQ("({ x: boolean } & { x: ~(false?) })?", toString(requireTypeAtPosition({3, 28}))); @@ -1082,7 +1082,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_comparison_ifelse_expression") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("*error-type* | number", toString(requireTypeAtPosition({6, 49}))); CHECK_EQ("*error-type* | ~number", toString(requireTypeAtPosition({6, 66}))); @@ -1094,7 +1094,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_comparison_ifelse_expression") } CHECK_EQ("number", toString(requireTypeAtPosition({10, 49}))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("~number", toString(requireTypeAtPosition({10, 66}))); else CHECK_EQ("unknown", toString(requireTypeAtPosition({10, 66}))); @@ -1224,7 +1224,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 Types produced by refinements do not consistently get simplified CHECK("{ tag: \"exists\", x: string } & { x: ~(false?) }" == toString(requireTypeAtPosition({5, 28}))); @@ -1360,7 +1360,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK(R"({ tag: "Part", x: Part })" == toString(requireTypeAtPosition({5, 28}))); CHECK(R"({ tag: "Folder", x: Folder })" == toString(requireTypeAtPosition({7, 28}))); @@ -1375,7 +1375,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x") TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector") { // CLI-115286 - Refining via type(x) == 'vector' does not work in the new solver - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function f(vec) @@ -1450,7 +1450,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "type_narrow_but_the_discriminant_type LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("never", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Instance | Vector3 | number | string", toString(requireTypeAtPosition({5, 28}))); @@ -1500,6 +1500,9 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "narrow_from_subclasses_of_instance_or TEST_CASE_FIXTURE(RefinementClassFixture, "x_as_any_if_x_is_instance_elseif_x_is_table") { + // CLI-117136 - this code doesn't finish constraint solving and has blocked types in the output + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( --!nonstrict @@ -1514,7 +1517,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "x_as_any_if_x_is_instance_elseif_x_is LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("Folder & Instance & {- -}", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ("(~Folder | ~Instance) & {- -} & never", toString(requireTypeAtPosition({7, 28}))); @@ -1566,7 +1569,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "isa_type_refinement_must_be_known_ahe { // CLI-115087 - The new solver does not consistently combine tables with // class types when they appear in the upper bounds of a free type. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function f(x): Instance @@ -1588,6 +1591,9 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "isa_type_refinement_must_be_known_ahe TEST_CASE_FIXTURE(RefinementClassFixture, "x_is_not_instance_or_else_not_part") { + // CLI-117135 - RefinementTests.x_is_not_instance_or_else_not_part not correctly applying refinements to a function parameter + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( local function f(x: Part | Folder | string) if typeof(x) ~= "Instance" or not x:IsA("Part") then @@ -1635,7 +1641,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknowns") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("string", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("~string", toString(requireTypeAtPosition({5, 28}))); @@ -1773,7 +1779,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_take_the_length end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ("table", toString(requireTypeAtPosition({3, 29}))); @@ -1795,7 +1801,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_clone_it") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); } @@ -1807,6 +1813,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table_then_clone_it") TEST_CASE_FIXTURE(RefinementClassFixture, "refine_a_param_that_got_resolved_during_constraint_solving_stage") { + // CLI-117134 - Applying a refinement causes an optional value access error. + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( type Id = T @@ -1840,7 +1849,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "refine_a_param_that_got_resolved_duri LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ("Part", toString(requireTypeAtPosition({5, 28}))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("Instance & ~Part", toString(requireTypeAtPosition({7, 28}))); else CHECK_EQ("Instance", toString(requireTypeAtPosition({7, 28}))); @@ -1856,7 +1865,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_a_property_of_some_global") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(3, result); @@ -1899,7 +1908,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dataflow_analysis_can_tell_refinements_when_ CHECK_EQ("nil", toString(requireTypeAtPosition({12, 28}))); CHECK_EQ("string", toString(requireTypeAtPosition({14, 28}))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115281 - Types produced by refinements don't always get simplified CHECK_EQ("nil & string", toString(requireTypeAtPosition({18, 28}))); @@ -1989,7 +1998,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_annotations_arent_relevant_when_doing_d LUAU_REQUIRE_NO_ERRORS(result); CHECK_EQ("nil", toString(requireTypeAtPosition({8, 28}))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115478 - This should be never CHECK_EQ("nil", toString(requireTypeAtPosition({9, 28}))); @@ -2000,7 +2009,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_annotations_arent_relevant_when_doing_d TEST_CASE_FIXTURE(BuiltinsFixture, "function_call_with_colon_after_refining_not_to_be_nil") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( --!strict @@ -2040,7 +2049,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinements_should_preserve_error_suppressio end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_NO_ERRORS(result); @@ -2066,7 +2075,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "many_refinements_on_val") TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; // this test is DCR-only as an instance of DCR fixing a bug in the old solver CheckResult result = check(R"( @@ -2088,7 +2097,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknown_to_table") TEST_CASE_FIXTURE(BuiltinsFixture, "conditional_refinement_should_stay_error_suppressing") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function test(element: any?) @@ -2109,7 +2118,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "globals_can_be_narrowed_too") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114134 CHECK("string & typeof(string)" == toString(requireTypeAtPosition(Position{2, 24}))); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp index bec9d953..43b1305e 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.singletons.test.cpp @@ -6,7 +6,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("TypeSingletons"); @@ -46,7 +46,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singletons") TEST_CASE_FIXTURE(Fixture, "string_singleton_function_call") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons") TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(g: ((true, string) -> ()) & ((false, number) -> ())) @@ -162,7 +162,7 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch") )"); LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("None of the overloads for function that accept 2 arguments are compatible.", toString(result.errors[0])); CHECK_EQ("Available overloads: (true, string) -> (); and (false, number) -> ()", toString(result.errors[1])); @@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'" == toString(result.errors[0])); else CHECK_EQ( @@ -256,7 +256,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag") LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CannotAssignToNever* tm = get(result.errors[0]); REQUIRE(tm); @@ -343,7 +343,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( "Type\n" " '{ [\"\\n\"]: number }'\n" @@ -368,7 +368,7 @@ local a: Animal = { tag = 'cat', cafood = 'something' } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Type '{ cafood: string, tag: \"cat\" }' could not be converted into 'Cat | Dog'" == toString(result.errors[0])); else { @@ -391,7 +391,7 @@ local a: Result = { success = false, result = 'something' } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Type '{ result: string, success: boolean }' could not be converted into 'Bad | Good'" == toString(result.errors[0])); else { @@ -406,7 +406,7 @@ Table type 'a' not compatible with type 'Bad' because the former is missing fiel TEST_CASE_FIXTURE(Fixture, "parametric_tagged_union_alias") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; CheckResult result = check(R"( type Ok = {success: true, result: T} @@ -442,7 +442,7 @@ local a: Animal = if true then { tag = 'cat', catfood = 'something' } else { tag TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_singleton") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function foo(f, x) @@ -462,7 +462,7 @@ TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_si TEST_CASE_FIXTURE(Fixture, "return_type_of_f_is_not_widened") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function foo(f, x): "hello"? -- anyone there? @@ -488,7 +488,7 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(R"("foo")", toString(requireType("copy"))); else CHECK_EQ("string", toString(requireType("copy"))); @@ -613,7 +613,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "singletons_stick_around_under_assignment") print(kind == "Bar") -- type of equality refines to `false` )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_ERROR_COUNT(1, result); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp index 6256ede6..9d76e7bd 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.tables.test.cpp @@ -15,9 +15,10 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); -LUAU_FASTFLAG(LuauInstantiateInSubtyping); -LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering); +LUAU_FASTFLAG(LuauSolverV2) +LUAU_FASTFLAG(LuauInstantiateInSubtyping) +LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering) +LUAU_FASTFLAG(LuauAcceptIndexingTableUnionsIntersections) LUAU_DYNAMIC_FASTFLAG(LuauImproveNonFunctionCallError) @@ -25,7 +26,7 @@ TEST_SUITE_BEGIN("TableTests"); TEST_CASE_FIXTURE(BuiltinsFixture, "generalization_shouldnt_seal_table_in_len_function_fn") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( local t = {} @@ -135,7 +136,7 @@ TEST_CASE_FIXTURE(Fixture, "index_expression_is_checked_against_the_indexer_type )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_MESSAGE(get(result.errors[0]), "Expected CannotExtendTable but got " << toString(result.errors[0])); else CHECK(get(result.errors[0])); @@ -162,7 +163,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_augment_sealed_table") // TODO: better, more robust comparison of type vars auto s = toString(error->tableType, ToStringOptions{/*exhaustive*/ true}); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(s, "{ prop: number }"); else CHECK_EQ(s, "{| prop: number |}"); @@ -317,7 +318,7 @@ TEST_CASE_FIXTURE(Fixture, "call_method_with_explicit_self_argument") TEST_CASE_FIXTURE(Fixture, "used_dot_instead_of_colon") { // CLI-114792 Dot vs colon warnings aren't in the new solver yet. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local T = {} @@ -370,7 +371,7 @@ TEST_CASE_FIXTURE(Fixture, "used_dot_instead_of_colon_but_correctly") TEST_CASE_FIXTURE(Fixture, "used_colon_instead_of_dot") { // CLI-114792 Dot vs colon warnings aren't in the new solver yet. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local T = {} @@ -395,7 +396,7 @@ TEST_CASE_FIXTURE(Fixture, "used_colon_instead_of_dot") TEST_CASE_FIXTURE(Fixture, "open_table_unification_2") { // CLI-114792 We don't report MissingProperties in many places where the old solver does. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a = {} @@ -479,7 +480,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_param_width_subtyping_2") LUAU_REQUIRE_ERROR_COUNT(1, result); // CLI 114792 We don't report MissingProperties in many places where the old solver does - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { TypeMismatch* error = get(result.errors[0]); REQUIRE_MESSAGE(error != nullptr, "Expected TypeMismatch but got " << toString(result.errors[0])); @@ -512,7 +513,7 @@ TEST_CASE_FIXTURE(Fixture, "table_param_width_subtyping_3") CHECK(result.errors[0].location == Location{Position{6, 8}, Position{6, 9}}); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors[0]) == "Type 'T' could not be converted into '{ read baz: unknown }'"); else { @@ -535,7 +536,7 @@ TEST_CASE_FIXTURE(Fixture, "table_param_width_subtyping_3") TEST_CASE_FIXTURE(Fixture, "table_unification_4") { // CLI-114134 - Use egraphs to simplify types better. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function foo(o) @@ -566,7 +567,7 @@ TEST_CASE_FIXTURE(Fixture, "ok_to_add_property_to_free_table") TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_assignment") { // CLI-114872 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -585,7 +586,7 @@ TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_assignmen TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_function_call") { // CLI-114873 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -690,7 +691,7 @@ TEST_CASE_FIXTURE(Fixture, "indexers_get_quantified_too") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("({unknown}) -> ()" == toString(requireType("swap"))); else { @@ -762,7 +763,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_array_like_table") CHECK_EQ(*builtinTypes->numberType, *indexer.indexType); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114134 - Use egraphs to simplify types CHECK("string | string | string" == toString(indexer.indexResultType)); @@ -801,7 +802,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_value_property_in_literal") CHECK(bool(retType->indexer)); const TableIndexer& indexer = *retType->indexer; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ __name: string }", toString(indexer.indexType)); else CHECK_EQ("{| __name: string |}", toString(indexer.indexType)); @@ -810,7 +811,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_value_property_in_literal") TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_its_variable_type_and_unifiable") { // This code is totally different in the new solver. We instead create a new type state for t2. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t1: { [string]: string } = {} @@ -850,7 +851,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_mismatch") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm != nullptr); CHECK(toString(tm->wantedType) == "{number}"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(tm->givenType) == "{ [string]: string }"); else CHECK(toString(tm->givenType) == "{| [string]: string |}"); @@ -892,7 +893,7 @@ TEST_CASE_FIXTURE(Fixture, "sealed_table_value_can_infer_an_indexer") TEST_CASE_FIXTURE(Fixture, "array_factory_function") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function empty() return {} end @@ -912,7 +913,7 @@ TEST_CASE_FIXTURE(Fixture, "sealed_table_indexers_must_unify") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114879 - Error path reporting is not great CHECK( @@ -929,7 +930,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_on_sealed_table_must_unify_with_free_table") // CLI-114134 What should be happening here is that the type of `t` should // be reduced from `{number} & {string}` to `never`, but that's not // happening. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function F(t): {number} @@ -992,7 +993,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "indexing_from_a_table_should_prefer_properti TEST_CASE_FIXTURE(Fixture, "any_when_indexing_into_an_unsealed_table_with_no_indexer_in_nonstrict_mode") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -1029,7 +1030,7 @@ TEST_CASE_FIXTURE(Fixture, "disallow_indexing_into_an_unsealed_table_with_no_ind local k1 = getConstant("key1") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("unknown" == toString(requireType("k1"))); else CHECK("any" == toString(requireType("k1"))); @@ -1144,7 +1145,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_inferred") TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type VectorMt = { __add: (Vector, number) -> Vector } @@ -1164,7 +1165,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways") TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways_lti") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local vectorMt = {} @@ -1522,7 +1523,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "found_multiple_like_keys") TEST_CASE_FIXTURE(BuiltinsFixture, "dont_suggest_exact_match_keys") { // CLI-114977 Unsealed table writes don't account for order properly - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t = {} @@ -1565,7 +1566,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "getmetatable_returns_pointer_to_metatable") TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_mismatch_should_fail") { // This test is invalid because we now create a new type state for t1 at the assignment. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t1 = {x = 1} @@ -1609,7 +1610,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "property_lookup_through_tabletypevar_metatab TEST_CASE_FIXTURE(BuiltinsFixture, "missing_metatable_for_sealed_tables_do_not_get_inferred") { // This test is invalid because we now create a new type state for t at the assignment. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local t = {x = 1} @@ -1664,7 +1665,7 @@ TEST_CASE_FIXTURE(Fixture, "right_table_missing_key") TEST_CASE_FIXTURE(Fixture, "right_table_missing_key2") { // CLI-114792 We don't report MissingProperties - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(t: {}): { [string]: string, a: string } @@ -1697,7 +1698,7 @@ TEST_CASE_FIXTURE(Fixture, "casting_unsealed_tables_with_props_into_table_with_i TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("{ [string]: string }", toString(tm->wantedType, o)); CHECK_EQ("{ [string]: number }", toString(tm->givenType, o)); @@ -1725,7 +1726,7 @@ TEST_CASE_FIXTURE(Fixture, "casting_sealed_tables_with_props_into_table_with_ind ToStringOptions o{/* exhaustive= */ true}; TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("{ [string]: string }", toString(tm->wantedType, o)); CHECK_EQ("{ foo: number }", toString(tm->givenType, o)); @@ -1760,7 +1761,7 @@ TEST_CASE_FIXTURE(Fixture, "casting_tables_with_props_into_table_with_indexer3") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("string" == toString(tm->wantedType)); CHECK("number" == toString(tm->givenType)); @@ -1795,7 +1796,7 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_missing_props_dont_report_multi LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( "Type pack '{ x: number }' could not be converted into '{ x: number, y: number, z: number }';" @@ -1824,7 +1825,7 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_missing_props_dont_report_multi local t: MixedTable = {"fail"} )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -1863,7 +1864,7 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_extra_props_dont_report_multipl TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("{{ x: number }}", toString(tm->wantedType)); CHECK_EQ("{{ x: number, y: number, z: number }}", toString(tm->givenType)); @@ -1901,7 +1902,7 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_on_massive_table_is_cut_short") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("{ a: number, b: number, c: number, d: number, e: number, ... 1 more ... }" == toString(requireType("t"))); CHECK_EQ("number", toString(tm->givenType)); @@ -1926,7 +1927,7 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_on_massive_table_is_cut_short") TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_even_on_non_lvalue_base_expr") { // CLI-100076 Assigning nil to an indexer should always succeed - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function f(): { [string]: number } @@ -1948,7 +1949,7 @@ TEST_CASE_FIXTURE(Fixture, "ok_to_provide_a_subtype_during_construction") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114134 Use egraphs to simplify types more consistently CHECK("{number | number | string}" == toString(requireType("t"), {/*exhaustive*/ true})); @@ -1968,7 +1969,7 @@ TEST_CASE_FIXTURE(Fixture, "reasonable_error_when_adding_a_nonexistent_property_ LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CannotExtendTable* cet = get(result.errors[0]); REQUIRE_MESSAGE(cet, "Expected CannotExtendTable but got " << result.errors[0]); @@ -2012,7 +2013,7 @@ TEST_CASE_FIXTURE(Fixture, "only_ascribe_synthetic_names_at_module_scope") CHECK_EQ("TopLevel", toString(requireType("TopLevel"))); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{number}?", toString(requireType("foo"))); else CHECK_EQ("{number}", toString(requireType("foo"))); @@ -2036,7 +2037,7 @@ TEST_CASE_FIXTURE(Fixture, "hide_table_error_properties") LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("Cannot add property 'a' to table '{ x: number }'", toString(result.errors[0])); CHECK_EQ("Cannot add property 'b' to table '{ x: number }'", toString(result.errors[1])); @@ -2095,7 +2096,7 @@ local Test: {Table} = { TEST_CASE_FIXTURE(Fixture, "common_table_element_general") { // CLI-115275 - Bidirectional inference does not always propagate indexer types into the expression - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Table = { @@ -2217,7 +2218,7 @@ foo({ TEST_CASE_FIXTURE(Fixture, "common_table_element_union_in_call_tail") { // CLI-115239 - Bidirectional checking does not work for __call metamethods - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Foo = {x: number | string} @@ -2264,7 +2265,7 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table local c : string = t.m("hi") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(2, result); @@ -2319,7 +2320,7 @@ local b: B = a LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == R"(Type 'A' could not be converted into 'B'; at [read "y"], number is not exactly string)"); else { @@ -2346,7 +2347,7 @@ local b: B = a LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors.at(0)) == R"(Type 'A' could not be converted into 'B'; at [read "b"][read "y"], number is not exactly string)"); else { @@ -2395,7 +2396,7 @@ Type could not be converted into '(a) -> ()'; different number of generic type parameters)"; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // The assignment of c2 to b2 is, surprisingly, allowed under the new // solver for two reasons: @@ -2460,7 +2461,7 @@ TEST_CASE_FIXTURE(Fixture, "error_detailed_indexer_key") LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("Type 'A' could not be converted into 'B'; at indexer(), number is not exactly string" == toString(result.errors[0])); } @@ -2486,7 +2487,7 @@ TEST_CASE_FIXTURE(Fixture, "error_detailed_indexer_value") LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("Type 'A' could not be converted into 'B'; at indexResult(), number is not exactly string" == toString(result.errors[0])); } @@ -2503,7 +2504,7 @@ Type 'number' could not be converted into 'string' in an invariant context)"; TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table") { // Table properties like HasSuper.p must be invariant. The new solver rightly rejects this program. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -2535,7 +2536,7 @@ local y: number = tmp.p.y LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( "Type 'tmp' could not be converted into 'HasSuper'; at [read \"p\"], { x: number, y: number } is not exactly Super" == toString(result.errors[0]) @@ -2553,7 +2554,7 @@ Table type '{ x: number, y: number }' not compatible with type 'Super' because t TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer") { // CLI-114791 Bidirectional inference should be able to cause the inference engine to forget that a table literal has some property - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -2571,7 +2572,7 @@ TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer") TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_metatable_type_call") { // CLI-114782 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local b @@ -2703,7 +2704,7 @@ TEST_CASE_FIXTURE(Fixture, "confusing_indexing") local foo = f({p = "string"}) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114781 Bidirectional checking can't see through the intersection LUAU_REQUIRE_ERROR_COUNT(1, result); @@ -2729,7 +2730,7 @@ TEST_CASE_FIXTURE(Fixture, "pass_a_union_of_tables_to_a_function_that_requires_a LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) REQUIRE_EQ("{ y: number }", toString(requireType("b"))); else REQUIRE_EQ("{- y: number -}", toString(requireType("b"))); @@ -2750,7 +2751,7 @@ TEST_CASE_FIXTURE(Fixture, "pass_a_union_of_tables_to_a_function_that_requires_a LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) REQUIRE_EQ("{ y: number }", toString(requireType("b"))); else REQUIRE_EQ("{- y: number -}", toString(requireType("b"))); @@ -2826,7 +2827,7 @@ TEST_CASE_FIXTURE(Fixture, "table_length") TEST_CASE_FIXTURE(Fixture, "nil_assign_doesnt_hit_indexer") { // CLI-100076 - Assigning a table key to `nil` in the presence of an indexer should always be permitted - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check("local a = {} a[0] = 7 a[0] = nil"); LUAU_REQUIRE_ERROR_COUNT(0, result); @@ -2932,7 +2933,7 @@ TEST_CASE_FIXTURE(Fixture, "tables_get_names_from_their_locals") TEST_CASE_FIXTURE(Fixture, "should_not_unblock_table_type_twice") { // don't run this when the DCR flag isn't set - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; check(R"( @@ -2972,7 +2973,7 @@ TEST_CASE_FIXTURE(Fixture, "generalize_table_argument") const TableType* fooArg1Table = get(follow(*fooArg1)); REQUIRE(fooArg1Table); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(fooArg1Table->state, TableState::Sealed); else CHECK_EQ(fooArg1Table->state, TableState::Generic); @@ -3058,7 +3059,7 @@ TEST_CASE_FIXTURE(Fixture, "inferring_crazy_table_should_also_be_quick") )"); ModulePtr module = getMainModule(); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_GE(500, module->internalTypes.types.size()); else CHECK_GE(100, module->internalTypes.types.size()); @@ -3118,7 +3119,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_crash_when_setmetatable_does_not_produc { CheckResult result = check("local x = setmetatable({})"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-114665: Generic parameters should not also be optional. LUAU_REQUIRE_NO_ERRORS(result); @@ -3223,7 +3224,7 @@ local baz = foo[bar] TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_basic") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -3238,7 +3239,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_basic") local foo = a(12) )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK(get(result.errors[0])); @@ -3260,7 +3261,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_must_be_callable") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { if (DFFlag::LuauImproveNonFunctionCallError) CHECK("Cannot call a value of type a" == toString(result.errors[0])); @@ -3299,7 +3300,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_generic") TEST_CASE_FIXTURE(BuiltinsFixture, "table_simple_call") { // The new solver can see that this function is safe to oversaturate. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a = setmetatable({ x = 2 }, { @@ -3333,7 +3334,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "access_index_metamethod_that_returns_variadi ToStringOptions o; o.exhaustive = true; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ x: string }", toString(requireType("foo"), o)); else CHECK_EQ("{| x: string |}", toString(requireType("foo"), o)); @@ -3385,7 +3386,7 @@ TEST_CASE_FIXTURE(Fixture, "checked_prop_too_early") LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("Value of type '{ x: number? }?' could be nil", toString(result.errors[0])); CHECK_EQ("number | { x: number }", toString(requireType("u"))); @@ -3405,7 +3406,7 @@ TEST_CASE_FIXTURE(Fixture, "accidentally_checked_prop_in_opposite_branch") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("Value of type '{ x: number? }?' could be nil", toString(result.errors[0])); else CHECK_EQ("Value of type '{| x: number? |}?' could be nil", toString(result.errors[0])); @@ -3484,7 +3485,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_leak_free_table_props") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("({ read blah: unknown }) -> ()", toString(requireType("a"))); CHECK_EQ("({ read gwar: unknown }) -> ()", toString(requireType("b"))); @@ -3504,7 +3505,7 @@ TEST_CASE_FIXTURE(Fixture, "mixed_tables_with_implicit_numbered_keys") local t: { [string]: number } = { 5, 6, 7 } )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK( @@ -3571,7 +3572,7 @@ TEST_CASE_FIXTURE(Fixture, "prop_access_on_unions_of_indexers_where_key_whose_ty )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("Type '{ [boolean]: number } | {number}' does not have key 'x'", toString(result.errors[0])); else CHECK_EQ("Type '{number} | {| [boolean]: number |}' does not have key 'x'", toString(result.errors[0])); @@ -3592,7 +3593,7 @@ local b = a.x TEST_CASE_FIXTURE(Fixture, "scalar_is_a_subtype_of_a_compatible_polymorphic_shape_type") { // CLI-115087 The new solver cannot infer that a table-like type is actually string - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function f(s) @@ -3619,7 +3620,7 @@ TEST_CASE_FIXTURE(Fixture, "scalar_is_not_a_subtype_of_a_compatible_polymorphic_ f("baz" :: "bar" | "baz") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // CLI-115090 Error reporting is quite bad in this case. @@ -3681,7 +3682,7 @@ Table type 'typeof(string)' not compatible with type 't1 where t1 = {- absolutel TEST_CASE_FIXTURE(Fixture, "a_free_shape_can_turn_into_a_scalar_if_it_is_compatible") { // CLI-115087 The new solver cannot infer that a table-like type is actually string - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function f(s): string @@ -3703,7 +3704,7 @@ TEST_CASE_FIXTURE(Fixture, "a_free_shape_cannot_turn_into_a_scalar_if_it_is_not_ end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(4, result); @@ -3736,7 +3737,7 @@ Table type 'typeof(string)' not compatible with type 't1 where t1 = {+ absolutel TEST_CASE_FIXTURE(BuiltinsFixture, "a_free_shape_can_turn_into_a_scalar_directly") { // We need egraphs to simplify the type of `out` here. CLI-114134 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function stringByteList(str) @@ -3774,7 +3775,7 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table local c : string = t.m("hi") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // FIXME. We really should be reporting just one error in this case. CLI-114509 LUAU_REQUIRE_ERROR_COUNT(3, result); @@ -3812,7 +3813,7 @@ local g : ({ p : number, q : string }) -> ({ p : number, r : boolean }) = f LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { const TypeMismatch* error = get(result.errors[0]); REQUIRE_MESSAGE(error, "Expected TypeMismatch but got " << result.errors[0]); @@ -3832,7 +3833,7 @@ local g : ({ p : number, q : string }) -> ({ p : number, r : boolean }) = f TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_has_a_side_effect") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -3970,7 +3971,7 @@ TEST_CASE_FIXTURE(Fixture, "when_augmenting_an_unsealed_table_with_an_indexer_ap CHECK(tt->props.empty()); REQUIRE(tt->indexer); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("unknown" == toString(tt->indexer->indexType)); else CHECK("string" == toString(tt->indexer->indexType)); @@ -3998,7 +3999,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_extend_unsealed_tables_in_rvalue_position") CHECK(0 == ttv->props.count("")); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_ERROR_COUNT(1, result); else LUAU_REQUIRE_NO_ERRORS(result); @@ -4151,7 +4152,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_84607_missing_prop_in_array_or_dict") LUAU_REQUIRE_ERROR_COUNT(2, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { const TypeMismatch* err1 = get(result.errors[0]); REQUIRE_MESSAGE(err1, "Expected TypeMismatch but got " << result.errors[0]); @@ -4199,7 +4200,7 @@ TEST_CASE_FIXTURE(Fixture, "simple_method_definition") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ m: (unknown) -> number }", toString(getMainModule()->returnType, ToStringOptions{true})); else CHECK_EQ("{| m: (a) -> number |}", toString(getMainModule()->returnType, ToStringOptions{true})); @@ -4207,7 +4208,7 @@ TEST_CASE_FIXTURE(Fixture, "simple_method_definition") TEST_CASE_FIXTURE(Fixture, "identify_all_problematic_table_fields") { - ScopedFastFlag sff_DebugLuauDeferredConstraintResolution{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff_LuauSolverV2{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type T = { @@ -4235,7 +4236,7 @@ TEST_CASE_FIXTURE(Fixture, "identify_all_problematic_table_fields") TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; CheckResult result = check(R"( @@ -4275,7 +4276,7 @@ TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported") TEST_CASE_FIXTURE(Fixture, "infer_write_property") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(t) @@ -4307,7 +4308,7 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_error_suppression") // the new solver reports specifically the inner mismatch, rather than the whole table // honestly not sure which of these is a better developer experience. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ(*tm->wantedType, *builtinTypes->stringType); CHECK_EQ(*tm->givenType, *builtinTypes->numberType); @@ -4321,7 +4322,7 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_error_suppression") TEST_CASE_FIXTURE(Fixture, "write_to_read_only_property") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(t: {read x: number}) @@ -4343,7 +4344,7 @@ TEST_CASE_FIXTURE(Fixture, "write_to_read_only_property") TEST_CASE_FIXTURE(Fixture, "write_to_unusually_named_read_only_property") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(t: {read ["hello world"]: number}) @@ -4358,7 +4359,7 @@ TEST_CASE_FIXTURE(Fixture, "write_to_unusually_named_read_only_property") TEST_CASE_FIXTURE(Fixture, "write_annotations_are_unsupported_even_with_the_new_solver") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( function f(t: {write foo: number}) @@ -4373,7 +4374,7 @@ TEST_CASE_FIXTURE(Fixture, "write_annotations_are_unsupported_even_with_the_new_ TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported") { - ScopedFastFlag sff[] = {{FFlag::DebugLuauDeferredConstraintResolution, false}}; + ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, false}}; CheckResult result = check(R"( type W = {read x: number} @@ -4397,7 +4398,7 @@ TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported") { - ScopedFastFlag sff[] = {{FFlag::DebugLuauDeferredConstraintResolution, false}}; + ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, false}}; CheckResult result = check(R"( type T = {read [string]: number} @@ -4414,10 +4415,10 @@ TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported") TEST_CASE_FIXTURE(Fixture, "table_writes_introduce_write_properties") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; - ScopedFastFlag sff[] = {{FFlag::DebugLuauDeferredConstraintResolution, true}}; + ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, true}}; CheckResult result = check(R"( function oc(player, speaker) @@ -4473,7 +4474,7 @@ TEST_CASE_FIXTURE(Fixture, "refined_thing_can_be_an_array") TEST_CASE_FIXTURE(Fixture, "parameter_was_set_an_indexer_and_bounded_by_string") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -4492,7 +4493,7 @@ TEST_CASE_FIXTURE(Fixture, "parameter_was_set_an_indexer_and_bounded_by_string") TEST_CASE_FIXTURE(Fixture, "parameter_was_set_an_indexer_and_bounded_by_another_parameter") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -4511,7 +4512,7 @@ TEST_CASE_FIXTURE(Fixture, "parameter_was_set_an_indexer_and_bounded_by_another_ TEST_CASE_FIXTURE(Fixture, "write_to_union_property_not_all_present") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( type Animal = {tag: "Cat", meow: boolean} | {tag: "Dog", woof: boolean} @@ -4631,7 +4632,7 @@ TEST_CASE_FIXTURE(Fixture, "cant_index_this") TEST_CASE_FIXTURE(Fixture, "setindexer_multiple_tables_intersection") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function f(t: { [string]: number } & { [thread]: boolean }, x) @@ -4657,7 +4658,7 @@ TEST_CASE_FIXTURE(Fixture, "insert_a_and_f_of_a_into_table_res_in_a_loop") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK(get(result.errors[0])); @@ -4677,7 +4678,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_adds_an_unbounded_indexer") // The old solver erroneously leaves a free type dangling here. The new // solver does better. - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("{unknown}" == toString(requireType("a"), {true})); else CHECK("{a}" == toString(requireType("a"), {true})); @@ -4794,4 +4795,41 @@ end LUAU_REQUIRE_NO_ERRORS(result); } + +TEST_CASE_FIXTURE(BuiltinsFixture, "indexing_branching_table") +{ + ScopedFastFlag sff{FFlag::LuauAcceptIndexingTableUnionsIntersections, true}; + + CheckResult result = check(R"( + local test = if true then { "meow", "woof" } else { 4, 81 } + local test2 = test[1] + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + + // unfortunate type duplication in the union + if (FFlag::LuauSolverV2) + CHECK("number | string | string" == toString(requireType("test2"))); + else + CHECK("number | string" == toString(requireType("test2"))); +} + +TEST_CASE_FIXTURE(BuiltinsFixture, "indexing_branching_table2") +{ + ScopedFastFlag sff{FFlag::LuauAcceptIndexingTableUnionsIntersections, true}; + + CheckResult result = check(R"( + local test = if true then {} else {} + local test2 = test[1] + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + + // unfortunate type duplication in the union + if (FFlag::LuauSolverV2) + CHECK("unknown | unknown" == toString(requireType("test2"))); + else + CHECK("any" == toString(requireType("test2"))); +} + TEST_SUITE_END(); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.test.cpp index 1140976f..09c6c05b 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.test.cpp @@ -17,7 +17,7 @@ #include LUAU_FASTFLAG(LuauFixLocationSpanTableIndexExpr); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauInstantiateInSubtyping); LUAU_FASTINT(LuauCheckRecursionLimit); LUAU_FASTINT(LuauNormalizeCacheLimit); @@ -49,7 +49,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_error") { CheckResult result = check("local a = 7 local b = 'hi' a = b"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK("number | string" == toString(requireType("a"))); @@ -69,7 +69,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_error_2") { CheckResult result = check("local a = 7 a = 'hi'"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_NO_ERRORS(result); CHECK("number | string" == toString(requireType("a"))); @@ -96,7 +96,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_with_nil_value") CheckResult result = check("local f = nil; f = 'hello world'"); LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("string?" == toString(requireType("f"))); } @@ -128,7 +128,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site") f("foo") )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("unknown" == toString(requireType("a"))); CHECK("(unknown) -> ()" == toString(requireType("f"))); @@ -146,7 +146,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site") TEST_CASE_FIXTURE(Fixture, "infer_in_nocheck_mode") { ScopedFastFlag sff[]{ - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; CheckResult result = check(R"( @@ -194,7 +194,7 @@ TEST_CASE_FIXTURE(Fixture, "if_statement") LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK("string?" == toString(requireType("a"))); CHECK("number?" == toString(requireType("b"))); @@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "statements_are_topologically_sorted") TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local o @@ -265,7 +265,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case") TEST_CASE_FIXTURE(Fixture, "dont_ice_when_failing_the_occurs_check") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -318,7 +318,7 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types") CHECK_EQ("x", err->key); // TODO: Should we assert anything about these tests when DCR is being used? - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) { CHECK_EQ("*error-type*", toString(requireType("c"))); CHECK_EQ("*error-type*", toString(requireType("d"))); @@ -384,7 +384,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types") // checker. We also want it to somewhat match up with production values, so we push up the parser recursion limit a little bit instead. TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; #if defined(LUAU_ENABLE_ASAN) int limit = 250; @@ -442,7 +442,7 @@ TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit") TEST_CASE_FIXTURE(Fixture, "globals") { // The new solver does not permit assignments to globals like this. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -456,7 +456,7 @@ TEST_CASE_FIXTURE(Fixture, "globals") TEST_CASE_FIXTURE(Fixture, "globals2") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!nonstrict @@ -506,7 +506,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do") TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CHECK_NOTHROW(check(R"( --!nonstrict @@ -600,7 +600,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert") TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error") { { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -622,7 +622,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_ } { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -697,7 +697,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_39932_use_unifier_in_ensure_methods") TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( foo @@ -708,7 +708,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError") TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a = foo: @@ -759,7 +759,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_isoptional") std::optional t0 = lookupType("t0"); REQUIRE(t0); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("any" == toString(*t0)); else CHECK_EQ("*error-type*", toString(*t0)); @@ -819,7 +819,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_heap_use_after_free_error") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) LUAU_REQUIRE_NO_ERRORS(result); else LUAU_REQUIRE_ERRORS(result); @@ -1099,7 +1099,7 @@ end TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( --!strict @@ -1177,7 +1177,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice") LUAU_REQUIRE_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Type contains a self-recursive construct that cannot be resolved" == toString(result.errors[0])); else CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0])); @@ -1199,7 +1199,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer") CHECK(1 == result.errors.size()); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(Location{{3, 22}, {3, 42}} == result.errors[0].location); else CHECK(Location{{3, 12}, {3, 46}} == result.errors[0].location); @@ -1222,7 +1222,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_cache_limit_normalizer") TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution") { // CLI-114134 - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local obj = {} @@ -1358,7 +1358,7 @@ end TEST_CASE_FIXTURE(Fixture, "dcr_delays_expansion_of_function_containing_blocked_parameter_type") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, }; CheckResult result = check(R"( @@ -1392,7 +1392,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_function_that_invokes_itself_with_ end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(unknown) -> ()" == toString(requireType("readValue"))); else CHECK("(a) -> ()" == toString(requireType("readValue"))); @@ -1408,7 +1408,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_function_that_invokes_itself_with_ end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("(unknown) -> ()" == toString(requireType("readValue"))); else CHECK("(number) -> ()" == toString(requireType("readValue"))); @@ -1527,7 +1527,7 @@ TEST_CASE_FIXTURE(Fixture, "promote_tail_type_packs") TEST_CASE_FIXTURE(BuiltinsFixture, "lti_must_record_contributing_locations") { - ScopedFastFlag sff_DebugLuauDeferredConstraintResolution{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff_LuauSolverV2{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function f(a) @@ -1563,7 +1563,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lti_must_record_contributing_locations") */ TEST_CASE_FIXTURE(BuiltinsFixture, "be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local function concat(target: {T}, ...: {T} | T): {T} @@ -1615,7 +1615,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_iter_metamethod") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp index 7db4512b..10ddd097 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.tryUnify.test.cpp @@ -11,13 +11,13 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauUnifierRecursionOnRestart); struct TryUnifyFixture : Fixture { // Cannot use `TryUnifyFixture` under DCR. - ScopedFastFlag noDcr{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag noDcr{FFlag::LuauSolverV2, false}; TypeArena arena; ScopePtr globalScope{new Scope{arena.addTypePack({TypeId{}})}}; @@ -154,7 +154,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_intersection_sub_anything") TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(arg : { prop : string & number }) : never @@ -166,7 +166,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never") TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(arg : { prop : string & number }) : boolean @@ -178,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything") TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_with_errorType") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(arg: number) end @@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_w TEST_CASE_FIXTURE(Fixture, "result_of_failed_typepack_unification_is_constrained") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(arg: number) return arg end @@ -278,7 +278,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cli_41095_concat_log_in_sealed_table_unifica LUAU_REQUIRE_ERROR_COUNT(2, result); CHECK_EQ(toString(result.errors[0]), "No overload for function accepts 0 arguments."); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(result.errors[1]), "Available overloads: ({V}, V) -> (); and ({V}, number, V) -> ()"); else CHECK_EQ(toString(result.errors[1]), "Available overloads: ({a}, a) -> (); and ({a}, number, a) -> ()"); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp index f23dfb47..8b489c44 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.typePacks.test.cpp @@ -9,7 +9,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_FASTFLAG(LuauInstantiateInSubtyping); TEST_SUITE_BEGIN("TypePackTests"); @@ -316,7 +316,7 @@ local c: Packed tf = lookupType("Packed"); REQUIRE(tf); CHECK_EQ(toString(*tf), "Packed"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(*tf, {true}), "{ f: (T, U...) -> (T, U...) }"); else CHECK_EQ(toString(*tf, {true}), "{| f: (T, U...) -> (T, U...) |}"); @@ -324,7 +324,7 @@ local c: Packed auto ttvA = get(requireType("a")); REQUIRE(ttvA); CHECK_EQ(toString(requireType("a")), "Packed"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireType("a"), {true}), "{ f: (number) -> number }"); else CHECK_EQ(toString(requireType("a"), {true}), "{| f: (number) -> number |}"); @@ -336,7 +336,7 @@ local c: Packed auto ttvB = get(requireType("b")); REQUIRE(ttvB); CHECK_EQ(toString(requireType("b")), "Packed"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireType("b"), {true}), "{ f: (string, number) -> (string, number) }"); else CHECK_EQ(toString(requireType("b"), {true}), "{| f: (string, number) -> (string, number) |}"); @@ -348,7 +348,7 @@ local c: Packed auto ttvC = get(requireType("c")); REQUIRE(ttvC); CHECK_EQ(toString(requireType("c")), "Packed"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireType("c"), {true}), "{ f: (string, number, boolean) -> (string, number, boolean) }"); else CHECK_EQ(toString(requireType("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}"); @@ -381,7 +381,7 @@ local d: { a: typeof(c) } REQUIRE(tf); CHECK_EQ(toString(*tf), "Packed"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ(toString(*tf, {true}), "{ a: T, b: (U...) -> () }"); @@ -421,12 +421,12 @@ type C = Import.Packed auto tf = lookupType("Alias"); REQUIRE(tf); CHECK_EQ(toString(*tf), "Alias"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(*tf, {true}), "{ a: S, b: (T, R...) -> () }"); else CHECK_EQ(toString(*tf, {true}), "{| a: S, b: (T, R...) -> () |}"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(requireType("a"), {true}), "{ a: string, b: (number, boolean) -> () }"); else CHECK_EQ(toString(requireType("a"), {true}), "{| a: string, b: (number, boolean) -> () |}"); @@ -434,7 +434,7 @@ type C = Import.Packed tf = lookupType("B"); REQUIRE(tf); CHECK_EQ(toString(*tf), "B"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(*tf, {true}), "{ a: string, b: (X...) -> () }"); else CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (X...) -> () |}"); @@ -442,7 +442,7 @@ type C = Import.Packed tf = lookupType("C"); REQUIRE(tf); CHECK_EQ(toString(*tf), "C"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(*tf, {true}), "{ a: string, b: (number, X...) -> () }"); else CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (number, X...) -> () |}"); @@ -787,7 +787,7 @@ local d: Y ()> TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Y = { a: T } @@ -811,7 +811,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors2") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors3") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Y = { a: (T) -> U... } @@ -824,7 +824,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors3") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors4") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type Packed = (T) -> T @@ -935,7 +935,7 @@ type R = { m: F } LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ(toString(*lookupType("R"), {true}), "t1 where t1 = { m: (t1) -> (t1) -> () }"); else CHECK_EQ(toString(*lookupType("R"), {true}), "t1 where t1 = {| m: (t1) -> (t1) -> () |}"); @@ -951,7 +951,7 @@ a = b LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { const std::string expected = "Type\n" @@ -1065,7 +1065,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2") TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function foo(...: string): number @@ -1094,7 +1094,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments_free") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK( toString(result.errors.at(0)) == "Type pack '...number' could not be converted into 'boolean'; type ...number.tail() (...number) is not a subtype of boolean (boolean)" @@ -1106,7 +1106,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments_free") TEST_CASE_FIXTURE(BuiltinsFixture, "type_packs_with_tails_in_vararg_adjustment") { std::optional sff; - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) sff = {FFlag::LuauInstantiateInSubtyping, true}; CheckResult result = check(R"( @@ -1127,7 +1127,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_packs_with_tails_in_vararg_adjustment") TEST_CASE_FIXTURE(BuiltinsFixture, "generalize_expectedTypes_with_proper_scope") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, true}, + {FFlag::LuauSolverV2, true}, {FFlag::LuauInstantiateInSubtyping, true}, }; diff --git a/Dependencies/luau/Luau/tests/TypeInfer.typestates.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.typestates.test.cpp index 19117447..0bce7546 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.typestates.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.typestates.test.cpp @@ -3,7 +3,7 @@ #include "doctest.h" -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) using namespace Luau; @@ -11,7 +11,7 @@ namespace { struct TypeStateFixture : BuiltinsFixture { - ScopedFastFlag dcr{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag dcr{FFlag::LuauSolverV2, true}; }; } // namespace @@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(TypeStateFixture, "parameter_x_was_constrained_by_two_types") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { // `y` is annotated `string | number` which is explicitly not compatible with `string?` // as such, we produce an error here for that mismatch. @@ -392,7 +392,7 @@ TEST_CASE_FIXTURE(TypeStateFixture, "prototyped_recursive_functions") TEST_CASE_FIXTURE(BuiltinsFixture, "prototyped_recursive_functions_but_has_future_assignments") { // early return if the flag isn't set since this is blocking gated commits - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -459,7 +459,9 @@ TEST_CASE_FIXTURE(TypeStateFixture, "typestates_preserve_error_suppression") TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_preserve_error_suppression_properties") { // early return if the flag isn't set since this is blocking gated commits - if (!FFlag::DebugLuauDeferredConstraintResolution) + // unconditional return + // CLI-117098 Type states with error suppressing properties doesn't infer the correct type for properties. + if (!FFlag::LuauSolverV2 || FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -475,7 +477,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_preserve_error_suppression_proper TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_do_not_apply_to_the_initial_local_definition") { // early return if the flag isn't set since this is blocking gated commits - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -493,7 +495,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typestates_do_not_apply_to_the_initial_local TEST_CASE_FIXTURE(Fixture, "typestate_globals") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; loadDefinition(R"( declare foo: string | number @@ -510,7 +512,7 @@ TEST_CASE_FIXTURE(Fixture, "typestate_globals") TEST_CASE_FIXTURE(Fixture, "typestate_unknown_global") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( x = 5 diff --git a/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp index 3a880d6d..6cdec4af 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.unionTypes.test.cpp @@ -8,7 +8,8 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2) +LUAU_FASTFLAG(LuauAcceptIndexingTableUnionsIntersections) TEST_SUITE_BEGIN("UnionTypes"); @@ -35,7 +36,7 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint") { // CLI-114134 We need egraphs to consistently reduce the cyclic union // introduced by the increment here. - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local count = 0 @@ -121,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments") TEST_CASE_FIXTURE(Fixture, "optional_arguments_table") { // CLI-115588 - Bidirectional inference does not happen for assignments - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local a:{a:string, b:string?} @@ -236,7 +237,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_missing_property") REQUIRE(mup); CHECK_EQ("Key 'x' is missing from 'B' in the type 'A | B'", toString(result.errors[0])); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(A | B) -> number", toString(requireType("f"))); else CHECK_EQ("(A | B) -> *error-type*", toString(requireType("f"))); @@ -410,7 +411,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_assignment_errors_2") LUAU_REQUIRE_ERROR_COUNT(1, result); auto s = toString(result.errors[0]); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("Value of type '({ x: number } & { y: number })?' could be nil", s); else CHECK_EQ("Value of type '({| x: number |} & {| y: number |})?' could be nil", s); @@ -472,7 +473,7 @@ end TEST_CASE_FIXTURE(Fixture, "unify_unsealed_table_union_check") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( local x = { x = 3 } @@ -533,7 +534,7 @@ end LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ( toString(result.errors[0]), @@ -565,7 +566,7 @@ TEST_CASE_FIXTURE(Fixture, "error_detailed_union_all") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK(toString(result.errors[0]) == "Type '{ w: number }' could not be converted into 'X | Y | Z'"); else CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X | Y | Z'; none of the union options are compatible)"); @@ -580,7 +581,7 @@ local a: X? = { w = 4 } )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK("Type '{ w: number }' could not be converted into 'X?'" == toString(result.errors[0])); else { @@ -636,12 +637,17 @@ TEST_CASE_FIXTURE(Fixture, "indexing_into_a_cyclic_union_doesnt_crash") end )"); - LUAU_REQUIRE_ERROR_COUNT(1, result); + // this is a cyclic union of number arrays, so it _is_ a table, even if it's a nonsense type. + // no need to generate a NotATable error here. + if (FFlag::LuauAcceptIndexingTableUnionsIntersections) + LUAU_REQUIRE_NO_ERRORS(result); + else + LUAU_REQUIRE_ERROR_COUNT(1, result); } TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( type A = { x: number, y: (number) -> string } | { z: number, y: (number) -> string } @@ -717,7 +723,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_generic_typepack_functions") TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f() @@ -737,7 +743,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics") TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generic_typepacks") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f() @@ -758,7 +764,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_arg_arities") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(x : (number) -> number?) @@ -777,7 +783,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_arities") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(x : () -> (number | string)) @@ -796,7 +802,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_variadics") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(x : (...nil) -> (...number?)) @@ -823,7 +829,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_arg_variadics") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK(R"(Type '(number) -> ()' @@ -842,7 +848,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_variadics") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(x : () -> (number?, ...number)) @@ -861,7 +867,7 @@ could not be converted into TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -878,7 +884,7 @@ TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types") TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types_2") { - if (!FFlag::DebugLuauDeferredConstraintResolution) + if (!FFlag::LuauSolverV2) return; CheckResult result = check(R"( @@ -910,7 +916,7 @@ TEST_CASE_FIXTURE(Fixture, "union_table_any_property") TEST_CASE_FIXTURE(Fixture, "union_function_any_args") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(sup : ((...any) -> (...any))?, sub : ((number) -> (...any))) @@ -934,7 +940,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_any") TEST_CASE_FIXTURE(Fixture, "generic_function_with_optional_arg") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, false}; + ScopedFastFlag sff{FFlag::LuauSolverV2, false}; CheckResult result = check(R"( function f(x : T?) : {T} @@ -968,7 +974,7 @@ TEST_CASE_FIXTURE(Fixture, "lookup_prop_of_intersection_containing_unions") TEST_CASE_FIXTURE(Fixture, "suppress_errors_for_prop_lookup_of_a_union_that_includes_error") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; registerHiddenTypes(&frontend); diff --git a/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp b/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp index 42007078..0c62d0b6 100644 --- a/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeInfer.unknownnever.test.cpp @@ -6,7 +6,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); TEST_SUITE_BEGIN("TypeInferUnknownNever"); @@ -118,7 +118,7 @@ TEST_CASE_FIXTURE(Fixture, "type_packs_containing_never_is_itself_uninhabitable" local x, y, z = f() )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK("Function only returns 2 values, but 3 are required here" == toString(result.errors[0])); @@ -149,7 +149,7 @@ TEST_CASE_FIXTURE(Fixture, "type_packs_containing_never_is_itself_uninhabitable2 LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { CHECK_EQ("string", toString(requireType("x1"))); CHECK_EQ("never", toString(requireType("x2"))); @@ -193,12 +193,20 @@ TEST_CASE_FIXTURE(Fixture, "call_never") TEST_CASE_FIXTURE(Fixture, "assign_to_local_which_is_never") { + // CLI-117119 - What do we do about assigning to never? CheckResult result = check(R"( local t: never t = 3 )"); - LUAU_REQUIRE_NO_ERRORS(result); + if (FFlag::LuauSolverV2) + { + LUAU_REQUIRE_ERROR_COUNT(1, result); + } + else + { + LUAU_REQUIRE_NO_ERRORS(result); + } } TEST_CASE_FIXTURE(Fixture, "assign_to_global_which_is_never") @@ -257,6 +265,9 @@ TEST_CASE_FIXTURE(Fixture, "pick_never_from_variadic_type_pack") TEST_CASE_FIXTURE(Fixture, "index_on_union_of_tables_for_properties_that_is_never") { + // CLI-117116 - We are erroneously warning when passing a valid table literal where we expect a union of tables. + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( type Disjoint = {foo: never, bar: unknown, tag: "ok"} | {foo: never, baz: unknown, tag: "err"} @@ -274,6 +285,9 @@ TEST_CASE_FIXTURE(Fixture, "index_on_union_of_tables_for_properties_that_is_neve TEST_CASE_FIXTURE(Fixture, "index_on_union_of_tables_for_properties_that_is_sorta_never") { + // CLI-117116 - We are erroneously warning when passing a valid table literal where we expect a union of tables. + if (FFlag::LuauSolverV2) + return; CheckResult result = check(R"( type Disjoint = {foo: string, bar: unknown, tag: "ok"} | {foo: never, baz: unknown, tag: "err"} @@ -321,7 +335,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_unify_operands_if_one_of_the_operand_is_never_i LUAU_REQUIRE_NO_ERRORS(result); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("(nil, unknown) -> boolean", toString(requireType("ord"))); else CHECK_EQ("(nil, a) -> boolean", toString(requireType("ord"))); @@ -335,7 +349,7 @@ TEST_CASE_FIXTURE(Fixture, "math_operators_and_never") end )"); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) { LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK(get(result.errors[0])); @@ -365,7 +379,7 @@ TEST_CASE_FIXTURE(Fixture, "compare_never") TEST_CASE_FIXTURE(Fixture, "lti_error_at_declaration_for_never_normalizations") { - ScopedFastFlag sff_DebugLuauDeferredConstraintResolution{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff_LuauSolverV2{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function num(x: number) end @@ -389,7 +403,7 @@ TEST_CASE_FIXTURE(Fixture, "lti_error_at_declaration_for_never_normalizations") TEST_CASE_FIXTURE(Fixture, "lti_permit_explicit_never_annotation") { - ScopedFastFlag sff_DebugLuauDeferredConstraintResolution{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff_LuauSolverV2{FFlag::LuauSolverV2, true}; CheckResult result = check(R"( local function num(x: number) end diff --git a/Dependencies/luau/Luau/tests/TypePath.test.cpp b/Dependencies/luau/Luau/tests/TypePath.test.cpp index 54ec14b8..2481f27a 100644 --- a/Dependencies/luau/Luau/tests/TypePath.test.cpp +++ b/Dependencies/luau/Luau/tests/TypePath.test.cpp @@ -15,17 +15,17 @@ using namespace Luau; using namespace Luau::TypePath; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAG(LuauSolverV2); LUAU_DYNAMIC_FASTINT(LuauTypePathMaximumTraverseSteps); struct TypePathFixture : Fixture { - ScopedFastFlag sff1{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff1{FFlag::LuauSolverV2, true}; }; struct TypePathBuiltinsFixture : BuiltinsFixture { - ScopedFastFlag sff1{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff1{FFlag::LuauSolverV2, true}; }; TEST_SUITE_BEGIN("TypePathManipulation"); @@ -522,7 +522,7 @@ TEST_SUITE_BEGIN("TypePathToString"); TEST_CASE("field") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; CHECK(toString(PathBuilder().prop("foo").build()) == R"(["foo"])"); @@ -551,7 +551,7 @@ TEST_CASE("empty_path") TEST_CASE("prop") { ScopedFastFlag sff[] = { - {FFlag::DebugLuauDeferredConstraintResolution, false}, + {FFlag::LuauSolverV2, false}, }; Path p = PathBuilder().prop("foo").build(); @@ -592,7 +592,7 @@ TEST_CASE("fields") TEST_CASE("chained") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; CHECK( PathBuilder().index(0).readProp("foo").mt().readProp("bar").args().index(1).build() == diff --git a/Dependencies/luau/Luau/tests/TypeVar.test.cpp b/Dependencies/luau/Luau/tests/TypeVar.test.cpp index 17c0c34b..9e21b1e0 100644 --- a/Dependencies/luau/Luau/tests/TypeVar.test.cpp +++ b/Dependencies/luau/Luau/tests/TypeVar.test.cpp @@ -304,7 +304,7 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") REQUIRE(!anyification.normalizationTooComplex); REQUIRE(any.has_value()); - if (FFlag::DebugLuauDeferredConstraintResolution) + if (FFlag::LuauSolverV2) CHECK_EQ("{ f: t1 } where t1 = () -> { f: () -> { f: ({ f: t1 }) -> (), signal: { f: (any) -> () } } }", toString(*any)); else CHECK_EQ("{| f: t1 |} where t1 = () -> {| f: () -> {| f: ({| f: t1 |}) -> (), signal: {| f: (any) -> () |} |} |}", toString(*any)); diff --git a/Dependencies/luau/Luau/tests/Unifier2.test.cpp b/Dependencies/luau/Luau/tests/Unifier2.test.cpp index 8efb2870..65734103 100644 --- a/Dependencies/luau/Luau/tests/Unifier2.test.cpp +++ b/Dependencies/luau/Luau/tests/Unifier2.test.cpp @@ -12,7 +12,7 @@ using namespace Luau; -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) struct Unifier2Fixture { @@ -23,7 +23,7 @@ struct Unifier2Fixture Unifier2 u2{NotNull{&arena}, NotNull{&builtinTypes}, NotNull{&scope}, NotNull{&iceReporter}}; ToStringOptions opts; - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; std::pair freshType() { diff --git a/Dependencies/luau/Luau/tests/VisitType.test.cpp b/Dependencies/luau/Luau/tests/VisitType.test.cpp index a1a17e8e..186afaa5 100644 --- a/Dependencies/luau/Luau/tests/VisitType.test.cpp +++ b/Dependencies/luau/Luau/tests/VisitType.test.cpp @@ -9,21 +9,34 @@ using namespace Luau; LUAU_FASTINT(LuauVisitRecursionLimit); -LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauSolverV2) TEST_SUITE_BEGIN("VisitType"); TEST_CASE_FIXTURE(Fixture, "throw_when_limit_is_exceeded") { - ScopedFastInt sfi{FInt::LuauVisitRecursionLimit, 3}; - - CheckResult result = check(R"( - local t : {a: {b: {c: {d: {e: boolean}}}}} - )"); - - TypeId tType = requireType("t"); - - CHECK_THROWS_AS(toString(tType), RecursionLimitException); + if (FFlag::LuauSolverV2) + { + CheckResult result = check(R"( + local t : {a: {b: {c: {d: {e: boolean}}}}} + )"); + ScopedFastInt sfi{FInt::LuauVisitRecursionLimit, 3}; + TypeId tType = requireType("t"); + + CHECK_THROWS_AS(toString(tType), RecursionLimitException); + } + else + { + ScopedFastInt sfi{FInt::LuauVisitRecursionLimit, 3}; + + CheckResult result = check(R"( + local t : {a: {b: {c: {d: {e: boolean}}}}} + )"); + + TypeId tType = requireType("t"); + + CHECK_THROWS_AS(toString(tType), RecursionLimitException); + } } TEST_CASE_FIXTURE(Fixture, "dont_throw_when_limit_is_high_enough") @@ -48,7 +61,7 @@ TEST_CASE_FIXTURE(Fixture, "some_free_types_do_not_have_bounds") TEST_CASE_FIXTURE(Fixture, "some_free_types_have_bounds") { - ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true}; + ScopedFastFlag sff{FFlag::LuauSolverV2, true}; Scope scope{builtinTypes->anyTypePack}; Type t{FreeType{&scope, builtinTypes->neverType, builtinTypes->numberType}}; diff --git a/Dependencies/luau/Luau/tests/conformance/vector.lua b/Dependencies/luau/Luau/tests/conformance/vector.lua index 7e4a9a3e..3c70cfb0 100644 --- a/Dependencies/luau/Luau/tests/conformance/vector.lua +++ b/Dependencies/luau/Luau/tests/conformance/vector.lua @@ -164,4 +164,23 @@ do assert(larget[vector(-0, 0, 0)] == 42) end +local function numvectemporary() + local proptab = {} + + proptab.vec3compsum = function(vec: vector) + local num = vec.X + vec.Y + local tmp = vec / num + local num2 = num * 2 + return tmp, num2 + end + + local a, b = proptab.vec3compsum(vector(2, 6, 0)) + + assert(a.X == 0.25) + assert(a.Y == 0.75) + assert(b == 16) +end + +numvectemporary() + return 'OK' diff --git a/Dependencies/luau/Luau/tests/main.cpp b/Dependencies/luau/Luau/tests/main.cpp index 42c3ad80..4612829b 100644 --- a/Dependencies/luau/Luau/tests/main.cpp +++ b/Dependencies/luau/Luau/tests/main.cpp @@ -51,7 +51,7 @@ static bool skipFastFlag(const char* flagName) if (strncmp(flagName, "Debug", 5) == 0) return true; - if (strcmp(flagName, "StudioReportLuauAny") == 0) + if (strcmp(flagName, "StudioReportLuauAny2") == 0) return true; return false; diff --git a/Dependencies/luau/Luau/tests/require/with_config/src/.luaurc b/Dependencies/luau/Luau/tests/require/with_config/src/.luaurc index 87064bbc..8c1ae683 100644 --- a/Dependencies/luau/Luau/tests/require/with_config/src/.luaurc +++ b/Dependencies/luau/Luau/tests/require/with_config/src/.luaurc @@ -1,6 +1,7 @@ { "paths": ["../ProjectLuauLibraries"], "aliases": { - "dep": "dependency" + "dep": "dependency", + "subdir": "subdirectory" } } diff --git a/Dependencies/luau/Luau/tests/require/with_config/src/directory_alias_requirer.luau b/Dependencies/luau/Luau/tests/require/with_config/src/directory_alias_requirer.luau new file mode 100644 index 00000000..3b19d4ff --- /dev/null +++ b/Dependencies/luau/Luau/tests/require/with_config/src/directory_alias_requirer.luau @@ -0,0 +1 @@ +return(require("@subdir/subdirectory_dependency")) diff --git a/Dependencies/luau/Luau/tests/require/with_config/src/subdirectory/subdirectory_dependency.luau b/Dependencies/luau/Luau/tests/require/with_config/src/subdirectory/subdirectory_dependency.luau new file mode 100644 index 00000000..8bbd0beb --- /dev/null +++ b/Dependencies/luau/Luau/tests/require/with_config/src/subdirectory/subdirectory_dependency.luau @@ -0,0 +1 @@ +return {"result from subdirectory_dependency"} diff --git a/Dependencies/luau/Luau/tools/faillist.txt b/Dependencies/luau/Luau/tools/faillist.txt index d785d14d..e69de29b 100644 --- a/Dependencies/luau/Luau/tools/faillist.txt +++ b/Dependencies/luau/Luau/tools/faillist.txt @@ -1,45 +0,0 @@ -AutocompleteTest.anonymous_autofilled_generic_on_argument_type_pack_vararg -AutocompleteTest.anonymous_autofilled_generic_type_pack_vararg -AutocompleteTest.autocomplete_string_singletons -AutocompleteTest.suggest_table_keys -AutocompleteTest.type_correct_suggestion_for_overloads -AutocompleteTest.type_correct_suggestion_in_table -GenericsTests.do_not_always_instantiate_generic_intersection_types -GenericsTests.error_detailed_function_mismatch_generic_pack -GenericsTests.error_detailed_function_mismatch_generic_types -GenericsTests.factories_of_generics -GenericsTests.generic_argument_count_too_few -GenericsTests.generic_argument_count_too_many -GenericsTests.generic_factories -GenericsTests.generic_functions_in_types -GenericsTests.generic_type_functions_work_in_subtyping -GenericsTests.generic_type_pack_unification1 -GenericsTests.generic_type_pack_unification2 -GenericsTests.generic_type_pack_unification3 -GenericsTests.higher_rank_polymorphism_should_not_accept_instantiated_arguments -GenericsTests.instantiated_function_argument_names -GenericsTests.properties_can_be_instantiated_polytypes -GenericsTests.quantify_functions_even_if_they_have_an_explicit_generic -IntersectionTypes.intersect_metatables -IntersectionTypes.intersect_saturate_overloaded_functions -IntersectionTypes.intersection_of_tables -IntersectionTypes.intersection_of_tables_with_top_properties -IntersectionTypes.less_greedy_unification_with_intersection_types -IntersectionTypes.overloaded_functions_mentioning_generic -IntersectionTypes.overloaded_functions_mentioning_generic_packs -IntersectionTypes.overloaded_functions_mentioning_generics -IntersectionTypes.overloaded_functions_returning_intersections -IntersectionTypes.overloadeded_functions_with_never_arguments -ModuleTests.clone_self_property -Negations.cofinite_strings_can_be_compared_for_equality -Normalize.higher_order_function_with_annotation -RefinementTest.refine_a_param_that_got_resolved_during_constraint_solving_stage -RefinementTest.x_as_any_if_x_is_instance_elseif_x_is_table -RefinementTest.x_is_not_instance_or_else_not_part -TypeInferFunctions.simple_unannotated_mutual_recursion -TypeInferUnknownNever.assign_to_local_which_is_never -TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_never -TypeInferUnknownNever.index_on_union_of_tables_for_properties_that_is_sorta_never -TypePackTests.fuzz_typepack_iter_follow_2 -TypeStatesTest.typestates_preserve_error_suppression_properties -VisitType.throw_when_limit_is_exceeded diff --git a/Dependencies/luau/Luau/tools/fuzz/requirements.txt b/Dependencies/luau/Luau/tools/fuzz/requirements.txt index 0f591a2b..297ba324 100644 --- a/Dependencies/luau/Luau/tools/fuzz/requirements.txt +++ b/Dependencies/luau/Luau/tools/fuzz/requirements.txt @@ -1,2 +1,2 @@ -Jinja2==3.1.2 +Jinja2==3.1.4 MarkupSafe==2.1.3 diff --git a/Dependencies/luau/Luau/tools/lldb_formatters.py b/Dependencies/luau/Luau/tools/lldb_formatters.py index 9be6cade..7e957c75 100644 --- a/Dependencies/luau/Luau/tools/lldb_formatters.py +++ b/Dependencies/luau/Luau/tools/lldb_formatters.py @@ -371,7 +371,7 @@ def luau_typepath_property_summary(valobj, internal_dict, options): read_write = False try: fflag_valobj = valobj.GetFrame().GetValueForVariablePath( - "FFlag::DebugLuauDeferredConstraintResolution::value") + "FFlag::LuauSolverV2::value") read_write = fflag_valobj.GetValue() == "true" except Exception as e: diff --git a/Dependencies/luau/Luau/tools/test_dcr.py b/Dependencies/luau/Luau/tools/test_dcr.py index 30940c63..3de92b37 100644 --- a/Dependencies/luau/Luau/tools/test_dcr.py +++ b/Dependencies/luau/Luau/tools/test_dcr.py @@ -136,7 +136,7 @@ def main(): failList = loadFailList() - flags = ["true", "DebugLuauDeferredConstraintResolution"] + flags = ["true", "LuauSolverV2"] commandLine = [args.path, "--reporters=xml", "--fflags=" + ",".join(flags)] diff --git a/Dependencies/luau/Version-0.639 b/Dependencies/luau/Version-0.643 similarity index 100% rename from Dependencies/luau/Version-0.639 rename to Dependencies/luau/Version-0.643 From 491414c729f74b7631eda814213fb5ee8a89aa86 Mon Sep 17 00:00:00 2001 From: Pursche Date: Sun, 20 Oct 2024 00:35:34 +0200 Subject: [PATCH 05/11] Add freetype, msdfgen and msdf-atlas-gen dependencies --- Dependencies/Dependencies.lua | 5 +- Dependencies/freetype/freetype.lua | 85 + Dependencies/freetype/freetype/.clang-format | 16 + Dependencies/freetype/freetype/LICENSE.TXT | 46 + Dependencies/freetype/freetype/README | 107 + Dependencies/freetype/freetype/README.git | 102 + .../freetype/freetype/devel/ft2build.h | 41 + .../freetype/freetype/devel/ftoption.h | 1030 ++ .../freetype/freetype/include/dlg/dlg.h | 290 + .../freetype/freetype/include/dlg/output.h | 172 + .../include/freetype/config/ftconfig.h | 51 + .../include/freetype/config/ftheader.h | 836 ++ .../include/freetype/config/ftmodule.h | 33 + .../include/freetype/config/ftoption.h | 1030 ++ .../include/freetype/config/ftstdlib.h | 185 + .../include/freetype/config/integer-types.h | 250 + .../include/freetype/config/mac-support.h | 49 + .../include/freetype/config/public-macros.h | 138 + .../freetype/include/freetype/freetype.h | 5289 +++++++++ .../freetype/include/freetype/ftadvanc.h | 188 + .../freetype/include/freetype/ftbbox.h | 101 + .../freetype/include/freetype/ftbdf.h | 212 + .../freetype/include/freetype/ftbitmap.h | 329 + .../freetype/include/freetype/ftbzip2.h | 102 + .../freetype/include/freetype/ftcache.h | 1087 ++ .../freetype/include/freetype/ftchapters.h | 168 + .../freetype/include/freetype/ftcid.h | 167 + .../freetype/include/freetype/ftcolor.h | 1667 +++ .../freetype/include/freetype/ftdriver.h | 1320 +++ .../freetype/include/freetype/fterrdef.h | 283 + .../freetype/include/freetype/fterrors.h | 296 + .../freetype/include/freetype/ftfntfmt.h | 93 + .../freetype/include/freetype/ftgasp.h | 143 + .../freetype/include/freetype/ftglyph.h | 750 ++ .../freetype/include/freetype/ftgxval.h | 354 + .../freetype/include/freetype/ftgzip.h | 151 + .../freetype/include/freetype/ftimage.h | 1289 +++ .../freetype/include/freetype/ftincrem.h | 348 + .../freetype/include/freetype/ftlcdfil.h | 323 + .../freetype/include/freetype/ftlist.h | 296 + .../freetype/include/freetype/ftlogging.h | 184 + .../freetype/include/freetype/ftlzw.h | 100 + .../freetype/include/freetype/ftmac.h | 289 + .../freetype/freetype/include/freetype/ftmm.h | 834 ++ .../freetype/include/freetype/ftmodapi.h | 807 ++ .../freetype/include/freetype/ftmoderr.h | 204 + .../freetype/include/freetype/ftotval.h | 206 + .../freetype/include/freetype/ftoutln.h | 588 + .../freetype/include/freetype/ftparams.h | 218 + .../freetype/include/freetype/ftpfr.h | 179 + .../freetype/include/freetype/ftrender.h | 244 + .../freetype/include/freetype/ftsizes.h | 159 + .../freetype/include/freetype/ftsnames.h | 272 + .../freetype/include/freetype/ftstroke.h | 773 ++ .../freetype/include/freetype/ftsynth.h | 104 + .../freetype/include/freetype/ftsystem.h | 350 + .../freetype/include/freetype/fttrigon.h | 350 + .../freetype/include/freetype/fttypes.h | 617 ++ .../freetype/include/freetype/ftwinfnt.h | 276 + .../include/freetype/internal/autohint.h | 234 + .../include/freetype/internal/cffotypes.h | 107 + .../include/freetype/internal/cfftypes.h | 416 + .../freetype/internal/compiler-macros.h | 343 + .../include/freetype/internal/ftcalc.h | 584 + .../include/freetype/internal/ftdebug.h | 442 + .../include/freetype/internal/ftdrv.h | 289 + .../include/freetype/internal/ftgloadr.h | 147 + .../include/freetype/internal/fthash.h | 135 + .../include/freetype/internal/ftmemory.h | 401 + .../include/freetype/internal/ftmmtypes.h | 91 + .../include/freetype/internal/ftobjs.h | 1232 +++ .../include/freetype/internal/ftpsprop.h | 47 + .../include/freetype/internal/ftrfork.h | 245 + .../include/freetype/internal/ftserv.h | 495 + .../include/freetype/internal/ftstream.h | 570 + .../include/freetype/internal/fttrace.h | 173 + .../include/freetype/internal/ftvalid.h | 160 + .../include/freetype/internal/psaux.h | 1447 +++ .../include/freetype/internal/pshints.h | 699 ++ .../freetype/internal/services/svbdf.h | 66 + .../freetype/internal/services/svcfftl.h | 90 + .../freetype/internal/services/svcid.h | 69 + .../freetype/internal/services/svfntfmt.h | 55 + .../freetype/internal/services/svgldict.h | 72 + .../freetype/internal/services/svgxval.h | 72 + .../freetype/internal/services/svkern.h | 51 + .../freetype/internal/services/svmetric.h | 131 + .../include/freetype/internal/services/svmm.h | 214 + .../freetype/internal/services/svotval.h | 55 + .../freetype/internal/services/svpfr.h | 65 + .../freetype/internal/services/svpostnm.h | 65 + .../freetype/internal/services/svprop.h | 66 + .../freetype/internal/services/svpscmap.h | 145 + .../freetype/internal/services/svpsinfo.h | 86 + .../freetype/internal/services/svsfnt.h | 88 + .../freetype/internal/services/svttcmap.h | 90 + .../freetype/internal/services/svtteng.h | 53 + .../freetype/internal/services/svttglyf.h | 56 + .../freetype/internal/services/svwinfnt.h | 50 + .../freetype/include/freetype/internal/sfnt.h | 1099 ++ .../include/freetype/internal/svginterface.h | 46 + .../include/freetype/internal/t1types.h | 307 + .../include/freetype/internal/tttypes.h | 1747 +++ .../include/freetype/internal/wofftypes.h | 312 + .../freetype/include/freetype/otsvg.h | 336 + .../freetype/include/freetype/t1tables.h | 735 ++ .../freetype/include/freetype/ttnameid.h | 1235 +++ .../freetype/include/freetype/tttables.h | 856 ++ .../freetype/include/freetype/tttags.h | 124 + .../freetype/freetype/include/ft2build.h | 42 + Dependencies/freetype/freetype/modules.cfg | 253 + .../freetype/freetype/src/autofit/afblue.c | 779 ++ .../freetype/freetype/src/autofit/afblue.cin | 39 + .../freetype/freetype/src/autofit/afblue.dat | 1121 ++ .../freetype/freetype/src/autofit/afblue.h | 429 + .../freetype/freetype/src/autofit/afblue.hin | 146 + .../freetype/freetype/src/autofit/afcjk.c | 2383 +++++ .../freetype/freetype/src/autofit/afcjk.h | 141 + .../freetype/freetype/src/autofit/afcover.h | 105 + .../freetype/freetype/src/autofit/afdummy.c | 77 + .../freetype/freetype/src/autofit/afdummy.h | 40 + .../freetype/freetype/src/autofit/aferrors.h | 42 + .../freetype/freetype/src/autofit/afglobal.c | 513 + .../freetype/freetype/src/autofit/afglobal.h | 173 + .../freetype/freetype/src/autofit/afhints.c | 1796 ++++ .../freetype/freetype/src/autofit/afhints.h | 467 + .../freetype/freetype/src/autofit/afindic.c | 157 + .../freetype/freetype/src/autofit/afindic.h | 41 + .../freetype/freetype/src/autofit/aflatin.c | 3643 +++++++ .../freetype/freetype/src/autofit/aflatin.h | 194 + .../freetype/freetype/src/autofit/afloader.c | 706 ++ .../freetype/freetype/src/autofit/afloader.h | 91 + .../freetype/freetype/src/autofit/afmodule.c | 527 + .../freetype/freetype/src/autofit/afmodule.h | 55 + .../freetype/freetype/src/autofit/afranges.c | 1072 ++ .../freetype/freetype/src/autofit/afranges.h | 47 + .../freetype/freetype/src/autofit/afscript.h | 408 + .../freetype/freetype/src/autofit/afshaper.c | 690 ++ .../freetype/freetype/src/autofit/afshaper.h | 71 + .../freetype/freetype/src/autofit/afstyles.h | 487 + .../freetype/freetype/src/autofit/aftypes.h | 511 + .../freetype/freetype/src/autofit/afws-decl.h | 33 + .../freetype/freetype/src/autofit/afws-iter.h | 31 + .../freetype/freetype/src/autofit/autofit.c | 35 + .../freetype/freetype/src/autofit/ft-hb.c | 115 + .../freetype/freetype/src/autofit/ft-hb.h | 48 + .../freetype/freetype/src/base/ftadvanc.c | 174 + .../freetype/freetype/src/base/ftbase.c | 41 + .../freetype/freetype/src/base/ftbase.h | 82 + .../freetype/freetype/src/base/ftbbox.c | 542 + .../freetype/freetype/src/base/ftbdf.c | 90 + .../freetype/freetype/src/base/ftbitmap.c | 1144 ++ .../freetype/freetype/src/base/ftcalc.c | 1126 ++ .../freetype/freetype/src/base/ftcid.c | 117 + .../freetype/freetype/src/base/ftcolor.c | 156 + .../freetype/freetype/src/base/ftdbgmem.c | 971 ++ .../freetype/freetype/src/base/ftdebug.c | 644 ++ .../freetype/freetype/src/base/fterrors.c | 45 + .../freetype/freetype/src/base/ftfntfmt.c | 54 + .../freetype/freetype/src/base/ftfstype.c | 61 + .../freetype/freetype/src/base/ftgasp.c | 60 + .../freetype/freetype/src/base/ftgloadr.c | 383 + .../freetype/freetype/src/base/ftglyph.c | 911 ++ .../freetype/freetype/src/base/ftgxval.c | 141 + .../freetype/freetype/src/base/fthash.c | 338 + .../freetype/freetype/src/base/ftinit.c | 263 + .../freetype/freetype/src/base/ftlcdfil.c | 437 + .../freetype/freetype/src/base/ftmac.c | 1099 ++ .../freetype/freetype/src/base/ftmm.c | 704 ++ .../freetype/freetype/src/base/ftobjs.c | 5917 +++++++++++ .../freetype/freetype/src/base/ftotval.c | 90 + .../freetype/freetype/src/base/ftoutln.c | 1120 ++ .../freetype/freetype/src/base/ftpatent.c | 50 + .../freetype/freetype/src/base/ftpfr.c | 152 + .../freetype/freetype/src/base/ftpsprop.c | 284 + .../freetype/freetype/src/base/ftrfork.c | 934 ++ .../freetype/freetype/src/base/ftsnames.c | 185 + .../freetype/freetype/src/base/ftstream.c | 872 ++ .../freetype/freetype/src/base/ftstroke.c | 2403 +++++ .../freetype/freetype/src/base/ftsynth.c | 180 + .../freetype/freetype/src/base/ftsystem.c | 338 + .../freetype/freetype/src/base/fttrigon.c | 517 + .../freetype/freetype/src/base/fttype1.c | 126 + .../freetype/freetype/src/base/ftutil.c | 442 + .../freetype/freetype/src/base/ftver.rc | 61 + .../freetype/freetype/src/base/ftwinfnt.c | 52 + Dependencies/freetype/freetype/src/base/md5.c | 291 + Dependencies/freetype/freetype/src/base/md5.h | 45 + Dependencies/freetype/freetype/src/bdf/README | 152 + Dependencies/freetype/freetype/src/bdf/bdf.c | 34 + Dependencies/freetype/freetype/src/bdf/bdf.h | 253 + .../freetype/freetype/src/bdf/bdfdrivr.c | 1013 ++ .../freetype/freetype/src/bdf/bdfdrivr.h | 72 + .../freetype/freetype/src/bdf/bdferror.h | 45 + .../freetype/freetype/src/bdf/bdflib.c | 2378 +++++ .../freetype/freetype/src/bzip2/ftbzip2.c | 535 + .../freetype/freetype/src/cache/ftcache.c | 31 + .../freetype/freetype/src/cache/ftcbasic.c | 598 ++ .../freetype/freetype/src/cache/ftccache.c | 584 + .../freetype/freetype/src/cache/ftccache.h | 359 + .../freetype/freetype/src/cache/ftccback.h | 85 + .../freetype/freetype/src/cache/ftccmap.c | 323 + .../freetype/freetype/src/cache/ftcerror.h | 42 + .../freetype/freetype/src/cache/ftcglyph.c | 204 + .../freetype/freetype/src/cache/ftcglyph.h | 314 + .../freetype/freetype/src/cache/ftcimage.c | 158 + .../freetype/freetype/src/cache/ftcimage.h | 106 + .../freetype/freetype/src/cache/ftcmanag.c | 677 ++ .../freetype/freetype/src/cache/ftcmanag.h | 175 + .../freetype/freetype/src/cache/ftcmru.c | 341 + .../freetype/freetype/src/cache/ftcmru.h | 242 + .../freetype/freetype/src/cache/ftcsbits.c | 413 + .../freetype/freetype/src/cache/ftcsbits.h | 91 + Dependencies/freetype/freetype/src/cff/cff.c | 28 + .../freetype/freetype/src/cff/cffcmap.c | 230 + .../freetype/freetype/src/cff/cffcmap.h | 67 + .../freetype/freetype/src/cff/cffdrivr.c | 1263 +++ .../freetype/freetype/src/cff/cffdrivr.h | 35 + .../freetype/freetype/src/cff/cfferrs.h | 42 + .../freetype/freetype/src/cff/cffgload.c | 762 ++ .../freetype/freetype/src/cff/cffgload.h | 62 + .../freetype/freetype/src/cff/cffload.c | 2570 +++++ .../freetype/freetype/src/cff/cffload.h | 124 + .../freetype/freetype/src/cff/cffobjs.c | 1175 ++ .../freetype/freetype/src/cff/cffobjs.h | 84 + .../freetype/freetype/src/cff/cffparse.c | 1550 +++ .../freetype/freetype/src/cff/cffparse.h | 144 + .../freetype/freetype/src/cff/cfftoken.h | 150 + .../freetype/freetype/src/cid/ciderrs.h | 41 + .../freetype/freetype/src/cid/cidgload.c | 618 ++ .../freetype/freetype/src/cid/cidgload.h | 58 + .../freetype/freetype/src/cid/cidload.c | 937 ++ .../freetype/freetype/src/cid/cidload.h | 52 + .../freetype/freetype/src/cid/cidobjs.c | 543 + .../freetype/freetype/src/cid/cidobjs.h | 154 + .../freetype/freetype/src/cid/cidparse.c | 311 + .../freetype/freetype/src/cid/cidparse.h | 130 + .../freetype/freetype/src/cid/cidriver.c | 274 + .../freetype/freetype/src/cid/cidriver.h | 36 + .../freetype/freetype/src/cid/cidtoken.h | 115 + .../freetype/freetype/src/cid/type1cid.c | 28 + Dependencies/freetype/freetype/src/dlg/dlg.c | 803 ++ .../freetype/freetype/src/dlg/dlgwrap.c | 32 + .../freetype/freetype/src/gxvalid/README | 532 + .../freetype/freetype/src/gxvalid/gxvalid.c | 46 + .../freetype/freetype/src/gxvalid/gxvalid.h | 107 + .../freetype/freetype/src/gxvalid/gxvbsln.c | 334 + .../freetype/freetype/src/gxvalid/gxvcommn.c | 1747 +++ .../freetype/freetype/src/gxvalid/gxvcommn.h | 581 + .../freetype/freetype/src/gxvalid/gxverror.h | 51 + .../freetype/freetype/src/gxvalid/gxvfeat.c | 339 + .../freetype/freetype/src/gxvalid/gxvfeat.h | 173 + .../freetype/freetype/src/gxvalid/gxvfgen.c | 484 + .../freetype/freetype/src/gxvalid/gxvjust.c | 721 ++ .../freetype/freetype/src/gxvalid/gxvkern.c | 920 ++ .../freetype/freetype/src/gxvalid/gxvlcar.c | 224 + .../freetype/freetype/src/gxvalid/gxvmod.c | 288 + .../freetype/freetype/src/gxvalid/gxvmod.h | 46 + .../freetype/freetype/src/gxvalid/gxvmort.c | 301 + .../freetype/freetype/src/gxvalid/gxvmort.h | 99 + .../freetype/freetype/src/gxvalid/gxvmort0.c | 152 + .../freetype/freetype/src/gxvalid/gxvmort1.c | 260 + .../freetype/freetype/src/gxvalid/gxvmort2.c | 312 + .../freetype/freetype/src/gxvalid/gxvmort4.c | 126 + .../freetype/freetype/src/gxvalid/gxvmort5.c | 234 + .../freetype/freetype/src/gxvalid/gxvmorx.c | 199 + .../freetype/freetype/src/gxvalid/gxvmorx.h | 73 + .../freetype/freetype/src/gxvalid/gxvmorx0.c | 112 + .../freetype/freetype/src/gxvalid/gxvmorx1.c | 278 + .../freetype/freetype/src/gxvalid/gxvmorx2.c | 331 + .../freetype/freetype/src/gxvalid/gxvmorx4.c | 56 + .../freetype/freetype/src/gxvalid/gxvmorx5.c | 226 + .../freetype/freetype/src/gxvalid/gxvopbd.c | 218 + .../freetype/freetype/src/gxvalid/gxvprop.c | 330 + .../freetype/freetype/src/gxvalid/gxvtrak.c | 288 + .../freetype/src/gzip/README.freetype | 22 + .../freetype/freetype/src/gzip/adler32.c | 168 + .../freetype/freetype/src/gzip/crc32.c | 1061 ++ .../freetype/freetype/src/gzip/crc32.h | 9446 +++++++++++++++++ .../freetype/freetype/src/gzip/ftgzip.c | 805 ++ .../freetype/freetype/src/gzip/ftzconf.h | 551 + .../freetype/freetype/src/gzip/gzguts.h | 218 + .../freetype/freetype/src/gzip/inffast.c | 320 + .../freetype/freetype/src/gzip/inffast.h | 11 + .../freetype/freetype/src/gzip/inffixed.h | 94 + .../freetype/freetype/src/gzip/inflate.c | 1534 +++ .../freetype/freetype/src/gzip/inflate.h | 131 + .../freetype/freetype/src/gzip/inftrees.c | 299 + .../freetype/freetype/src/gzip/inftrees.h | 67 + .../src/gzip/patches/freetype-zlib.diff | 451 + .../freetype/freetype/src/gzip/zlib.h | 1972 ++++ .../freetype/freetype/src/gzip/zutil.c | 305 + .../freetype/freetype/src/gzip/zutil.h | 281 + .../freetype/freetype/src/lzw/ftlzw.c | 415 + .../freetype/freetype/src/lzw/ftzopen.c | 429 + .../freetype/freetype/src/lzw/ftzopen.h | 174 + .../freetype/freetype/src/otvalid/otvalid.c | 31 + .../freetype/freetype/src/otvalid/otvalid.h | 77 + .../freetype/freetype/src/otvalid/otvbase.c | 345 + .../freetype/freetype/src/otvalid/otvcommn.c | 1099 ++ .../freetype/freetype/src/otvalid/otvcommn.h | 468 + .../freetype/freetype/src/otvalid/otverror.h | 42 + .../freetype/freetype/src/otvalid/otvgdef.c | 303 + .../freetype/freetype/src/otvalid/otvgpos.c | 1051 ++ .../freetype/freetype/src/otvalid/otvgpos.h | 36 + .../freetype/freetype/src/otvalid/otvgsub.c | 627 ++ .../freetype/freetype/src/otvalid/otvjstf.c | 259 + .../freetype/freetype/src/otvalid/otvmath.c | 453 + .../freetype/freetype/src/otvalid/otvmod.c | 281 + .../freetype/freetype/src/otvalid/otvmod.h | 38 + Dependencies/freetype/freetype/src/pcf/README | 96 + Dependencies/freetype/freetype/src/pcf/pcf.c | 35 + Dependencies/freetype/freetype/src/pcf/pcf.h | 251 + .../freetype/freetype/src/pcf/pcfdrivr.c | 836 ++ .../freetype/freetype/src/pcf/pcfdrivr.h | 44 + .../freetype/freetype/src/pcf/pcferror.h | 41 + .../freetype/freetype/src/pcf/pcfread.c | 1731 +++ .../freetype/freetype/src/pcf/pcfread.h | 44 + .../freetype/freetype/src/pcf/pcfutil.c | 119 + .../freetype/freetype/src/pcf/pcfutil.h | 55 + Dependencies/freetype/freetype/src/pfr/pfr.c | 29 + .../freetype/freetype/src/pfr/pfrcmap.c | 188 + .../freetype/freetype/src/pfr/pfrcmap.h | 45 + .../freetype/freetype/src/pfr/pfrdrivr.c | 212 + .../freetype/freetype/src/pfr/pfrdrivr.h | 36 + .../freetype/freetype/src/pfr/pfrerror.h | 41 + .../freetype/freetype/src/pfr/pfrgload.c | 849 ++ .../freetype/freetype/src/pfr/pfrgload.h | 49 + .../freetype/freetype/src/pfr/pfrload.c | 1062 ++ .../freetype/freetype/src/pfr/pfrload.h | 123 + .../freetype/freetype/src/pfr/pfrobjs.c | 603 ++ .../freetype/freetype/src/pfr/pfrobjs.h | 96 + .../freetype/freetype/src/pfr/pfrsbit.c | 813 ++ .../freetype/freetype/src/pfr/pfrsbit.h | 37 + .../freetype/freetype/src/pfr/pfrtypes.h | 331 + .../freetype/freetype/src/psaux/afmparse.c | 1094 ++ .../freetype/freetype/src/psaux/afmparse.h | 88 + .../freetype/freetype/src/psaux/cffdecode.c | 2411 +++++ .../freetype/freetype/src/psaux/cffdecode.h | 63 + .../freetype/freetype/src/psaux/psarrst.c | 240 + .../freetype/freetype/src/psaux/psarrst.h | 99 + .../freetype/freetype/src/psaux/psaux.c | 40 + .../freetype/freetype/src/psaux/psauxerr.h | 42 + .../freetype/freetype/src/psaux/psauxmod.c | 190 + .../freetype/freetype/src/psaux/psauxmod.h | 60 + .../freetype/freetype/src/psaux/psblues.c | 571 + .../freetype/freetype/src/psaux/psblues.h | 185 + .../freetype/freetype/src/psaux/psconv.c | 610 ++ .../freetype/freetype/src/psaux/psconv.h | 70 + .../freetype/freetype/src/psaux/pserror.c | 52 + .../freetype/freetype/src/psaux/pserror.h | 120 + .../freetype/freetype/src/psaux/psfixed.h | 94 + .../freetype/freetype/src/psaux/psfont.c | 566 + .../freetype/freetype/src/psaux/psfont.h | 134 + .../freetype/freetype/src/psaux/psft.c | 895 ++ .../freetype/freetype/src/psaux/psft.h | 167 + .../freetype/freetype/src/psaux/psglue.h | 144 + .../freetype/freetype/src/psaux/pshints.c | 1952 ++++ .../freetype/freetype/src/psaux/pshints.h | 288 + .../freetype/freetype/src/psaux/psintrp.c | 3050 ++++++ .../freetype/freetype/src/psaux/psintrp.h | 83 + .../freetype/freetype/src/psaux/psobjs.c | 2560 +++++ .../freetype/freetype/src/psaux/psobjs.h | 312 + .../freetype/freetype/src/psaux/psread.c | 112 + .../freetype/freetype/src/psaux/psread.h | 68 + .../freetype/freetype/src/psaux/psstack.c | 329 + .../freetype/freetype/src/psaux/psstack.h | 122 + .../freetype/freetype/src/psaux/pstypes.h | 77 + .../freetype/freetype/src/psaux/t1cmap.c | 393 + .../freetype/freetype/src/psaux/t1cmap.h | 104 + .../freetype/freetype/src/psaux/t1decode.c | 2159 ++++ .../freetype/freetype/src/psaux/t1decode.h | 73 + .../freetype/freetype/src/pshinter/pshalgo.c | 2191 ++++ .../freetype/freetype/src/pshinter/pshalgo.h | 233 + .../freetype/freetype/src/pshinter/pshglob.c | 795 ++ .../freetype/freetype/src/pshinter/pshglob.h | 196 + .../freetype/freetype/src/pshinter/pshinter.c | 27 + .../freetype/freetype/src/pshinter/pshmod.c | 125 + .../freetype/freetype/src/pshinter/pshmod.h | 38 + .../freetype/freetype/src/pshinter/pshnterr.h | 41 + .../freetype/freetype/src/pshinter/pshrec.c | 1224 +++ .../freetype/freetype/src/pshinter/pshrec.h | 171 + .../freetype/freetype/src/psnames/psmodule.c | 621 ++ .../freetype/freetype/src/psnames/psmodule.h | 37 + .../freetype/freetype/src/psnames/psnamerr.h | 42 + .../freetype/freetype/src/psnames/psnames.c | 24 + .../freetype/freetype/src/psnames/pstables.h | 4238 ++++++++ .../freetype/freetype/src/raster/ftmisc.h | 118 + .../freetype/freetype/src/raster/ftraster.c | 2738 +++++ .../freetype/freetype/src/raster/ftraster.h | 47 + .../freetype/freetype/src/raster/ftrend1.c | 209 + .../freetype/freetype/src/raster/ftrend1.h | 37 + .../freetype/freetype/src/raster/raster.c | 25 + .../freetype/freetype/src/raster/rasterrs.h | 42 + .../freetype/freetype/src/sdf/ftbsdf.c | 1350 +++ .../freetype/freetype/src/sdf/ftsdf.c | 3932 +++++++ .../freetype/freetype/src/sdf/ftsdf.h | 97 + .../freetype/freetype/src/sdf/ftsdfcommon.c | 104 + .../freetype/freetype/src/sdf/ftsdfcommon.h | 140 + .../freetype/freetype/src/sdf/ftsdferrs.h | 37 + .../freetype/freetype/src/sdf/ftsdfrend.c | 603 ++ .../freetype/freetype/src/sdf/ftsdfrend.h | 118 + Dependencies/freetype/freetype/src/sdf/sdf.c | 29 + .../freetype/freetype/src/sfnt/pngshim.c | 462 + .../freetype/freetype/src/sfnt/pngshim.h | 50 + .../freetype/freetype/src/sfnt/sfdriver.c | 1384 +++ .../freetype/freetype/src/sfnt/sfdriver.h | 35 + .../freetype/freetype/src/sfnt/sferrors.h | 41 + .../freetype/freetype/src/sfnt/sfnt.c | 41 + .../freetype/freetype/src/sfnt/sfobjs.c | 1552 +++ .../freetype/freetype/src/sfnt/sfobjs.h | 58 + .../freetype/freetype/src/sfnt/sfwoff.c | 426 + .../freetype/freetype/src/sfnt/sfwoff.h | 43 + .../freetype/freetype/src/sfnt/sfwoff2.c | 2380 +++++ .../freetype/freetype/src/sfnt/sfwoff2.h | 78 + .../freetype/freetype/src/sfnt/ttbdf.c | 257 + .../freetype/freetype/src/sfnt/ttbdf.h | 49 + .../freetype/freetype/src/sfnt/ttcmap.c | 3902 +++++++ .../freetype/freetype/src/sfnt/ttcmap.h | 126 + .../freetype/freetype/src/sfnt/ttcmapc.h | 56 + .../freetype/freetype/src/sfnt/ttcolr.c | 1923 ++++ .../freetype/freetype/src/sfnt/ttcolr.h | 83 + .../freetype/freetype/src/sfnt/ttcpal.c | 310 + .../freetype/freetype/src/sfnt/ttcpal.h | 48 + .../freetype/freetype/src/sfnt/ttgpos.c | 598 ++ .../freetype/freetype/src/sfnt/ttgpos.h | 53 + .../freetype/freetype/src/sfnt/ttkern.c | 317 + .../freetype/freetype/src/sfnt/ttkern.h | 51 + .../freetype/freetype/src/sfnt/ttload.c | 1496 +++ .../freetype/freetype/src/sfnt/ttload.h | 111 + .../freetype/freetype/src/sfnt/ttmtx.c | 338 + .../freetype/freetype/src/sfnt/ttmtx.h | 54 + .../freetype/freetype/src/sfnt/ttpost.c | 484 + .../freetype/freetype/src/sfnt/ttpost.h | 46 + .../freetype/freetype/src/sfnt/ttsbit.c | 1685 +++ .../freetype/freetype/src/sfnt/ttsbit.h | 62 + .../freetype/freetype/src/sfnt/ttsvg.c | 413 + .../freetype/freetype/src/sfnt/ttsvg.h | 43 + .../freetype/freetype/src/sfnt/woff2tags.c | 119 + .../freetype/freetype/src/sfnt/woff2tags.h | 41 + .../freetype/freetype/src/smooth/ftgrays.c | 2149 ++++ .../freetype/freetype/src/smooth/ftgrays.h | 57 + .../freetype/freetype/src/smooth/ftsmerrs.h | 42 + .../freetype/freetype/src/smooth/ftsmooth.c | 605 ++ .../freetype/freetype/src/smooth/ftsmooth.h | 37 + .../freetype/freetype/src/smooth/smooth.c | 25 + .../freetype/freetype/src/svg/ftsvg.c | 355 + .../freetype/freetype/src/svg/ftsvg.h | 35 + Dependencies/freetype/freetype/src/svg/svg.c | 24 + .../freetype/freetype/src/svg/svgtypes.h | 42 + .../freetype/freetype/src/tools/afblue.pl | 551 + .../freetype/freetype/src/tools/apinames.c | 556 + .../freetype/freetype/src/tools/chktrcmp.py | 119 + .../freetype/freetype/src/tools/cordic.py | 32 + .../freetype/src/tools/ftrandom/Makefile | 45 + .../freetype/src/tools/ftrandom/README | 69 + .../freetype/src/tools/ftrandom/ftrandom.c | 720 ++ .../freetype/freetype/src/tools/glnames.py | 5533 ++++++++++ .../src/tools/make_distribution_archives.py | 208 + .../freetype/freetype/src/tools/no-copyright | 66 + .../freetype/freetype/src/tools/test_afm.c | 156 + .../freetype/freetype/src/tools/test_bbox.c | 187 + .../freetype/freetype/src/tools/test_trig.c | 257 + .../freetype/src/tools/update-copyright | 14 + .../freetype/src/tools/update-copyright-year | 157 + .../freetype/src/tools/vms_shorten_symbol.c | 250 + .../freetype/freetype/src/truetype/truetype.c | 29 + .../freetype/freetype/src/truetype/ttdriver.c | 704 ++ .../freetype/freetype/src/truetype/ttdriver.h | 35 + .../freetype/freetype/src/truetype/tterrors.h | 42 + .../freetype/freetype/src/truetype/ttgload.c | 2740 +++++ .../freetype/freetype/src/truetype/ttgload.h | 61 + .../freetype/freetype/src/truetype/ttgxvar.c | 4594 ++++++++ .../freetype/freetype/src/truetype/ttgxvar.h | 453 + .../freetype/freetype/src/truetype/ttinterp.c | 7751 ++++++++++++++ .../freetype/freetype/src/truetype/ttinterp.h | 465 + .../freetype/freetype/src/truetype/ttobjs.c | 1543 +++ .../freetype/freetype/src/truetype/ttobjs.h | 426 + .../freetype/freetype/src/truetype/ttpload.c | 665 ++ .../freetype/freetype/src/truetype/ttpload.h | 74 + .../freetype/freetype/src/type1/t1afm.c | 413 + .../freetype/freetype/src/type1/t1afm.h | 53 + .../freetype/freetype/src/type1/t1driver.c | 807 ++ .../freetype/freetype/src/type1/t1driver.h | 35 + .../freetype/freetype/src/type1/t1errors.h | 41 + .../freetype/freetype/src/type1/t1gload.c | 606 ++ .../freetype/freetype/src/type1/t1gload.h | 52 + .../freetype/freetype/src/type1/t1load.c | 2755 +++++ .../freetype/freetype/src/type1/t1load.h | 126 + .../freetype/freetype/src/type1/t1objs.c | 655 ++ .../freetype/freetype/src/type1/t1objs.h | 160 + .../freetype/freetype/src/type1/t1parse.c | 487 + .../freetype/freetype/src/type1/t1parse.h | 137 + .../freetype/freetype/src/type1/t1tokens.h | 143 + .../freetype/freetype/src/type1/type1.c | 29 + .../freetype/freetype/src/type42/t42drivr.c | 248 + .../freetype/freetype/src/type42/t42drivr.h | 36 + .../freetype/freetype/src/type42/t42error.h | 41 + .../freetype/freetype/src/type42/t42objs.c | 698 ++ .../freetype/freetype/src/type42/t42objs.h | 123 + .../freetype/freetype/src/type42/t42parse.c | 1351 +++ .../freetype/freetype/src/type42/t42parse.h | 91 + .../freetype/freetype/src/type42/t42types.h | 56 + .../freetype/freetype/src/type42/type42.c | 26 + .../freetype/freetype/src/winfonts/fnterrs.h | 42 + .../freetype/freetype/src/winfonts/winfnt.c | 1219 +++ .../freetype/freetype/src/winfonts/winfnt.h | 164 + Dependencies/msdf-atlas-gen/.gitattributes | 1 + Dependencies/msdf-atlas-gen/.gitignore | 26 + Dependencies/msdf-atlas-gen/.gitmodules | 6 + Dependencies/msdf-atlas-gen/CHANGELOG.md | 55 + Dependencies/msdf-atlas-gen/CMakeLists.txt | 207 + Dependencies/msdf-atlas-gen/CMakePresets.json | 155 + Dependencies/msdf-atlas-gen/LICENSE.txt | 21 + Dependencies/msdf-atlas-gen/README.md | 277 + .../msdf-atlas-gen/cmake/CMakePresets.json | 154 + .../cmake/msdf-atlas-gen-config.cmake.in | 21 + .../msdf-atlas-gen/cmake/version.cmake | 19 + Dependencies/msdf-atlas-gen/icon.ico | Bin 0 -> 32038 bytes Dependencies/msdf-atlas-gen/msdf-atlas-gen | 1 + .../msdf-atlas-gen/msdf-atlas-gen.lua | 76 + Dependencies/msdf-atlas-gen/msdf-atlas-gen.rc | Bin 0 -> 4676 bytes Dependencies/msdf-atlas-gen/resource.h | Bin 0 -> 1336 bytes Dependencies/msdf-atlas-gen/vcpkg.json | 24 + Dependencies/msdfgen/msdfgen.lua | 98 + Dependencies/msdfgen/msdfgen/.gitattributes | 1 + Dependencies/msdfgen/msdfgen/.gitignore | 32 + Dependencies/msdfgen/msdfgen/CHANGELOG.md | 134 + Dependencies/msdfgen/msdfgen/CMakeLists.txt | 328 + .../msdfgen/msdfgen/CMakePresets.json | 239 + Dependencies/msdfgen/msdfgen/LICENSE.txt | 21 + Dependencies/msdfgen/msdfgen/README.md | 215 + .../msdfgen/msdfgen/build-release.bat | 96 + .../msdfgen/msdfgen/cmake/CMakePresets.json | 170 + .../msdfgen/msdfgen/cmake/msdfgen-config.h.in | 12 + .../msdfgen/cmake/msdfgenConfig.cmake.in | 48 + .../msdfgen/msdfgen/cmake/version.cmake | 19 + Dependencies/msdfgen/msdfgen/core/Bitmap.h | 50 + Dependencies/msdfgen/msdfgen/core/Bitmap.hpp | 117 + .../msdfgen/msdfgen/core/BitmapRef.hpp | 41 + Dependencies/msdfgen/msdfgen/core/Contour.cpp | 90 + Dependencies/msdfgen/msdfgen/core/Contour.h | 34 + .../msdfgen/msdfgen/core/DistanceMapping.cpp | 27 + .../msdfgen/msdfgen/core/DistanceMapping.h | 36 + Dependencies/msdfgen/msdfgen/core/EdgeColor.h | 20 + .../msdfgen/msdfgen/core/EdgeHolder.cpp | 67 + .../msdfgen/msdfgen/core/EdgeHolder.h | 41 + .../msdfgen/core/MSDFErrorCorrection.cpp | 494 + .../msdfgen/core/MSDFErrorCorrection.h | 55 + .../msdfgen/msdfgen/core/Projection.cpp | 42 + .../msdfgen/msdfgen/core/Projection.h | 37 + Dependencies/msdfgen/msdfgen/core/Range.hpp | 46 + .../msdfgen/msdfgen/core/SDFTransformation.h | 24 + .../msdfgen/msdfgen/core/Scanline.cpp | 125 + Dependencies/msdfgen/msdfgen/core/Scanline.h | 56 + Dependencies/msdfgen/msdfgen/core/Shape.cpp | 200 + Dependencies/msdfgen/msdfgen/core/Shape.h | 53 + .../msdfgen/core/ShapeDistanceFinder.h | 37 + .../msdfgen/core/ShapeDistanceFinder.hpp | 60 + .../msdfgen/msdfgen/core/SignedDistance.hpp | 38 + Dependencies/msdfgen/msdfgen/core/Vector2.hpp | 167 + .../msdfgen/msdfgen/core/arithmetics.hpp | 63 + Dependencies/msdfgen/msdfgen/core/base.h | 16 + .../msdfgen/core/bitmap-interpolation.hpp | 25 + .../msdfgen/core/contour-combiners.cpp | 141 + .../msdfgen/msdfgen/core/contour-combiners.h | 47 + .../msdfgen/msdfgen/core/edge-coloring.cpp | 531 + .../msdfgen/msdfgen/core/edge-coloring.h | 29 + .../msdfgen/msdfgen/core/edge-segments.cpp | 527 + .../msdfgen/msdfgen/core/edge-segments.h | 146 + .../msdfgen/msdfgen/core/edge-selectors.cpp | 261 + .../msdfgen/msdfgen/core/edge-selectors.h | 117 + .../msdfgen/msdfgen/core/equation-solver.cpp | 72 + .../msdfgen/msdfgen/core/equation-solver.h | 14 + .../msdfgen/msdfgen/core/export-svg.cpp | 79 + .../msdfgen/msdfgen/core/export-svg.h | 11 + .../msdfgen/msdfgen/core/generator-config.h | 66 + .../msdfgen/core/msdf-error-correction.cpp | 172 + .../msdfgen/core/msdf-error-correction.h | 36 + Dependencies/msdfgen/msdfgen/core/msdfgen.cpp | 334 + .../msdfgen/msdfgen/core/pixel-conversion.hpp | 16 + .../msdfgen/msdfgen/core/rasterization.cpp | 115 + .../msdfgen/msdfgen/core/rasterization.h | 25 + .../msdfgen/msdfgen/core/render-sdf.cpp | 194 + .../msdfgen/msdfgen/core/render-sdf.h | 23 + .../msdfgen/msdfgen/core/save-bmp.cpp | 171 + Dependencies/msdfgen/msdfgen/core/save-bmp.h | 16 + .../msdfgen/msdfgen/core/save-fl32.cpp | 39 + Dependencies/msdfgen/msdfgen/core/save-fl32.h | 12 + .../msdfgen/msdfgen/core/save-rgba.cpp | 133 + Dependencies/msdfgen/msdfgen/core/save-rgba.h | 16 + .../msdfgen/msdfgen/core/save-tiff.cpp | 192 + Dependencies/msdfgen/msdfgen/core/save-tiff.h | 13 + .../msdfgen/core/sdf-error-estimation.cpp | 192 + .../msdfgen/core/sdf-error-estimation.h | 30 + .../msdfgen/core/shape-description.cpp | 300 + .../msdfgen/msdfgen/core/shape-description.h | 15 + .../msdfgen/msdfgen/ext/import-font.cpp | 315 + .../msdfgen/msdfgen/ext/import-font.h | 103 + .../msdfgen/msdfgen/ext/import-svg.cpp | 1060 ++ Dependencies/msdfgen/msdfgen/ext/import-svg.h | 32 + .../msdfgen/ext/resolve-shape-geometry.cpp | 130 + .../msdfgen/ext/resolve-shape-geometry.h | 15 + Dependencies/msdfgen/msdfgen/ext/save-png.cpp | 173 + Dependencies/msdfgen/msdfgen/ext/save-png.h | 20 + Dependencies/msdfgen/msdfgen/icon.ico | Bin 0 -> 32038 bytes Dependencies/msdfgen/msdfgen/main.cpp | 1387 +++ Dependencies/msdfgen/msdfgen/msdfgen-config.h | 11 + Dependencies/msdfgen/msdfgen/msdfgen-ext.h | 27 + Dependencies/msdfgen/msdfgen/msdfgen.h | 78 + Dependencies/msdfgen/msdfgen/msdfgen.rc | Bin 0 -> 4568 bytes Dependencies/msdfgen/msdfgen/resource.h | Bin 0 -> 1298 bytes Dependencies/msdfgen/msdfgen/vcpkg.json | 38 + 613 files changed, 260398 insertions(+), 1 deletion(-) create mode 100644 Dependencies/freetype/freetype.lua create mode 100644 Dependencies/freetype/freetype/.clang-format create mode 100644 Dependencies/freetype/freetype/LICENSE.TXT create mode 100644 Dependencies/freetype/freetype/README create mode 100644 Dependencies/freetype/freetype/README.git create mode 100644 Dependencies/freetype/freetype/devel/ft2build.h create mode 100644 Dependencies/freetype/freetype/devel/ftoption.h create mode 100644 Dependencies/freetype/freetype/include/dlg/dlg.h create mode 100644 Dependencies/freetype/freetype/include/dlg/output.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/ftconfig.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/ftheader.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/ftmodule.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/ftoption.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/ftstdlib.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/integer-types.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/mac-support.h create mode 100644 Dependencies/freetype/freetype/include/freetype/config/public-macros.h create mode 100644 Dependencies/freetype/freetype/include/freetype/freetype.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftadvanc.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftbbox.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftbdf.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftbitmap.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftbzip2.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftcache.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftchapters.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftcid.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftcolor.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftdriver.h create mode 100644 Dependencies/freetype/freetype/include/freetype/fterrdef.h create mode 100644 Dependencies/freetype/freetype/include/freetype/fterrors.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftfntfmt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftgasp.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftglyph.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftgxval.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftgzip.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftimage.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftincrem.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftlcdfil.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftlist.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftlogging.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftlzw.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftmac.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftmm.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftmodapi.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftmoderr.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftotval.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftoutln.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftparams.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftpfr.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftrender.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftsizes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftsnames.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftstroke.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftsynth.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftsystem.h create mode 100644 Dependencies/freetype/freetype/include/freetype/fttrigon.h create mode 100644 Dependencies/freetype/freetype/include/freetype/fttypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ftwinfnt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/autohint.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/cffotypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/cfftypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/compiler-macros.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftcalc.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftdebug.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftdrv.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftgloadr.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/fthash.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftmemory.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftmmtypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftobjs.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftpsprop.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftrfork.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftserv.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftstream.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/fttrace.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/ftvalid.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/psaux.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/pshints.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svbdf.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svcfftl.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svcid.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svfntfmt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svgldict.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svgxval.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svkern.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svmetric.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svmm.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svotval.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svpfr.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svpostnm.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svprop.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svpscmap.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svpsinfo.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svsfnt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svttcmap.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svtteng.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svttglyf.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/services/svwinfnt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/sfnt.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/svginterface.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/t1types.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/tttypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/internal/wofftypes.h create mode 100644 Dependencies/freetype/freetype/include/freetype/otsvg.h create mode 100644 Dependencies/freetype/freetype/include/freetype/t1tables.h create mode 100644 Dependencies/freetype/freetype/include/freetype/ttnameid.h create mode 100644 Dependencies/freetype/freetype/include/freetype/tttables.h create mode 100644 Dependencies/freetype/freetype/include/freetype/tttags.h create mode 100644 Dependencies/freetype/freetype/include/ft2build.h create mode 100644 Dependencies/freetype/freetype/modules.cfg create mode 100644 Dependencies/freetype/freetype/src/autofit/afblue.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afblue.cin create mode 100644 Dependencies/freetype/freetype/src/autofit/afblue.dat create mode 100644 Dependencies/freetype/freetype/src/autofit/afblue.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afblue.hin create mode 100644 Dependencies/freetype/freetype/src/autofit/afcjk.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afcjk.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afcover.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afdummy.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afdummy.h create mode 100644 Dependencies/freetype/freetype/src/autofit/aferrors.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afglobal.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afglobal.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afhints.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afhints.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afindic.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afindic.h create mode 100644 Dependencies/freetype/freetype/src/autofit/aflatin.c create mode 100644 Dependencies/freetype/freetype/src/autofit/aflatin.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afloader.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afloader.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afmodule.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afmodule.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afranges.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afranges.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afscript.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afshaper.c create mode 100644 Dependencies/freetype/freetype/src/autofit/afshaper.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afstyles.h create mode 100644 Dependencies/freetype/freetype/src/autofit/aftypes.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afws-decl.h create mode 100644 Dependencies/freetype/freetype/src/autofit/afws-iter.h create mode 100644 Dependencies/freetype/freetype/src/autofit/autofit.c create mode 100644 Dependencies/freetype/freetype/src/autofit/ft-hb.c create mode 100644 Dependencies/freetype/freetype/src/autofit/ft-hb.h create mode 100644 Dependencies/freetype/freetype/src/base/ftadvanc.c create mode 100644 Dependencies/freetype/freetype/src/base/ftbase.c create mode 100644 Dependencies/freetype/freetype/src/base/ftbase.h create mode 100644 Dependencies/freetype/freetype/src/base/ftbbox.c create mode 100644 Dependencies/freetype/freetype/src/base/ftbdf.c create mode 100644 Dependencies/freetype/freetype/src/base/ftbitmap.c create mode 100644 Dependencies/freetype/freetype/src/base/ftcalc.c create mode 100644 Dependencies/freetype/freetype/src/base/ftcid.c create mode 100644 Dependencies/freetype/freetype/src/base/ftcolor.c create mode 100644 Dependencies/freetype/freetype/src/base/ftdbgmem.c create mode 100644 Dependencies/freetype/freetype/src/base/ftdebug.c create mode 100644 Dependencies/freetype/freetype/src/base/fterrors.c create mode 100644 Dependencies/freetype/freetype/src/base/ftfntfmt.c create mode 100644 Dependencies/freetype/freetype/src/base/ftfstype.c create mode 100644 Dependencies/freetype/freetype/src/base/ftgasp.c create mode 100644 Dependencies/freetype/freetype/src/base/ftgloadr.c create mode 100644 Dependencies/freetype/freetype/src/base/ftglyph.c create mode 100644 Dependencies/freetype/freetype/src/base/ftgxval.c create mode 100644 Dependencies/freetype/freetype/src/base/fthash.c create mode 100644 Dependencies/freetype/freetype/src/base/ftinit.c create mode 100644 Dependencies/freetype/freetype/src/base/ftlcdfil.c create mode 100644 Dependencies/freetype/freetype/src/base/ftmac.c create mode 100644 Dependencies/freetype/freetype/src/base/ftmm.c create mode 100644 Dependencies/freetype/freetype/src/base/ftobjs.c create mode 100644 Dependencies/freetype/freetype/src/base/ftotval.c create mode 100644 Dependencies/freetype/freetype/src/base/ftoutln.c create mode 100644 Dependencies/freetype/freetype/src/base/ftpatent.c create mode 100644 Dependencies/freetype/freetype/src/base/ftpfr.c create mode 100644 Dependencies/freetype/freetype/src/base/ftpsprop.c create mode 100644 Dependencies/freetype/freetype/src/base/ftrfork.c create mode 100644 Dependencies/freetype/freetype/src/base/ftsnames.c create mode 100644 Dependencies/freetype/freetype/src/base/ftstream.c create mode 100644 Dependencies/freetype/freetype/src/base/ftstroke.c create mode 100644 Dependencies/freetype/freetype/src/base/ftsynth.c create mode 100644 Dependencies/freetype/freetype/src/base/ftsystem.c create mode 100644 Dependencies/freetype/freetype/src/base/fttrigon.c create mode 100644 Dependencies/freetype/freetype/src/base/fttype1.c create mode 100644 Dependencies/freetype/freetype/src/base/ftutil.c create mode 100644 Dependencies/freetype/freetype/src/base/ftver.rc create mode 100644 Dependencies/freetype/freetype/src/base/ftwinfnt.c create mode 100644 Dependencies/freetype/freetype/src/base/md5.c create mode 100644 Dependencies/freetype/freetype/src/base/md5.h create mode 100644 Dependencies/freetype/freetype/src/bdf/README create mode 100644 Dependencies/freetype/freetype/src/bdf/bdf.c create mode 100644 Dependencies/freetype/freetype/src/bdf/bdf.h create mode 100644 Dependencies/freetype/freetype/src/bdf/bdfdrivr.c create mode 100644 Dependencies/freetype/freetype/src/bdf/bdfdrivr.h create mode 100644 Dependencies/freetype/freetype/src/bdf/bdferror.h create mode 100644 Dependencies/freetype/freetype/src/bdf/bdflib.c create mode 100644 Dependencies/freetype/freetype/src/bzip2/ftbzip2.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcache.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcbasic.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftccache.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftccache.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftccback.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftccmap.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcerror.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftcglyph.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcglyph.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftcimage.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcimage.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftcmanag.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcmanag.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftcmru.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcmru.h create mode 100644 Dependencies/freetype/freetype/src/cache/ftcsbits.c create mode 100644 Dependencies/freetype/freetype/src/cache/ftcsbits.h create mode 100644 Dependencies/freetype/freetype/src/cff/cff.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffcmap.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffcmap.h create mode 100644 Dependencies/freetype/freetype/src/cff/cffdrivr.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffdrivr.h create mode 100644 Dependencies/freetype/freetype/src/cff/cfferrs.h create mode 100644 Dependencies/freetype/freetype/src/cff/cffgload.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffgload.h create mode 100644 Dependencies/freetype/freetype/src/cff/cffload.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffload.h create mode 100644 Dependencies/freetype/freetype/src/cff/cffobjs.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffobjs.h create mode 100644 Dependencies/freetype/freetype/src/cff/cffparse.c create mode 100644 Dependencies/freetype/freetype/src/cff/cffparse.h create mode 100644 Dependencies/freetype/freetype/src/cff/cfftoken.h create mode 100644 Dependencies/freetype/freetype/src/cid/ciderrs.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidgload.c create mode 100644 Dependencies/freetype/freetype/src/cid/cidgload.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidload.c create mode 100644 Dependencies/freetype/freetype/src/cid/cidload.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidobjs.c create mode 100644 Dependencies/freetype/freetype/src/cid/cidobjs.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidparse.c create mode 100644 Dependencies/freetype/freetype/src/cid/cidparse.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidriver.c create mode 100644 Dependencies/freetype/freetype/src/cid/cidriver.h create mode 100644 Dependencies/freetype/freetype/src/cid/cidtoken.h create mode 100644 Dependencies/freetype/freetype/src/cid/type1cid.c create mode 100644 Dependencies/freetype/freetype/src/dlg/dlg.c create mode 100644 Dependencies/freetype/freetype/src/dlg/dlgwrap.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/README create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvalid.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvalid.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvbsln.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvcommn.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvcommn.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxverror.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvfeat.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvfeat.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvfgen.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvjust.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvkern.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvlcar.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmod.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmod.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort0.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort1.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort2.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort4.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmort5.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx.h create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx0.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx1.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx2.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx4.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvmorx5.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvopbd.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvprop.c create mode 100644 Dependencies/freetype/freetype/src/gxvalid/gxvtrak.c create mode 100644 Dependencies/freetype/freetype/src/gzip/README.freetype create mode 100644 Dependencies/freetype/freetype/src/gzip/adler32.c create mode 100644 Dependencies/freetype/freetype/src/gzip/crc32.c create mode 100644 Dependencies/freetype/freetype/src/gzip/crc32.h create mode 100644 Dependencies/freetype/freetype/src/gzip/ftgzip.c create mode 100644 Dependencies/freetype/freetype/src/gzip/ftzconf.h create mode 100644 Dependencies/freetype/freetype/src/gzip/gzguts.h create mode 100644 Dependencies/freetype/freetype/src/gzip/inffast.c create mode 100644 Dependencies/freetype/freetype/src/gzip/inffast.h create mode 100644 Dependencies/freetype/freetype/src/gzip/inffixed.h create mode 100644 Dependencies/freetype/freetype/src/gzip/inflate.c create mode 100644 Dependencies/freetype/freetype/src/gzip/inflate.h create mode 100644 Dependencies/freetype/freetype/src/gzip/inftrees.c create mode 100644 Dependencies/freetype/freetype/src/gzip/inftrees.h create mode 100644 Dependencies/freetype/freetype/src/gzip/patches/freetype-zlib.diff create mode 100644 Dependencies/freetype/freetype/src/gzip/zlib.h create mode 100644 Dependencies/freetype/freetype/src/gzip/zutil.c create mode 100644 Dependencies/freetype/freetype/src/gzip/zutil.h create mode 100644 Dependencies/freetype/freetype/src/lzw/ftlzw.c create mode 100644 Dependencies/freetype/freetype/src/lzw/ftzopen.c create mode 100644 Dependencies/freetype/freetype/src/lzw/ftzopen.h create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvalid.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvalid.h create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvbase.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvcommn.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvcommn.h create mode 100644 Dependencies/freetype/freetype/src/otvalid/otverror.h create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvgdef.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvgpos.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvgpos.h create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvgsub.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvjstf.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvmath.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvmod.c create mode 100644 Dependencies/freetype/freetype/src/otvalid/otvmod.h create mode 100644 Dependencies/freetype/freetype/src/pcf/README create mode 100644 Dependencies/freetype/freetype/src/pcf/pcf.c create mode 100644 Dependencies/freetype/freetype/src/pcf/pcf.h create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfdrivr.c create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfdrivr.h create mode 100644 Dependencies/freetype/freetype/src/pcf/pcferror.h create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfread.c create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfread.h create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfutil.c create mode 100644 Dependencies/freetype/freetype/src/pcf/pcfutil.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfr.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrcmap.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrcmap.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrdrivr.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrdrivr.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrerror.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrgload.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrgload.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrload.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrload.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrobjs.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrobjs.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrsbit.c create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrsbit.h create mode 100644 Dependencies/freetype/freetype/src/pfr/pfrtypes.h create mode 100644 Dependencies/freetype/freetype/src/psaux/afmparse.c create mode 100644 Dependencies/freetype/freetype/src/psaux/afmparse.h create mode 100644 Dependencies/freetype/freetype/src/psaux/cffdecode.c create mode 100644 Dependencies/freetype/freetype/src/psaux/cffdecode.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psarrst.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psarrst.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psaux.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psauxerr.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psauxmod.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psauxmod.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psblues.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psblues.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psconv.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psconv.h create mode 100644 Dependencies/freetype/freetype/src/psaux/pserror.c create mode 100644 Dependencies/freetype/freetype/src/psaux/pserror.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psfixed.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psfont.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psfont.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psft.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psft.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psglue.h create mode 100644 Dependencies/freetype/freetype/src/psaux/pshints.c create mode 100644 Dependencies/freetype/freetype/src/psaux/pshints.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psintrp.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psintrp.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psobjs.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psobjs.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psread.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psread.h create mode 100644 Dependencies/freetype/freetype/src/psaux/psstack.c create mode 100644 Dependencies/freetype/freetype/src/psaux/psstack.h create mode 100644 Dependencies/freetype/freetype/src/psaux/pstypes.h create mode 100644 Dependencies/freetype/freetype/src/psaux/t1cmap.c create mode 100644 Dependencies/freetype/freetype/src/psaux/t1cmap.h create mode 100644 Dependencies/freetype/freetype/src/psaux/t1decode.c create mode 100644 Dependencies/freetype/freetype/src/psaux/t1decode.h create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshalgo.c create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshalgo.h create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshglob.c create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshglob.h create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshinter.c create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshmod.c create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshmod.h create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshnterr.h create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshrec.c create mode 100644 Dependencies/freetype/freetype/src/pshinter/pshrec.h create mode 100644 Dependencies/freetype/freetype/src/psnames/psmodule.c create mode 100644 Dependencies/freetype/freetype/src/psnames/psmodule.h create mode 100644 Dependencies/freetype/freetype/src/psnames/psnamerr.h create mode 100644 Dependencies/freetype/freetype/src/psnames/psnames.c create mode 100644 Dependencies/freetype/freetype/src/psnames/pstables.h create mode 100644 Dependencies/freetype/freetype/src/raster/ftmisc.h create mode 100644 Dependencies/freetype/freetype/src/raster/ftraster.c create mode 100644 Dependencies/freetype/freetype/src/raster/ftraster.h create mode 100644 Dependencies/freetype/freetype/src/raster/ftrend1.c create mode 100644 Dependencies/freetype/freetype/src/raster/ftrend1.h create mode 100644 Dependencies/freetype/freetype/src/raster/raster.c create mode 100644 Dependencies/freetype/freetype/src/raster/rasterrs.h create mode 100644 Dependencies/freetype/freetype/src/sdf/ftbsdf.c create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdf.c create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdf.h create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdfcommon.c create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdfcommon.h create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdferrs.h create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdfrend.c create mode 100644 Dependencies/freetype/freetype/src/sdf/ftsdfrend.h create mode 100644 Dependencies/freetype/freetype/src/sdf/sdf.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/pngshim.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/pngshim.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfdriver.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfdriver.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/sferrors.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfnt.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfobjs.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfobjs.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfwoff.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfwoff.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfwoff2.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/sfwoff2.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttbdf.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttbdf.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcmap.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcmap.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcmapc.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcolr.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcolr.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcpal.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttcpal.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttgpos.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttgpos.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttkern.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttkern.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttload.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttload.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttmtx.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttmtx.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttpost.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttpost.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttsbit.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttsbit.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttsvg.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/ttsvg.h create mode 100644 Dependencies/freetype/freetype/src/sfnt/woff2tags.c create mode 100644 Dependencies/freetype/freetype/src/sfnt/woff2tags.h create mode 100644 Dependencies/freetype/freetype/src/smooth/ftgrays.c create mode 100644 Dependencies/freetype/freetype/src/smooth/ftgrays.h create mode 100644 Dependencies/freetype/freetype/src/smooth/ftsmerrs.h create mode 100644 Dependencies/freetype/freetype/src/smooth/ftsmooth.c create mode 100644 Dependencies/freetype/freetype/src/smooth/ftsmooth.h create mode 100644 Dependencies/freetype/freetype/src/smooth/smooth.c create mode 100644 Dependencies/freetype/freetype/src/svg/ftsvg.c create mode 100644 Dependencies/freetype/freetype/src/svg/ftsvg.h create mode 100644 Dependencies/freetype/freetype/src/svg/svg.c create mode 100644 Dependencies/freetype/freetype/src/svg/svgtypes.h create mode 100644 Dependencies/freetype/freetype/src/tools/afblue.pl create mode 100644 Dependencies/freetype/freetype/src/tools/apinames.c create mode 100644 Dependencies/freetype/freetype/src/tools/chktrcmp.py create mode 100644 Dependencies/freetype/freetype/src/tools/cordic.py create mode 100644 Dependencies/freetype/freetype/src/tools/ftrandom/Makefile create mode 100644 Dependencies/freetype/freetype/src/tools/ftrandom/README create mode 100644 Dependencies/freetype/freetype/src/tools/ftrandom/ftrandom.c create mode 100644 Dependencies/freetype/freetype/src/tools/glnames.py create mode 100644 Dependencies/freetype/freetype/src/tools/make_distribution_archives.py create mode 100644 Dependencies/freetype/freetype/src/tools/no-copyright create mode 100644 Dependencies/freetype/freetype/src/tools/test_afm.c create mode 100644 Dependencies/freetype/freetype/src/tools/test_bbox.c create mode 100644 Dependencies/freetype/freetype/src/tools/test_trig.c create mode 100644 Dependencies/freetype/freetype/src/tools/update-copyright create mode 100644 Dependencies/freetype/freetype/src/tools/update-copyright-year create mode 100644 Dependencies/freetype/freetype/src/tools/vms_shorten_symbol.c create mode 100644 Dependencies/freetype/freetype/src/truetype/truetype.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttdriver.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttdriver.h create mode 100644 Dependencies/freetype/freetype/src/truetype/tterrors.h create mode 100644 Dependencies/freetype/freetype/src/truetype/ttgload.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttgload.h create mode 100644 Dependencies/freetype/freetype/src/truetype/ttgxvar.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttgxvar.h create mode 100644 Dependencies/freetype/freetype/src/truetype/ttinterp.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttinterp.h create mode 100644 Dependencies/freetype/freetype/src/truetype/ttobjs.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttobjs.h create mode 100644 Dependencies/freetype/freetype/src/truetype/ttpload.c create mode 100644 Dependencies/freetype/freetype/src/truetype/ttpload.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1afm.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1afm.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1driver.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1driver.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1errors.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1gload.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1gload.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1load.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1load.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1objs.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1objs.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1parse.c create mode 100644 Dependencies/freetype/freetype/src/type1/t1parse.h create mode 100644 Dependencies/freetype/freetype/src/type1/t1tokens.h create mode 100644 Dependencies/freetype/freetype/src/type1/type1.c create mode 100644 Dependencies/freetype/freetype/src/type42/t42drivr.c create mode 100644 Dependencies/freetype/freetype/src/type42/t42drivr.h create mode 100644 Dependencies/freetype/freetype/src/type42/t42error.h create mode 100644 Dependencies/freetype/freetype/src/type42/t42objs.c create mode 100644 Dependencies/freetype/freetype/src/type42/t42objs.h create mode 100644 Dependencies/freetype/freetype/src/type42/t42parse.c create mode 100644 Dependencies/freetype/freetype/src/type42/t42parse.h create mode 100644 Dependencies/freetype/freetype/src/type42/t42types.h create mode 100644 Dependencies/freetype/freetype/src/type42/type42.c create mode 100644 Dependencies/freetype/freetype/src/winfonts/fnterrs.h create mode 100644 Dependencies/freetype/freetype/src/winfonts/winfnt.c create mode 100644 Dependencies/freetype/freetype/src/winfonts/winfnt.h create mode 100644 Dependencies/msdf-atlas-gen/.gitattributes create mode 100644 Dependencies/msdf-atlas-gen/.gitignore create mode 100644 Dependencies/msdf-atlas-gen/.gitmodules create mode 100644 Dependencies/msdf-atlas-gen/CHANGELOG.md create mode 100644 Dependencies/msdf-atlas-gen/CMakeLists.txt create mode 100644 Dependencies/msdf-atlas-gen/CMakePresets.json create mode 100644 Dependencies/msdf-atlas-gen/LICENSE.txt create mode 100644 Dependencies/msdf-atlas-gen/README.md create mode 100644 Dependencies/msdf-atlas-gen/cmake/CMakePresets.json create mode 100644 Dependencies/msdf-atlas-gen/cmake/msdf-atlas-gen-config.cmake.in create mode 100644 Dependencies/msdf-atlas-gen/cmake/version.cmake create mode 100644 Dependencies/msdf-atlas-gen/icon.ico create mode 160000 Dependencies/msdf-atlas-gen/msdf-atlas-gen create mode 100644 Dependencies/msdf-atlas-gen/msdf-atlas-gen.lua create mode 100644 Dependencies/msdf-atlas-gen/msdf-atlas-gen.rc create mode 100644 Dependencies/msdf-atlas-gen/resource.h create mode 100644 Dependencies/msdf-atlas-gen/vcpkg.json create mode 100644 Dependencies/msdfgen/msdfgen.lua create mode 100644 Dependencies/msdfgen/msdfgen/.gitattributes create mode 100644 Dependencies/msdfgen/msdfgen/.gitignore create mode 100644 Dependencies/msdfgen/msdfgen/CHANGELOG.md create mode 100644 Dependencies/msdfgen/msdfgen/CMakeLists.txt create mode 100644 Dependencies/msdfgen/msdfgen/CMakePresets.json create mode 100644 Dependencies/msdfgen/msdfgen/LICENSE.txt create mode 100644 Dependencies/msdfgen/msdfgen/README.md create mode 100644 Dependencies/msdfgen/msdfgen/build-release.bat create mode 100644 Dependencies/msdfgen/msdfgen/cmake/CMakePresets.json create mode 100644 Dependencies/msdfgen/msdfgen/cmake/msdfgen-config.h.in create mode 100644 Dependencies/msdfgen/msdfgen/cmake/msdfgenConfig.cmake.in create mode 100644 Dependencies/msdfgen/msdfgen/cmake/version.cmake create mode 100644 Dependencies/msdfgen/msdfgen/core/Bitmap.h create mode 100644 Dependencies/msdfgen/msdfgen/core/Bitmap.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/BitmapRef.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Contour.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Contour.h create mode 100644 Dependencies/msdfgen/msdfgen/core/DistanceMapping.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/DistanceMapping.h create mode 100644 Dependencies/msdfgen/msdfgen/core/EdgeColor.h create mode 100644 Dependencies/msdfgen/msdfgen/core/EdgeHolder.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/EdgeHolder.h create mode 100644 Dependencies/msdfgen/msdfgen/core/MSDFErrorCorrection.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/MSDFErrorCorrection.h create mode 100644 Dependencies/msdfgen/msdfgen/core/Projection.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Projection.h create mode 100644 Dependencies/msdfgen/msdfgen/core/Range.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/SDFTransformation.h create mode 100644 Dependencies/msdfgen/msdfgen/core/Scanline.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Scanline.h create mode 100644 Dependencies/msdfgen/msdfgen/core/Shape.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Shape.h create mode 100644 Dependencies/msdfgen/msdfgen/core/ShapeDistanceFinder.h create mode 100644 Dependencies/msdfgen/msdfgen/core/ShapeDistanceFinder.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/SignedDistance.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/Vector2.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/arithmetics.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/base.h create mode 100644 Dependencies/msdfgen/msdfgen/core/bitmap-interpolation.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/contour-combiners.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/contour-combiners.h create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-coloring.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-coloring.h create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-segments.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-segments.h create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-selectors.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/edge-selectors.h create mode 100644 Dependencies/msdfgen/msdfgen/core/equation-solver.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/equation-solver.h create mode 100644 Dependencies/msdfgen/msdfgen/core/export-svg.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/export-svg.h create mode 100644 Dependencies/msdfgen/msdfgen/core/generator-config.h create mode 100644 Dependencies/msdfgen/msdfgen/core/msdf-error-correction.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/msdf-error-correction.h create mode 100644 Dependencies/msdfgen/msdfgen/core/msdfgen.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/pixel-conversion.hpp create mode 100644 Dependencies/msdfgen/msdfgen/core/rasterization.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/rasterization.h create mode 100644 Dependencies/msdfgen/msdfgen/core/render-sdf.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/render-sdf.h create mode 100644 Dependencies/msdfgen/msdfgen/core/save-bmp.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/save-bmp.h create mode 100644 Dependencies/msdfgen/msdfgen/core/save-fl32.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/save-fl32.h create mode 100644 Dependencies/msdfgen/msdfgen/core/save-rgba.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/save-rgba.h create mode 100644 Dependencies/msdfgen/msdfgen/core/save-tiff.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/save-tiff.h create mode 100644 Dependencies/msdfgen/msdfgen/core/sdf-error-estimation.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/sdf-error-estimation.h create mode 100644 Dependencies/msdfgen/msdfgen/core/shape-description.cpp create mode 100644 Dependencies/msdfgen/msdfgen/core/shape-description.h create mode 100644 Dependencies/msdfgen/msdfgen/ext/import-font.cpp create mode 100644 Dependencies/msdfgen/msdfgen/ext/import-font.h create mode 100644 Dependencies/msdfgen/msdfgen/ext/import-svg.cpp create mode 100644 Dependencies/msdfgen/msdfgen/ext/import-svg.h create mode 100644 Dependencies/msdfgen/msdfgen/ext/resolve-shape-geometry.cpp create mode 100644 Dependencies/msdfgen/msdfgen/ext/resolve-shape-geometry.h create mode 100644 Dependencies/msdfgen/msdfgen/ext/save-png.cpp create mode 100644 Dependencies/msdfgen/msdfgen/ext/save-png.h create mode 100644 Dependencies/msdfgen/msdfgen/icon.ico create mode 100644 Dependencies/msdfgen/msdfgen/main.cpp create mode 100644 Dependencies/msdfgen/msdfgen/msdfgen-config.h create mode 100644 Dependencies/msdfgen/msdfgen/msdfgen-ext.h create mode 100644 Dependencies/msdfgen/msdfgen/msdfgen.h create mode 100644 Dependencies/msdfgen/msdfgen/msdfgen.rc create mode 100644 Dependencies/msdfgen/msdfgen/resource.h create mode 100644 Dependencies/msdfgen/msdfgen/vcpkg.json diff --git a/Dependencies/Dependencies.lua b/Dependencies/Dependencies.lua index 30b71de0..f7d1734a 100644 --- a/Dependencies/Dependencies.lua +++ b/Dependencies/Dependencies.lua @@ -24,7 +24,10 @@ local dependencies = "luau/luau.lua", "quill/quill.lua", "asio/asio.lua", - "hwloc/hwloc.lua" + "hwloc/hwloc.lua", + "freetype/freetype.lua", + "msdfgen/msdfgen.lua", + "msdf-atlas-gen/msdf-atlas-gen.lua", } for k,v in pairs(dependencies) do diff --git a/Dependencies/freetype/freetype.lua b/Dependencies/freetype/freetype.lua new file mode 100644 index 00000000..c60ce1c5 --- /dev/null +++ b/Dependencies/freetype/freetype.lua @@ -0,0 +1,85 @@ +local dep = Solution.Util.CreateDepTable("freetype", {}) + +Solution.Util.CreateStaticLib(dep.Name, Solution.Projects.Current.BinDir, dep.Dependencies, function() + Solution.Util.SetLanguage("C++") + Solution.Util.SetCppDialect(20) + + local rootDir = dep.Path .. "/freetype" + local sourceDir = rootDir .. "/src" + local buildsDir = rootDir .. "/builds" + local includeDir = rootDir .. "/include" + + local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "FT2_BUILD_LIBRARY" } + local links = {} + local files = + { + sourceDir .. "/autofit/autofit.c", + sourceDir .. "/bdf/bdf.c", + sourceDir .. "/cff/cff.c", + sourceDir .. "/base/ftbase.c", + sourceDir .. "/base/ftbitmap.c", + sourceDir .. "/cache/ftcache.c", + sourceDir .. "/base/ftfstype.c", + sourceDir .. "/base/ftglyph.c", + sourceDir .. "/gzip/ftgzip.c", + sourceDir .. "/base/ftinit.c", + sourceDir .. "/lzw/ftlzw.c", + sourceDir .. "/base/ftstroke.c", + sourceDir .. "/base/ftsystem.c", + sourceDir .. "/smooth/smooth.c", + + sourceDir .. "/base/ftbbox.c", + sourceDir .. "/base/ftgxval.c", + sourceDir .. "/base/ftlcdfil.c", + sourceDir .. "/base/ftmm.c", + sourceDir .. "/base/ftotval.c", + sourceDir .. "/base/ftpatent.c", + sourceDir .. "/base/ftpfr.c", + sourceDir .. "/base/ftsynth.c", + sourceDir .. "/base/ftfstype.c", + sourceDir .. "/pcf/pcf.c", + sourceDir .. "/pfr/pfr.c", + sourceDir .. "/psaux/psaux.c", + sourceDir .. "/pshinter/pshinter.c", + sourceDir .. "/psnames/psmodule.c", + sourceDir .. "/raster/raster.c", + sourceDir .. "/sdf/ftbsdf.c", + sourceDir .. "/sdf/ftsdf.c", + sourceDir .. "/sdf/ftsdfcommon.c", + sourceDir .. "/sdf/ftsdfrend.c", + sourceDir .. "/sdf/sdf.c", + sourceDir .. "/sfnt/sfnt.c", + sourceDir .. "/svg/ftsvg.c", + sourceDir .. "/truetype/truetype.c", + sourceDir .. "/type1/type1.c", + sourceDir .. "/cid/type1cid.c", + sourceDir .. "/type42/type42.c", + sourceDir .. "/winfonts/winfnt.c", + } + + if os.target() == "windows" then + local platformFiles = + { + buildsDir .. "/windows/ftdebug.c", -- TODO: Windows only + } + Solution.Util.MergeIntoTable(files, platformFiles) + Solution.Util.MergeIntoTable(defines, { "WIN32", "WIN32_LEAN_AND_MEAN", "VC_EXTRALEAN" } ) + else + -- TODO Linux + end + + warnings "Off" + + Solution.Util.SetDefines(defines) + Solution.Util.SetLinks(links) + Solution.Util.SetFiles(files) + Solution.Util.SetIncludes(includeDir) +end) + +Solution.Util.CreateDep(dep.NameLow, dep.Dependencies, function() + + local includeDir = dep.Path .. "/freetype/include" + + Solution.Util.SetIncludes(includeDir) + Solution.Util.SetLinks({ dep.Name }) +end) \ No newline at end of file diff --git a/Dependencies/freetype/freetype/.clang-format b/Dependencies/freetype/freetype/.clang-format new file mode 100644 index 00000000..fbd04c11 --- /dev/null +++ b/Dependencies/freetype/freetype/.clang-format @@ -0,0 +1,16 @@ +BasedOnStyle: Chromium +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignConsecutiveMacros: true +AlignEscapedNewlines: true +# AlignOperands: Align +AlignTrailingComments: true +AlwaysBreakAfterReturnType: AllDefinitions +BreakBeforeBraces: Allman +ColumnLimit: 80 +DerivePointerAlignment: false +IndentCaseLabels: false +PointerAlignment: Left +SpaceBeforeParens: ControlStatements +SpacesInParentheses: true diff --git a/Dependencies/freetype/freetype/LICENSE.TXT b/Dependencies/freetype/freetype/LICENSE.TXT new file mode 100644 index 00000000..8b9ce9e2 --- /dev/null +++ b/Dependencies/freetype/freetype/LICENSE.TXT @@ -0,0 +1,46 @@ +FREETYPE LICENSES +----------------- + +The FreeType 2 font engine is copyrighted work and cannot be used +legally without a software license. In order to make this project +usable to a vast majority of developers, we distribute it under two +mutually exclusive open-source licenses. + +This means that *you* must choose *one* of the two licenses described +below, then obey all its terms and conditions when using FreeType 2 in +any of your projects or products. + + - The FreeType License, found in the file `docs/FTL.TXT`, which is + similar to the original BSD license *with* an advertising clause + that forces you to explicitly cite the FreeType project in your + product's documentation. All details are in the license file. + This license is suited to products which don't use the GNU General + Public License. + + Note that this license is compatible to the GNU General Public + License version 3, but not version 2. + + - The GNU General Public License version 2, found in + `docs/GPLv2.TXT` (any later version can be used also), for + programs which already use the GPL. Note that the FTL is + incompatible with GPLv2 due to its advertisement clause. + +The contributed BDF and PCF drivers come with a license similar to +that of the X Window System. It is compatible to the above two +licenses (see files `src/bdf/README` and `src/pcf/README`). The same +holds for the source code files `src/base/fthash.c` and +`include/freetype/internal/fthash.h`; they were part of the BDF driver +in earlier FreeType versions. + +The gzip module uses the zlib license (see `src/gzip/zlib.h`) which +too is compatible to the above two licenses. + +The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code +taken almost verbatim from the HarfBuzz file `hb-ft.cc`, which uses +the 'Old MIT' license, compatible to the above two licenses. + +The MD5 checksum support (only used for debugging in development +builds) is in the public domain. + + +--- end of LICENSE.TXT --- diff --git a/Dependencies/freetype/freetype/README b/Dependencies/freetype/freetype/README new file mode 100644 index 00000000..0f5d3e0e --- /dev/null +++ b/Dependencies/freetype/freetype/README @@ -0,0 +1,107 @@ +FreeType 2.13.3 +=============== + +Homepage: https://www.freetype.org + +FreeType is a freely available software library to render fonts. + +It is written in C, designed to be small, efficient, highly +customizable, and portable while capable of producing high-quality +output (glyph images) of most vector and bitmap font formats. + +Please read the `docs/CHANGES` file, it contains IMPORTANT +INFORMATION. + +Read the files `docs/INSTALL*` for installation instructions; see the +file `docs/LICENSE.TXT` for the available licenses. + +For using FreeType's git repository instead of a distribution bundle, +please read file `README.git`. Note that you have to actually clone +the repository; using a snapshot will not work (in other words, don't +use gitlab's 'Download' button). + +The FreeType 2 API reference is located in directory `docs/reference`; +use the file `index.html` as the top entry point. [Please note that +currently the search function for locally installed documentation +doesn't work due to cross-site scripting issues.] + +Additional documentation is available as a separate package from our +sites. Go to + + https://download.savannah.gnu.org/releases/freetype/ + +and download one of the following files. + + freetype-doc-2.13.3.tar.xz + freetype-doc-2.13.3.tar.gz + ftdoc2133.zip + +To view the documentation online, go to + + https://www.freetype.org/freetype2/docs/ + + +Mailing Lists +------------- + +The preferred way of communication with the FreeType team is using +e-mail lists. + + general use and discussion: freetype@nongnu.org + engine internals, porting, etc.: freetype-devel@nongnu.org + announcements: freetype-announce@nongnu.org + git repository tracker: freetype-commit@nongnu.org + +The lists are moderated; see + + https://www.freetype.org/contact.html + +how to subscribe. + + +Bugs +---- + +Please submit bug reports at + + https://gitlab.freedesktop.org/freetype/freetype/-/issues + +Alternatively, you might report bugs by e-mail to +`freetype-devel@nongnu.org`. Don't forget to send a detailed +explanation of the problem -- there is nothing worse than receiving a +terse message that only says 'it doesn't work'. + + +Patches +------- + +For larger changes please provide merge requests at + + https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests + +Alternatively, you can send patches to the `freetype-devel@nongnu.org` +mailing list -- and thank you in advance for your work on improving +FreeType! + +Details on the process can be found here: + + https://www.freetype.org/developer.html#patches + + +Enjoy! + + The FreeType Team + +---------------------------------------------------------------------- + +Copyright (C) 2006-2024 by +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute +this file you indicate that you have read the license and understand +and accept it fully. + + +--- end of README --- diff --git a/Dependencies/freetype/freetype/README.git b/Dependencies/freetype/freetype/README.git new file mode 100644 index 00000000..c818bbb5 --- /dev/null +++ b/Dependencies/freetype/freetype/README.git @@ -0,0 +1,102 @@ +README.git +========== + + +repository issues +----------------- + +FreeType's official repository site is + + https://gitlab.freedesktop.org/freetype , + +from which the 'freetype.git' and 'freetype-demos.git' repositories +can be cloned in the usual way. + + git clone https://gitlab.freedesktop.org/freetype/freetype.git + git clone https://gitlab.freedesktop.org/freetype/freetype-demos.git + +If you want to use the Savannah mirror instead, you have to do a +slightly different incantation because the repository names contain +digit '2' for historical reasons. + + git clone \ + https://git.savannah.nongnu.org/git/freetype/freetype2.git \ + freetype + git clone \ + https://git.savannah.nongnu.org/git/freetype/freetype2-demos.git \ + freetype-demos + + +standard builds with `configure` +-------------------------------- + +The git repository doesn't contain pre-built configuration scripts for +UNIXish platforms. To generate them say + + sh autogen.sh + +which in turn depends on the following packages: + + automake (1.10.1) + libtool (2.2.4) + autoconf (2.62) + +The versions given in parentheses are known to work. Newer versions +should work too, of course. Note that `autogen.sh` also sets up +proper file permissions for the `configure` and auxiliary scripts. + +The `autogen.sh` script checks whether the versions of the above three +tools match the numbers above. Otherwise it will complain and suggest +either upgrading or using environment variables to point to more +recent versions of the required tools. + +Note that `aclocal` is provided by the 'automake' package on Linux, +and that `libtoolize` is called `glibtoolize` on Darwin (OS X). + + +alternative build methods +------------------------- + +For static builds that don't use platform-specific optimizations, no +configure script is necessary at all; saying + + make setup ansi + make + +should work on all platforms that have GNU `make` (or `makepp`). + +A build with `cmake` or `meson` can be done directly from the git +repository. However, if you want to use the `FT_DEBUG_LOGGING` macro +(see file `docs/DEBUG` for more information) it is currently mandatory +to execute `autogen.sh` in advance; this script clones the 'dlg' git +submodule and copies some files into FreeType's source tree. + + +Code of Conduct +--------------- + +Please note that this project is released with a Contributor Code of +Conduct (CoC). By participating in this project you agree to abide by +its terms, which you can find in the following link: + + https://www.freedesktop.org/wiki/CodeOfConduct + +CoC issues may be raised to the project maintainers at the following +address: + + wl@gnu.org + apodtele@gmail.com + +---------------------------------------------------------------------- + +Copyright (C) 2005-2024 by +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute +this file you indicate that you have read the license and understand +and accept it fully. + + +--- end of README.git --- diff --git a/Dependencies/freetype/freetype/devel/ft2build.h b/Dependencies/freetype/freetype/devel/ft2build.h new file mode 100644 index 00000000..7e5260d6 --- /dev/null +++ b/Dependencies/freetype/freetype/devel/ft2build.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ft2build.h + * + * FreeType 2 build and setup macros (development version). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * This is a development version of to build the library in + * debug mode. Its only difference to the default version is that it + * includes a local `ftoption.h' header file with different settings for + * many configuration macros. + * + * To use it, simply ensure that the directory containing this file is + * scanned by the compiler before the default FreeType header directory. + * + */ + +#ifndef FT2BUILD_H_ +#define FT2BUILD_H_ + +#define FT_CONFIG_MODULES_H +#define FT_CONFIG_OPTIONS_H + +#include + +#endif /* FT2BUILD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/devel/ftoption.h b/Dependencies/freetype/freetype/devel/ftoption.h new file mode 100644 index 00000000..caa45095 --- /dev/null +++ b/Dependencies/freetype/freetype/devel/ftoption.h @@ -0,0 +1,1030 @@ +/**************************************************************************** + * + * ftoption.h (for development) + * + * User-selectable configuration macros (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + + +#include + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * USER-SELECTABLE CONFIGURATION MACROS + * + * This file contains the default configuration macro definitions for a + * standard build of the FreeType library. There are three ways to use + * this file to build project-specific versions of the library: + * + * - You can modify this file by hand, but this is not recommended in + * cases where you would like to build several versions of the library + * from a single source directory. + * + * - You can put a copy of this file in your build directory, more + * precisely in `$BUILD/freetype/config/ftoption.h`, where `$BUILD` is + * the name of a directory that is included _before_ the FreeType include + * path during compilation. + * + * The default FreeType Makefiles use the build directory + * `builds/` by default, but you can easily change that for your + * own projects. + * + * - Copy the file to `$BUILD/ft2build.h` and modify it + * slightly to pre-define the macro `FT_CONFIG_OPTIONS_H` used to locate + * this file during the build. For example, + * + * ``` + * #define FT_CONFIG_OPTIONS_H + * #include + * ``` + * + * will use `$BUILD/myftoptions.h` instead of this file for macro + * definitions. + * + * Note also that you can similarly pre-define the macro + * `FT_CONFIG_MODULES_H` used to locate the file listing of the modules + * that are statically linked to the library at compile time. By + * default, this file is ``. + * + * We highly recommend using the third method whenever possible. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*#************************************************************************ + * + * If you enable this configuration option, FreeType recognizes an + * environment variable called `FREETYPE_PROPERTIES`, which can be used to + * control the various font drivers and modules. The controllable + * properties are listed in the section @properties. + * + * You have to undefine this configuration option on platforms that lack + * the concept of environment variables (and thus don't have the `getenv` + * function), for example Windows CE. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=1 + * ``` + * + */ +#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + + /************************************************************************** + * + * Uncomment the line below if you want to activate LCD rendering + * technology similar to ClearType in this build of the library. This + * technology triples the resolution in the direction color subpixels. To + * mitigate color fringes inherent to this technology, you also need to + * explicitly set up LCD filtering. + * + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. + */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /************************************************************************** + * + * Many compilers provide a non-ANSI 64-bit data type that can be used by + * FreeType to speed up some computations. However, this will create some + * problems when compiling the library in strict ANSI mode. + * + * For this reason, the use of 64-bit integers is normally disabled when + * the `__STDC__` macro is defined. You can however disable this by + * defining the macro `FT_CONFIG_OPTION_FORCE_INT64` here. + * + * For most compilers, this will only create compilation warnings when + * building the library. + * + * ObNote: The compiler-specific 64-bit integers are detected in the + * file `ftconfig.h` either statically or through the `configure` + * script on supported platforms. + */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /************************************************************************** + * + * If this macro is defined, do not try to use an assembler version of + * performance-critical functions (e.g., @FT_MulFix). You should only do + * that to verify that the assembler function works properly, or to execute + * benchmark tests of the various implementations. + */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /************************************************************************** + * + * If this macro is defined, try to use an inlined assembler version of the + * @FT_MulFix function, which is a 'hotspot' when loading and hinting + * glyphs, and which should be executed as fast as possible. + * + * Note that if your compiler or CPU is not supported, this will default to + * the standard and portable implementation found in `ftcalc.c`. + */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /************************************************************************** + * + * LZW-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `compress` program. This is mostly used to parse many of the PCF + * files that come with various X11 distributions. The implementation + * uses NetBSD's `zopen` to partially uncompress the file on the fly (see + * `src/lzw/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. + */ +#define FT_CONFIG_OPTION_USE_LZW + + + /************************************************************************** + * + * Gzip-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `gzip` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses 'zlib' to partially + * uncompress the file on the fly (see `src/gzip/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. See also the + * macro `FT_CONFIG_OPTION_SYSTEM_ZLIB` below. + */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * ZLib library selection + * + * This macro is only used when `FT_CONFIG_OPTION_USE_ZLIB` is defined. + * It allows FreeType's 'ftgzip' component to link to the system's + * installation of the ZLib library. This is useful on systems like + * Unix or VMS where it generally is already available. + * + * If you let it undefined, the component will use its own copy of the + * zlib sources instead. These have been modified to be included + * directly within the component and **not** export external function + * names. This allows you to link any program with FreeType _and_ ZLib + * without linking conflicts. + * + * Do not `#undef` this macro here since the build system might define + * it for certain configurations only. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. + */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /************************************************************************** + * + * Bzip2-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `bzip2` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses `libbz2` to partially + * uncompress the file on the fly (see `src/bzip2/ftbzip2.c`). Contrary + * to gzip, bzip2 currently is not included and need to use the system + * available bzip2 implementation. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_BZIP2 + + + /************************************************************************** + * + * Define to disable the use of file stream functions and types, `FILE`, + * `fopen`, etc. Enables the use of smaller system libraries on embedded + * systems that have multiple system libraries, some with or without file + * stream support, in the cases where file stream support is not necessary + * such as memory loading of font files. + */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + + + /************************************************************************** + * + * PNG bitmap support. + * + * FreeType now handles loading color bitmap glyphs in the PNG format. + * This requires help from the external libpng library. Uncompressed + * color bitmaps do not need any external libraries and will be supported + * regardless of this configuration. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_PNG + + + /************************************************************************** + * + * HarfBuzz support. + * + * FreeType uses the HarfBuzz library to improve auto-hinting of OpenType + * fonts. If available, many glyphs not directly addressable by a font's + * character map will be hinted also. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_HARFBUZZ + + + /************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +#define FT_CONFIG_OPTION_USE_BROTLI + + + /************************************************************************** + * + * Glyph Postscript Names handling + * + * By default, FreeType 2 is compiled with the 'psnames' module. This + * module is in charge of converting a glyph name string into a Unicode + * value, or return a Macintosh standard glyph name for the use with the + * TrueType 'post' table. + * + * Undefine this macro if you do not want 'psnames' compiled in your + * build of FreeType. This has the following effects: + * + * - The TrueType driver will provide its own set of glyph names, if you + * build it to support postscript names in the TrueType 'post' table, + * but will not synthesize a missing Unicode charmap. + * + * - The Type~1 driver will not be able to synthesize a Unicode charmap + * out of the glyphs found in the fonts. + * + * You would normally undefine this configuration macro when building a + * version of FreeType that doesn't contain a Type~1 or CFF driver. + */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Postscript Names to Unicode Values support + * + * By default, FreeType~2 is built with the 'psnames' module compiled in. + * Among other things, the module is used to convert a glyph name into a + * Unicode value. This is especially useful in order to synthesize on + * the fly a Unicode charmap from the CFF/Type~1 driver through a big + * table named the 'Adobe Glyph List' (AGL). + * + * Undefine this macro if you do not want the Adobe Glyph List compiled + * in your 'psnames' module. The Type~1 driver will not be able to + * synthesize a Unicode charmap out of the glyphs found in the fonts. + */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /************************************************************************** + * + * Support for Mac fonts + * + * Define this macro if you want support for outline fonts in Mac format + * (mac dfont, mac resource, macbinary containing a mac resource) on + * non-Mac platforms. + * + * Note that the 'FOND' resource isn't checked. + */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /************************************************************************** + * + * Guessing methods to access embedded resource forks + * + * Enable extra Mac fonts support on non-Mac platforms (e.g., GNU/Linux). + * + * Resource forks which include fonts data are stored sometimes in + * locations which users or developers don't expected. In some cases, + * resource forks start with some offset from the head of a file. In + * other cases, the actual resource fork is stored in file different from + * what the user specifies. If this option is activated, FreeType tries + * to guess whether such offsets or different file names must be used. + * + * Note that normal, direct access of resource forks is controlled via + * the `FT_CONFIG_OPTION_MAC_FONTS` option. + */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /************************************************************************** + * + * Allow the use of `FT_Incremental_Interface` to load typefaces that + * contain no glyph data, but supply it via a callback function. This is + * required by clients supporting document formats which supply font data + * incrementally as the document is parsed, such as the Ghostscript + * interpreter for the PostScript language. + */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /************************************************************************** + * + * The size in bytes of the render pool used by the scan-line converter to + * do all of its work. + */ +#define FT_RENDER_POOL_SIZE 16384L + + + /************************************************************************** + * + * FT_MAX_MODULES + * + * The maximum number of modules that can be registered in a single + * FreeType library object. 32~is the default. + */ +#define FT_MAX_MODULES 32 + + + /************************************************************************** + * + * Debug level + * + * FreeType can be compiled in debug or trace mode. In debug mode, + * errors are reported through the 'ftdebug' component. In trace mode, + * additional messages are sent to the standard output during execution. + * + * Define `FT_DEBUG_LEVEL_ERROR` to build the library in debug mode. + * Define `FT_DEBUG_LEVEL_TRACE` to build it in trace mode. + * + * Don't define any of these macros to compile in 'release' mode! + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +#define FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_TRACE + + + /************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +#define FT_DEBUG_LOGGING + + + /************************************************************************** + * + * Autofitter debugging + * + * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to + * control the autofitter behaviour for debugging purposes with global + * boolean variables (consequently, you should **never** enable this + * while compiling in 'release' mode): + * + * ``` + * af_debug_disable_horz_hints_ + * af_debug_disable_vert_hints_ + * af_debug_disable_blue_hints_ + * ``` + * + * Additionally, the following functions provide dumps of various + * internal autofit structures to stdout (using `printf`): + * + * ``` + * af_glyph_hints_dump_points + * af_glyph_hints_dump_segments + * af_glyph_hints_dump_edges + * af_glyph_hints_get_num_segments + * af_glyph_hints_get_segment_offset + * ``` + * + * As an argument, they use another global variable: + * + * ``` + * af_debug_hints_ + * ``` + * + * Please have a look at the `ftgrid` demo program to see how those + * variables and macros should be used. + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +#define FT_DEBUG_AUTOFIT + + + /************************************************************************** + * + * Memory Debugging + * + * FreeType now comes with an integrated memory debugger that is capable + * of detecting simple errors like memory leaks or double deletes. To + * compile it within your build of the library, you should define + * `FT_DEBUG_MEMORY` here. + * + * Note that the memory debugger is only activated at runtime when when + * the _environment_ variable `FT2_DEBUG_MEMORY` is defined also! + * + * Do not `#undef` this macro here since the build system might define it + * for certain configurations only. + */ +#define FT_DEBUG_MEMORY + + + /************************************************************************** + * + * Module errors + * + * If this macro is set (which is _not_ the default), the higher byte of + * an error code gives the module in which the error has occurred, while + * the lower byte is the real error code. + * + * Setting this macro makes sense for debugging purposes only, since it + * would break source compatibility of certain programs that use + * FreeType~2. + * + * More details can be found in the files `ftmoderr.h` and `fterrors.h`. + */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + + + /************************************************************************** + * + * Error Strings + * + * If this macro is set, `FT_Error_String` will return meaningful + * descriptions. This is not enabled by default to reduce the overall + * size of FreeType. + * + * More details can be found in the file `fterrors.h`. + */ +/* #define FT_CONFIG_OPTION_ERROR_STRINGS */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_EMBEDDED_BITMAPS` if you want to support + * embedded bitmaps in all formats using the 'sfnt' module (namely + * TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored + * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' + * module (namely TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_COLOR_LAYERS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_POSTSCRIPT_NAMES` if you want to be able to + * load and enumerate Postscript names of glyphs in a TrueType or OpenType + * file. + * + * Note that if you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` macro, the 'sfnt' module will + * contain additional code to read the PostScript name table from a font. + * + * (By default, the module uses 'psnames' to extract glyph names.) + */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SFNT_NAMES` if your applications need to access + * the internal name table in a SFNT-based format like TrueType or + * OpenType. The name table contains various strings used to describe the + * font, like family name, copyright, version, etc. It does not contain + * any glyph name though. + * + * Accessing SFNT names is done through the functions declared in + * `ftsnames.h`. + */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /************************************************************************** + * + * TrueType CMap support + * + * Here you can fine-tune which TrueType CMap table format shall be + * supported. + */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` if you want to compile a + * bytecode interpreter in the TrueType driver. + * + * By undefining this, you will only compile the code necessary to load + * TrueType glyphs without hinting. + * + * Do not `#undef` this macro here, since the build system might define it + * for certain configurations only. + */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SUBPIXEL_HINTING` if you want to compile + * subpixel hinting support into the TrueType driver. This modifies the + * TrueType hinting mechanism when anything but `FT_RENDER_MODE_MONO` is + * requested. + * + * In particular, it modifies the bytecode interpreter to interpret (or + * not) instructions in a certain way so that all TrueType fonts look like + * they do in a Windows ClearType (DirectWrite) environment. See [1] for a + * technical overview on what this means. See `ttinterp.h` for more + * details on this option. + * + * The new default mode focuses on applying a minimal set of rules to all + * fonts indiscriminately so that modern and web fonts render well while + * legacy fonts render okay. The corresponding interpreter version is v40. + * The so-called Infinality mode (v38) is no longer available in FreeType. + * + * By undefining these, you get rendering behavior like on Windows without + * ClearType, i.e., Windows XP without ClearType enabled and Win9x + * (interpreter version v35). Or not, depending on how much hinting blood + * and testing tears the font designer put into a given font. If you + * define one or both subpixel hinting options, you can switch between + * between v35 and the ones you define (using `FT_Property_Set`). + * + * This option requires `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` to be + * defined. + * + * [1] + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED` to compile the + * TrueType glyph loader to use Apple's definition of how to handle + * component offsets in composite glyphs. + * + * Apple and MS disagree on the default behavior of component offsets in + * composites. Apple says that they should be scaled by the scaling + * factors in the transformation matrix (roughly, it's more complex) while + * MS says they should not. OpenType defines two bits in the composite + * flags array which can be used to disambiguate, but old fonts will not + * have them. + * + * https://www.microsoft.com/typography/otspec/glyf.htm + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html + */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_GX_VAR_SUPPORT` if you want to include support + * for Apple's distortable font technology ('fvar', 'gvar', 'cvar', and + * 'avar' tables). Tagged 'Font Variations', this is now part of OpenType + * also. This has many similarities to Type~1 Multiple Masters support. + */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_NO_BORING_EXPANSION` if you want to exclude + * support for 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec + * + * Right now, the following features are covered: + * + * - 'avar' version 2.0 + * + * Most likely, this is a temporary configuration option to be removed in + * the near future, since it is assumed that eventually those features are + * added to the OpenType standard. + */ +/* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an + * embedded 'BDF~' table within SFNT-based bitmap formats. + */ +#define TT_CONFIG_OPTION_BDF + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES` controls the maximum + * number of bytecode instructions executed for a single run of the + * bytecode interpreter, needed to prevent infinite loops. You don't want + * to change this except for very special situations (e.g., making a + * library fuzzer spend less time to handle broken fonts). + * + * It is not expected that this value is ever modified by a configuring + * script; instead, it gets surrounded with `#ifndef ... #endif` so that + * the value can be set as a preprocessor option on the compiler's command + * line. + */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning + * implementation (for TrueType fonts only). With this defined, FreeType + * is able to get kerning pair data from the GPOS 'kern' feature as well as + * legacy 'kern' tables; without this defined, FreeType will only be able + * to use legacy 'kern' tables. + * + * Note that FreeType does not support more advanced GPOS layout features; + * even the 'kern' feature implemented here doesn't handle more + * sophisticated kerning variants. Use a higher-level library like + * HarfBuzz instead for that. + */ +#define TT_CONFIG_OPTION_GPOS_KERNING + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * `T1_MAX_DICT_DEPTH` is the maximum depth of nest dictionaries and arrays + * in the Type~1 stream (see `t1load.c`). A minimum of~4 is required. + */ +#define T1_MAX_DICT_DEPTH 5 + + + /************************************************************************** + * + * `T1_MAX_SUBRS_CALLS` details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 16 + + + /************************************************************************** + * + * `T1_MAX_CHARSTRING_OPERANDS` is the charstring stack's capacity. A + * minimum of~16 is required. + * + * The Chinese font 'MingTiEG-Medium' (covering the CNS 11643 character + * set) needs 256. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the 't1afm' module, which is in charge of reading Type~1 AFM files + * into an existing face. Note that if set, the Type~1 driver will be + * unable to produce kerning distances. + */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the Multiple Masters font support in the Type~1 driver. + */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /************************************************************************** + * + * `T1_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe Type~1 + * engine gets compiled into FreeType. If defined, it is possible to + * switch between the two engines using the `hinting-engine` property of + * the 'type1' driver module. + */ +#define T1_CONFIG_OPTION_OLD_ENGINE + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** C F F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Using `CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4}` it is + * possible to set up the default values of the four control points that + * define the stem darkening behaviour of the (new) CFF engine. For more + * details please read the documentation of the `darkening-parameters` + * property (file `ftdriver.h`), which allows the control at run-time. + * + * Do **not** undefine these macros! + */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + + /************************************************************************** + * + * `CFF_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe CFF engine + * gets compiled into FreeType. If defined, it is possible to switch + * between the two engines using the `hinting-engine` property of the 'cff' + * driver module. + */ +#define CFF_CONFIG_OPTION_OLD_ENGINE + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P C F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When selecting + * 'Fixed' in KDE or Gnome one gets results that appear rather random, the + * style changes often if one changes the size and one cannot select some + * fonts at all. This option makes the 'pcf' module prepend the foundry + * name (plus a space) to the family name. + * + * We also check whether we have 'wide' characters; all put together, we + * get family names like 'Sony Fixed' or 'Misc Fixed Wide'. + * + * If this option is activated, it can be controlled with the + * `no-long-family-names` property of the 'pcf' driver module. + */ +#define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Compile 'autofit' module with CJK (Chinese, Japanese, Korean) script + * support. + */ +#define AF_CONFIG_OPTION_CJK + + + /************************************************************************** + * + * Compile 'autofit' module with fallback Indic script support, covering + * some scripts that the 'latin' submodule of the 'autofit' module doesn't + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. + */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_CONFIG_OPTION_INDIC +#endif + + + /************************************************************************** + * + * Use TrueType-like size metrics for 'light' auto-hinting. + * + * It is strongly recommended to avoid this option, which exists only to + * help some legacy applications retain its appearance and behaviour with + * respect to auto-hinted TrueType fonts. + * + * The very reason this option exists at all are GNU/Linux distributions + * like Fedora that did not un-patch the following change (which was + * present in FreeType between versions 2.4.6 and 2.7.1, inclusive). + * + * ``` + * 2011-07-16 Steven Chu + * + * [truetype] Fix metrics on size request for scalable fonts. + * ``` + * + * This problematic commit is now reverted (more or less). + */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + + /* */ + + + /* + * This macro is obsolete. Support has been removed in FreeType version + * 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * The next two macros are defined if native TrueType hinting is + * requested by the definitions above. Don't change this. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif + + + /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set` in file `cffdrivr.c`. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + + +FT_END_HEADER + +#endif /* FTOPTION_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/dlg/dlg.h b/Dependencies/freetype/freetype/include/dlg/dlg.h new file mode 100644 index 00000000..fa10730e --- /dev/null +++ b/Dependencies/freetype/freetype/include/dlg/dlg.h @@ -0,0 +1,290 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#ifndef INC_DLG_DLG_H_ +#define INC_DLG_DLG_H_ + +#include +#include +#include +#include +#include + +// Hosted at https://github.com/nyorain/dlg. +// There are examples and documentation. +// Issue reports and contributions appreciated. + +// - CONFIG - +// Define this macro to make all dlg macros have no effect at all +// #define DLG_DISABLE + +// the log/assertion levels below which logs/assertions are ignored +// defaulted depending on the NDEBUG macro +#ifndef DLG_LOG_LEVEL + #ifdef NDEBUG + #define DLG_LOG_LEVEL dlg_level_warn + #else + #define DLG_LOG_LEVEL dlg_level_trace + #endif +#endif + +#ifndef DLG_ASSERT_LEVEL + #ifdef NDEBUG + #define DLG_ASSERT_LEVEL dlg_level_warn + #else + #define DLG_ASSERT_LEVEL dlg_level_trace + #endif +#endif + +// the assert level of dlg_assert +#ifndef DLG_DEFAULT_ASSERT + #define DLG_DEFAULT_ASSERT dlg_level_error +#endif + +// evaluated to the 'file' member in dlg_origin +#ifndef DLG_FILE + #define DLG_FILE dlg__strip_root_path(__FILE__, DLG_BASE_PATH) + + // the base path stripped from __FILE__. If you don't override DLG_FILE set this to + // the project root to make 'main.c' from '/some/bullshit/main.c' + #ifndef DLG_BASE_PATH + #define DLG_BASE_PATH "" + #endif +#endif + +// Default tags applied to all logs/assertions (in the defining file). +// Must be in format ```#define DLG_DEFAULT_TAGS "tag1", "tag2"``` +// or just nothing (as defaulted here) +#ifndef DLG_DEFAULT_TAGS + #define DLG_DEFAULT_TAGS_TERM NULL +#else + #define DLG_DEFAULT_TAGS_TERM DLG_DEFAULT_TAGS, NULL +#endif + +// The function used for formatting. Can have any signature, but must be callable with +// the arguments the log/assertions macros are called with. Must return a const char* +// that will not be freed by dlg, the formatting function must keep track of it. +// The formatting function might use dlg_thread_buffer or a custom owned buffer. +// The returned const char* has to be valid until the dlg log/assertion ends. +// Usually a c function with ... (i.e. using va_list) or a variadic c++ template do +// allow formatting. +#ifndef DLG_FMT_FUNC + #define DLG_FMT_FUNC dlg__printf_format +#endif + +// Only overwrite (i.e. predefine) this if you know what you are doing. +// On windows this is used to add the dllimport specified. +// If you are using the static version of dlg (on windows) define +// DLG_STATIC before including dlg.h +#ifndef DLG_API + #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(DLG_STATIC) + #define DLG_API __declspec(dllimport) + #else + #define DLG_API + #endif +#endif + +// This macro is used when an assertion fails. It gets the source expression +// and can return an alternative (that must stay alive). +// Mainly useful to execute something on failed assertion. +#ifndef DLG_FAILED_ASSERTION_TEXT + #define DLG_FAILED_ASSERTION_TEXT(x) x +#endif + +// - utility - +// two methods needed since cplusplus does not support compound literals +// and c does not support uniform initialization/initializer lists +#ifdef __cplusplus + #include + #define DLG_CREATE_TAGS(...) std::initializer_list \ + {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}.begin() +#else + #define DLG_CREATE_TAGS(...) (const char* const[]) {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL} +#endif + +#ifdef __GNUC__ + #define DLG_PRINTF_ATTRIB(a, b) __attribute__ ((format (printf, a, b))) +#else + #define DLG_PRINTF_ATTRIB(a, b) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +// Represents the importance of a log/assertion call. +enum dlg_level { + dlg_level_trace = 0, // temporary used debug, e.g. to check if control reaches function + dlg_level_debug, // general debugging, prints e.g. all major events + dlg_level_info, // general useful information + dlg_level_warn, // warning, something went wrong but might have no (really bad) side effect + dlg_level_error, // something really went wrong; expect serious issues + dlg_level_fatal // critical error; application is likely to crash/exit +}; + +// Holds various information associated with a log/assertion call. +// Forwarded to the output handler. +struct dlg_origin { + const char* file; + unsigned int line; + const char* func; + enum dlg_level level; + const char** tags; // null-terminated + const char* expr; // assertion expression, otherwise null +}; + +// Type of the output handler, see dlg_set_handler. +typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string, void* data); + +#ifndef DLG_DISABLE + // Tagged/Untagged logging with variable level + // Tags must always be in the format `("tag1", "tag2")` (including brackets) + // Example usages: + // dlg_log(dlg_level_warning, "test 1") + // dlg_logt(("tag1, "tag2"), dlg_level_debug, "test %d", 2) + #define dlg_log(level, ...) if(level >= DLG_LOG_LEVEL) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), NULL) + #define dlg_logt(level, tags, ...) if(level >= DLG_LOG_LEVEL) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), NULL) + + // Dynamic level assert macros in various versions for additional arguments + // Example usages: + // dlg_assertl(dlg_level_warning, data != nullptr); + // dlg_assertlt(("tag1, "tag2"), dlg_level_trace, data != nullptr); + // dlg_asserttlm(("tag1), dlg_level_warning, data != nullptr, "Data must not be null"); + // dlg_assertlm(dlg_level_error, data != nullptr, "Data must not be null"); + #define dlg_assertl(level, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, \ + DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertlt(level, tags, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, \ + DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertlm(level, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertltm(level, tags, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, \ + __func__, DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr)) + + #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) {\ + if(level >= DLG_ASSERT_LEVEL) \ + dlg__do_log(level, tags, DLG_FILE, __LINE__, __func__, msg, \ + DLG_FAILED_ASSERTION_TEXT(#expr)); \ + code; \ + } (void) NULL + + // - Private interface: not part of the abi/api but needed in macros - + // Formats the given format string and arguments as printf would, uses the thread buffer. + DLG_API const char* dlg__printf_format(const char* format, ...) DLG_PRINTF_ATTRIB(1, 2); + DLG_API void dlg__do_log(enum dlg_level lvl, const char* const*, const char*, int, + const char*, const char*, const char*); + DLG_API const char* dlg__strip_root_path(const char* file, const char* base); + +#else // DLG_DISABLE + + #define dlg_log(level, ...) + #define dlg_logt(level, tags, ...) + + #define dlg_assertl(level, expr) // assert without tags/message + #define dlg_assertlt(level, tags, expr) // assert with tags + #define dlg_assertlm(level, expr, ...) // assert with message + #define dlg_assertltm(level, tags, expr, ...) // assert with tags & message + + #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) { code; } (void) NULL +#endif // DLG_DISABLE + +// The API below is independent from DLG_DISABLE + +// Sets the handler that is responsible for formatting and outputting log calls. +// This function is not thread safe and the handler is set globally. +// The handler itself must not change dlg tags or call a dlg macro (if it +// does so, the provided string or tags array in 'origin' might get invalid). +// The handler can also be used for various other things such as dealing +// with failed assertions or filtering calls based on the passed tags. +// The default handler is dlg_default_output (see its doc for more info). +// If using c++ make sure the registered handler cannot throw e.g. by +// wrapping everything into a try-catch blog. +DLG_API void dlg_set_handler(dlg_handler handler, void* data); + +// The default output handler. +// Only use this to reset the output handler, prefer to use +// dlg_generic_output (from output.h) which this function simply calls. +// It also flushes the stream used and correctly outputs even from multiple threads. +DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*); + +// Returns the currently active dlg handler and sets `data` to +// its user data pointer. `data` must not be NULL. +// Useful to create handler chains. +// This function is not threadsafe, i.e. retrieving the handler while +// changing it from another thread is unsafe. +// See `dlg_set_handler`. +DLG_API dlg_handler dlg_get_handler(void** data); + +// Adds the given tag associated with the given function to the thread specific list. +// If func is not NULL the tag will only applied to calls from the same function. +// Remove the tag again calling dlg_remove_tag (with exactly the same pointers!). +// Does not check if the tag is already present. +DLG_API void dlg_add_tag(const char* tag, const char* func); + +// Removes a tag added with dlg_add_tag (has no effect for tags no present). +// The pointers must be exactly the same pointers that were supplied to dlg_add_tag, +// this function will not check using strcmp. When the same tag/func combination +// is added multiple times, this function remove exactly one candidate, it is +// undefined which. Returns whether a tag was found (and removed). +DLG_API bool dlg_remove_tag(const char* tag, const char* func); + +// Returns the thread-specific buffer and its size for dlg. +// The buffer should only be used by formatting functions. +// The buffer can be reallocated and the size changed, just make sure +// to update both values correctly. +DLG_API char** dlg_thread_buffer(size_t** size); + +// Untagged leveled logging +#define dlg_trace(...) dlg_log(dlg_level_trace, __VA_ARGS__) +#define dlg_debug(...) dlg_log(dlg_level_debug, __VA_ARGS__) +#define dlg_info(...) dlg_log(dlg_level_info, __VA_ARGS__) +#define dlg_warn(...) dlg_log(dlg_level_warn, __VA_ARGS__) +#define dlg_error(...) dlg_log(dlg_level_error, __VA_ARGS__) +#define dlg_fatal(...) dlg_log(dlg_level_fatal, __VA_ARGS__) + +// Tagged leveled logging +#define dlg_tracet(tags, ...) dlg_logt(dlg_level_trace, tags, __VA_ARGS__) +#define dlg_debugt(tags, ...) dlg_logt(dlg_level_debug, tags, __VA_ARGS__) +#define dlg_infot(tags, ...) dlg_logt(dlg_level_info, tags, __VA_ARGS__) +#define dlg_warnt(tags, ...) dlg_logt(dlg_level_warn, tags, __VA_ARGS__) +#define dlg_errort(tags, ...) dlg_logt(dlg_level_error, tags, __VA_ARGS__) +#define dlg_fatalt(tags, ...) dlg_logt(dlg_level_fatal, tags, __VA_ARGS__) + +// Assert macros useing DLG_DEFAULT_ASSERT as level +#define dlg_assert(expr) dlg_assertl(DLG_DEFAULT_ASSERT, expr) +#define dlg_assertt(tags, expr) dlg_assertlt(DLG_DEFAULT_ASSERT, tags, expr) +#define dlg_assertm(expr, ...) dlg_assertlm(DLG_DEFAULT_ASSERT, expr, __VA_ARGS__) +#define dlg_asserttm(tags, expr, ...) dlg_assertltm(DLG_DEFAULT_ASSERT, tags, expr, __VA_ARGS__) + +// If (expr) does not evaluate to true, always executes 'code' (no matter what +// DLG_ASSERT_LEVEL is or if dlg is disabled or not). +// When dlg is enabled and the level is greater or equal to DLG_ASSERT_LEVEL, +// logs the failed assertion. +// Example usages: +// dlg_assertl_or(dlg_level_warn, data != nullptr, return); +// dlg_assertlm_or(dlg_level_fatal, data != nullptr, return, "Data must not be null"); +// dlg_assert_or(data != nullptr, logError(); return false); +#define dlg_assertltm_or(level, tags, expr, code, ...) dlg__assert_or(level, \ + DLG_CREATE_TAGS tags, expr, code, DLG_FMT_FUNC(__VA_ARGS__)) +#define dlg_assertlm_or(level, expr, code, ...) dlg__assert_or(level, \ + DLG_CREATE_TAGS(NULL), expr, code, DLG_FMT_FUNC(__VA_ARGS__)) +#define dlg_assertl_or(level, expr, code) dlg__assert_or(level, \ + DLG_CREATE_TAGS(NULL), expr, code, NULL) + +#define dlg_assert_or(expr, code) dlg_assertl_or(DLG_DEFAULT_ASSERT, expr, code) +#define dlg_assertm_or(expr, code, ...) dlg_assertlm_or(DLG_DEFAULT_ASSERT, expr, code, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif // header guard diff --git a/Dependencies/freetype/freetype/include/dlg/output.h b/Dependencies/freetype/freetype/include/dlg/output.h new file mode 100644 index 00000000..453e4a56 --- /dev/null +++ b/Dependencies/freetype/freetype/include/dlg/output.h @@ -0,0 +1,172 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#ifndef INC_DLG_OUTPUT_H_ +#define INC_DLG_OUTPUT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Text style +enum dlg_text_style { + dlg_text_style_reset = 0, + dlg_text_style_bold = 1, + dlg_text_style_dim = 2, + dlg_text_style_italic = 3, + dlg_text_style_underline = 4, + dlg_text_style_blink = 5, + dlg_text_style_rblink = 6, + dlg_text_style_reversed = 7, + dlg_text_style_conceal = 8, + dlg_text_style_crossed = 9, + dlg_text_style_none, +}; + +// Text color +enum dlg_color { + dlg_color_black = 0, + dlg_color_red, + dlg_color_green, + dlg_color_yellow, + dlg_color_blue, + dlg_color_magenta, + dlg_color_cyan, + dlg_color_gray, + dlg_color_reset = 9, + + dlg_color_black2 = 60, + dlg_color_red2, + dlg_color_green2, + dlg_color_yellow2, + dlg_color_blue2, + dlg_color_magenta2, + dlg_color_cyan2, + dlg_color_gray2, + + dlg_color_none = 69, +}; + +struct dlg_style { + enum dlg_text_style style; + enum dlg_color fg; + enum dlg_color bg; +}; + +// Like fprintf but fixes utf-8 output to console on windows. +// On non-windows sytems just uses the corresponding standard library +// functions. On windows, if dlg was compiled with the win_console option, +// will first try to output it in a way that allows the default console +// to display utf-8. If that fails, will fall back to the standard +// library functions. +DLG_API int dlg_fprintf(FILE* stream, const char* format, ...) DLG_PRINTF_ATTRIB(2, 3); +DLG_API int dlg_vfprintf(FILE* stream, const char* format, va_list list); + +// Like dlg_printf, but also applies the given style to this output. +// The style will always be applied (using escape sequences), independent of the given stream. +// On windows escape sequences don't work out of the box, see dlg_win_init_ansi(). +DLG_API int dlg_styled_fprintf(FILE* stream, struct dlg_style style, + const char* format, ...) DLG_PRINTF_ATTRIB(3, 4); + +// Features to output from the generic output handler. +// Some features might have only an effect in the specializations. +enum dlg_output_feature { + dlg_output_tags = 1, // output tags list + dlg_output_time = 2, // output time of log call (hour:minute:second) + dlg_output_style = 4, // whether to use the supplied styles + dlg_output_func = 8, // output function + dlg_output_file_line = 16, // output file:line, + dlg_output_newline = 32, // output a newline at the end + dlg_output_threadsafe = 64, // locks stream before printing + dlg_output_time_msecs = 128 // output micro seconds (ms on windows) +}; + +// The default level-dependent output styles. The array values represent the styles +// to be used for the associated level (i.e. [0] for trace level). +DLG_API extern const struct dlg_style dlg_default_output_styles[6]; + +// Generic output function. Used by the default output handler and might be useful +// for custom output handlers (that don't want to manually format the output). +// Will call the given output func with the given data (and format + args to print) +// for everything it has to print in printf format. +// See also the *_stream and *_buf specializations for common usage. +// The given output function must not be NULL. +typedef void(*dlg_generic_output_handler)(void* data, const char* format, ...); +DLG_API void dlg_generic_output(dlg_generic_output_handler output, void* data, + unsigned int features, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); + +// Generic output function, using a format string instead of feature flags. +// Use following conversion characters: +// %h - output the time in H:M:S format +// %m - output the time in milliseconds +// %t - output the full list of tags, comma separated +// %f - output the function name noted in the origin +// %o - output the file:line of the origin +// %s - print the appropriate style escape sequence. +// %r - print the escape sequence to reset the style. +// %c - The content of the log/assert +// %% - print the '%' character +// Only the above specified conversion characters are valid, the rest are +// written as it is. +DLG_API void dlg_generic_outputf(dlg_generic_output_handler output, void* data, + const char* format_string, const struct dlg_origin* origin, + const char* string, const struct dlg_style styles[6]); + +// Generic output function. Used by the default output handler and might be useful +// for custom output handlers (that don't want to manually format the output). +// If stream is NULL uses stdout. +// Automatically uses dlg_fprintf to assure correct utf-8 even on windows consoles. +// Locks the stream (i.e. assures threadsafe access) when the associated feature +// is passed (note that stdout/stderr might still mix from multiple threads). +DLG_API void dlg_generic_output_stream(FILE* stream, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); +DLG_API void dlg_generic_outputf_stream(FILE* stream, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6], bool lock_stream); + +// Generic output function (see dlg_generic_output) that uses a buffer instead of +// a stream. buf must at least point to *size bytes. Will set *size to the number +// of bytes written (capped to the given size), if buf == NULL will set *size +// to the needed size. The size parameter must not be NULL. +DLG_API void dlg_generic_output_buf(char* buf, size_t* size, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); +DLG_API void dlg_generic_outputf_buf(char* buf, size_t* size, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); + +// Returns if the given stream is a tty. Useful for custom output handlers +// e.g. to determine whether to use color. +// NOTE: Due to windows limitations currently returns false for wsl ttys. +DLG_API bool dlg_is_tty(FILE* stream); + +// Returns the null-terminated escape sequence for the given style into buf. +// Undefined behvaiour if any member of style has a value outside its enum range (will +// probably result in a buffer overflow or garbage being printed). +// If all member of style are 'none' will simply nullterminate the first buf char. +DLG_API void dlg_escape_sequence(struct dlg_style style, char buf[12]); + +// The reset style escape sequence. +DLG_API extern const char* const dlg_reset_sequence; + +// Just returns true without other effect on non-windows systems or if dlg +// was compiled without the win_console option. +// On windows tries to set the console mode to ansi to make escape sequences work. +// This works only on newer windows 10 versions. Returns false on error. +// Only the first call to it will have an effect, following calls just return the result. +// The function is threadsafe. Automatically called by the default output handler. +// This will only be able to set the mode for the stdout and stderr consoles, so +// other streams to consoles will still not work. +DLG_API bool dlg_win_init_ansi(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // header guard diff --git a/Dependencies/freetype/freetype/include/freetype/config/ftconfig.h b/Dependencies/freetype/freetype/include/freetype/config/ftconfig.h new file mode 100644 index 00000000..0667493f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/ftconfig.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * ftconfig.h + * + * ANSI-specific configuration file (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This header file contains a number of macro definitions that are used by + * the rest of the engine. Most of the macros here are automatically + * determined at compile time, and you should not need to change it to port + * FreeType, except to compile the library with a non-ANSI compiler. + * + * Note however that if some specific modifications are needed, we advise + * you to place a modified copy in your build directory. + * + * The build directory is usually `builds/`, and contains + * system-specific files that are always included first when building the + * library. + * + * This ANSI version should stay in `include/config/`. + * + */ + +#ifndef FTCONFIG_H_ +#define FTCONFIG_H_ + +#include +#include FT_CONFIG_OPTIONS_H +#include FT_CONFIG_STANDARD_LIBRARY_H + +#include +#include +#include + +#endif /* FTCONFIG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/ftheader.h b/Dependencies/freetype/freetype/include/freetype/config/ftheader.h new file mode 100644 index 00000000..f6ef2618 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/ftheader.h @@ -0,0 +1,836 @@ +/**************************************************************************** + * + * ftheader.h + * + * Build macros of the FreeType 2 library. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTHEADER_H_ +#define FTHEADER_H_ + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_BEGIN_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_END_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }` block when included from a */ + /* C++ compiler. */ + /* */ +#ifndef FT_BEGIN_HEADER +# ifdef __cplusplus +# define FT_BEGIN_HEADER extern "C" { +# else +# define FT_BEGIN_HEADER /* nothing */ +# endif +#endif + + + /*@***********************************************************************/ + /* */ + /* */ + /* FT_END_HEADER */ + /* */ + /* */ + /* This macro is used in association with @FT_BEGIN_HEADER in header */ + /* files to ensure that the declarations within are properly */ + /* encapsulated in an `extern "C" { .. }` block when included from a */ + /* C++ compiler. */ + /* */ +#ifndef FT_END_HEADER +# ifdef __cplusplus +# define FT_END_HEADER } +# else +# define FT_END_HEADER /* nothing */ +# endif +#endif + + + /************************************************************************** + * + * Aliases for the FreeType 2 public and configuration files. + * + */ + + /************************************************************************** + * + * @section: + * header_file_macros + * + * @title: + * Header File Macros + * + * @abstract: + * Macro definitions used to `#include` specific header files. + * + * @description: + * In addition to the normal scheme of including header files like + * + * ``` + * #include + * #include + * #include + * ``` + * + * it is possible to used named macros instead. They can be used + * directly in `#include` statements as in + * + * ``` + * #include FT_FREETYPE_H + * #include FT_MULTIPLE_MASTERS_H + * #include FT_GLYPH_H + * ``` + * + * These macros were introduced to overcome the infamous 8.3~naming rule + * required by DOS (and `FT_MULTIPLE_MASTERS_H` is a lot more meaningful + * than `ftmm.h`). + * + */ + + + /* configuration files */ + + /************************************************************************** + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * FreeType~2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H +#endif + + + /************************************************************************** + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H +#endif + + /* */ + + /* public headers */ + + /************************************************************************** + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * base FreeType~2 API. + * + */ +#define FT_FREETYPE_H + + + /************************************************************************** + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H + + + /************************************************************************** + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list of FreeType~2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H + + + /************************************************************************** + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H + + + /************************************************************************** + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in `#include` statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H + + + /************************************************************************** + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * basic data types defined by FreeType~2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H + + + /************************************************************************** + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * list management API of FreeType~2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H + + + /************************************************************************** + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * scalable outline management API of FreeType~2. + * + */ +#define FT_OUTLINE_H + + + /************************************************************************** + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H + + + /************************************************************************** + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * module management API of FreeType~2. + * + */ +#define FT_MODULE_H + + + /************************************************************************** + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * renderer module management API of FreeType~2. + * + */ +#define FT_RENDER_H + + + /************************************************************************** + * + * @macro: + * FT_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the driver modules. + * + */ +#define FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_AUTOHINTER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the auto-hinting module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_AUTOHINTER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_CFF_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the CFF driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_CFF_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the TrueType driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_TRUETYPE_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_PCF_DRIVER_H + * + * @description: + * A macro used in `#include` statements to name the file containing + * structures and macros related to the PCF driver module. + * + * Deprecated since version~2.9; use @FT_DRIVER_H instead. + * + */ +#define FT_PCF_DRIVER_H FT_DRIVER_H + + + /************************************************************************** + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * types and API specific to the Type~1 format. + * + */ +#define FT_TYPE1_TABLES_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H + + + /************************************************************************** + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of TrueType four-byte 'tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H + + + /************************************************************************** + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a face. + * + */ +#define FT_BDF_H + + + /************************************************************************** + * + * @macro: + * FT_CID_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which access CID font information from a face. + * + */ +#define FT_CID_H + + + /************************************************************************** + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H + + + /************************************************************************** + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H + + + /************************************************************************** + * + * @macro: + * FT_BZIP2_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports bzip2-compressed files. + * + */ +#define FT_BZIP2_H + + + /************************************************************************** + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H + + + /************************************************************************** + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H + + + /************************************************************************** + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H + + + /************************************************************************** + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H + + + /************************************************************************** + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * API of the optional FreeType~2 cache sub-system. + * + */ +#define FT_CACHE_H + + + /************************************************************************** + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * Macintosh-specific FreeType~2 API. The latter is used to access fonts + * embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H + + + /************************************************************************** + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional multiple-masters management API of FreeType~2. + * + */ +#define FT_MULTIPLE_MASTERS_H + + + /************************************************************************** + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which accesses embedded 'name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H + + + /************************************************************************** + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which validates OpenType tables ('BASE', + * 'GDEF', 'GPOS', 'GSUB', 'JSTF'). + * + */ +#define FT_OPENTYPE_VALIDATE_H + + + /************************************************************************** + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * optional FreeType~2 API which validates TrueTypeGX/AAT tables ('feat', + * 'mort', 'morx', 'bsln', 'just', 'kern', 'opbd', 'trak', 'prop'). + * + */ +#define FT_GX_VALIDATE_H + + + /************************************************************************** + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H + + + /************************************************************************** + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H + + + /************************************************************************** + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H + + + /************************************************************************** + * + * @macro: + * FT_FONT_FORMATS_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which provides functions specific to font formats. + */ +#define FT_FONT_FORMATS_H + + /* deprecated */ +#define FT_XFREE86_H FT_FONT_FORMATS_H + + + /************************************************************************** + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H + + + /************************************************************************** + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H + + + /************************************************************************** + * + * @macro: + * FT_INCREMENTAL_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which performs incremental glyph loading. + */ +#define FT_INCREMENTAL_H + + + /************************************************************************** + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H + + + /************************************************************************** + * + * @macro: + * FT_ADVANCES_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which returns individual and ranged glyph advances. + */ +#define FT_ADVANCES_H + + + /************************************************************************** + * + * @macro: + * FT_COLOR_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'CPAL' table. + */ +#define FT_COLOR_H + + + /************************************************************************** + * + * @macro: + * FT_OTSVG_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'SVG~' glyphs. + */ +#define FT_OTSVG_H + + + /* */ + + /* These header files don't need to be included by the user. */ +#define FT_ERROR_DEFINITIONS_H +#define FT_PARAMETER_TAGS_H + + /* Deprecated macros. */ +#define FT_UNPATENTED_HINTING_H +#define FT_TRUETYPE_UNPATENTED_H + + /* `FT_CACHE_H` is the only header file needed for the cache subsystem. */ +#define FT_CACHE_IMAGE_H FT_CACHE_H +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H +#define FT_CACHE_CHARMAP_H FT_CACHE_H + + /* The internals of the cache sub-system are no longer exposed. We */ + /* default to `FT_CACHE_H` at the moment just in case, but we know */ + /* of no rogue client that uses them. */ + /* */ +#define FT_CACHE_MANAGER_H FT_CACHE_H +#define FT_CACHE_INTERNAL_MRU_H FT_CACHE_H +#define FT_CACHE_INTERNAL_MANAGER_H FT_CACHE_H +#define FT_CACHE_INTERNAL_CACHE_H FT_CACHE_H +#define FT_CACHE_INTERNAL_GLYPH_H FT_CACHE_H +#define FT_CACHE_INTERNAL_IMAGE_H FT_CACHE_H +#define FT_CACHE_INTERNAL_SBITS_H FT_CACHE_H + +/* TODO(david): Move this section below to a different header */ +#ifdef FT2_BUILD_LIBRARY +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + + /* We disable the warning `conditional expression is constant' here */ + /* in order to compile cleanly with the maximum level of warnings. */ + /* In particular, the warning complains about stuff like `while(0)' */ + /* which is very useful in macro definitions. There is no benefit */ + /* in having it enabled. */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ +#endif /* FT2_BUILD_LIBRARY */ + +#endif /* FTHEADER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/ftmodule.h b/Dependencies/freetype/freetype/include/freetype/config/ftmodule.h new file mode 100644 index 00000000..b315baba --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/ftmodule.h @@ -0,0 +1,33 @@ +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `/objs/`) based on information + * from `/modules.cfg`. + * + * Please read `docs/INSTALL.ANY` and `docs/CUSTOMIZE` how to compile + * FreeType without GNU make. + * + */ + +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_svg_renderer_class ) + +/* EOF */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/ftoption.h b/Dependencies/freetype/freetype/include/freetype/config/ftoption.h new file mode 100644 index 00000000..eb4e32d8 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/ftoption.h @@ -0,0 +1,1030 @@ +/**************************************************************************** + * + * ftoption.h + * + * User-selectable configuration macros (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + + +#include + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * USER-SELECTABLE CONFIGURATION MACROS + * + * This file contains the default configuration macro definitions for a + * standard build of the FreeType library. There are three ways to use + * this file to build project-specific versions of the library: + * + * - You can modify this file by hand, but this is not recommended in + * cases where you would like to build several versions of the library + * from a single source directory. + * + * - You can put a copy of this file in your build directory, more + * precisely in `$BUILD/freetype/config/ftoption.h`, where `$BUILD` is + * the name of a directory that is included _before_ the FreeType include + * path during compilation. + * + * The default FreeType Makefiles use the build directory + * `builds/` by default, but you can easily change that for your + * own projects. + * + * - Copy the file to `$BUILD/ft2build.h` and modify it + * slightly to pre-define the macro `FT_CONFIG_OPTIONS_H` used to locate + * this file during the build. For example, + * + * ``` + * #define FT_CONFIG_OPTIONS_H + * #include + * ``` + * + * will use `$BUILD/myftoptions.h` instead of this file for macro + * definitions. + * + * Note also that you can similarly pre-define the macro + * `FT_CONFIG_MODULES_H` used to locate the file listing of the modules + * that are statically linked to the library at compile time. By + * default, this file is ``. + * + * We highly recommend using the third method whenever possible. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /*#************************************************************************ + * + * If you enable this configuration option, FreeType recognizes an + * environment variable called `FREETYPE_PROPERTIES`, which can be used to + * control the various font drivers and modules. The controllable + * properties are listed in the section @properties. + * + * You have to undefine this configuration option on platforms that lack + * the concept of environment variables (and thus don't have the `getenv` + * function), for example Windows CE. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=1 + * ``` + * + */ +#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + + /************************************************************************** + * + * Uncomment the line below if you want to activate LCD rendering + * technology similar to ClearType in this build of the library. This + * technology triples the resolution in the direction color subpixels. To + * mitigate color fringes inherent to this technology, you also need to + * explicitly set up LCD filtering. + * + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. + */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + + /************************************************************************** + * + * Many compilers provide a non-ANSI 64-bit data type that can be used by + * FreeType to speed up some computations. However, this will create some + * problems when compiling the library in strict ANSI mode. + * + * For this reason, the use of 64-bit integers is normally disabled when + * the `__STDC__` macro is defined. You can however disable this by + * defining the macro `FT_CONFIG_OPTION_FORCE_INT64` here. + * + * For most compilers, this will only create compilation warnings when + * building the library. + * + * ObNote: The compiler-specific 64-bit integers are detected in the + * file `ftconfig.h` either statically or through the `configure` + * script on supported platforms. + */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + + + /************************************************************************** + * + * If this macro is defined, do not try to use an assembler version of + * performance-critical functions (e.g., @FT_MulFix). You should only do + * that to verify that the assembler function works properly, or to execute + * benchmark tests of the various implementations. + */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + + + /************************************************************************** + * + * If this macro is defined, try to use an inlined assembler version of the + * @FT_MulFix function, which is a 'hotspot' when loading and hinting + * glyphs, and which should be executed as fast as possible. + * + * Note that if your compiler or CPU is not supported, this will default to + * the standard and portable implementation found in `ftcalc.c`. + */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + + + /************************************************************************** + * + * LZW-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `compress` program. This is mostly used to parse many of the PCF + * files that come with various X11 distributions. The implementation + * uses NetBSD's `zopen` to partially uncompress the file on the fly (see + * `src/lzw/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. + */ +#define FT_CONFIG_OPTION_USE_LZW + + + /************************************************************************** + * + * Gzip-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `gzip` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses 'zlib' to partially + * uncompress the file on the fly (see `src/gzip/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. See also the + * macro `FT_CONFIG_OPTION_SYSTEM_ZLIB` below. + */ +#define FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * ZLib library selection + * + * This macro is only used when `FT_CONFIG_OPTION_USE_ZLIB` is defined. + * It allows FreeType's 'ftgzip' component to link to the system's + * installation of the ZLib library. This is useful on systems like + * Unix or VMS where it generally is already available. + * + * If you let it undefined, the component will use its own copy of the + * zlib sources instead. These have been modified to be included + * directly within the component and **not** export external function + * names. This allows you to link any program with FreeType _and_ ZLib + * without linking conflicts. + * + * Do not `#undef` this macro here since the build system might define + * it for certain configurations only. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. + */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + + /************************************************************************** + * + * Bzip2-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `bzip2` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses `libbz2` to partially + * uncompress the file on the fly (see `src/bzip2/ftbzip2.c`). Contrary + * to gzip, bzip2 currently is not included and need to use the system + * available bzip2 implementation. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BZIP2 */ + + + /************************************************************************** + * + * Define to disable the use of file stream functions and types, `FILE`, + * `fopen`, etc. Enables the use of smaller system libraries on embedded + * systems that have multiple system libraries, some with or without file + * stream support, in the cases where file stream support is not necessary + * such as memory loading of font files. + */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + + + /************************************************************************** + * + * PNG bitmap support. + * + * FreeType now handles loading color bitmap glyphs in the PNG format. + * This requires help from the external libpng library. Uncompressed + * color bitmaps do not need any external libraries and will be supported + * regardless of this configuration. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_PNG */ + + + /************************************************************************** + * + * HarfBuzz support. + * + * FreeType uses the HarfBuzz library to improve auto-hinting of OpenType + * fonts. If available, many glyphs not directly addressable by a font's + * character map will be hinted also. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + /************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BROTLI */ + + + /************************************************************************** + * + * Glyph Postscript Names handling + * + * By default, FreeType 2 is compiled with the 'psnames' module. This + * module is in charge of converting a glyph name string into a Unicode + * value, or return a Macintosh standard glyph name for the use with the + * TrueType 'post' table. + * + * Undefine this macro if you do not want 'psnames' compiled in your + * build of FreeType. This has the following effects: + * + * - The TrueType driver will provide its own set of glyph names, if you + * build it to support postscript names in the TrueType 'post' table, + * but will not synthesize a missing Unicode charmap. + * + * - The Type~1 driver will not be able to synthesize a Unicode charmap + * out of the glyphs found in the fonts. + * + * You would normally undefine this configuration macro when building a + * version of FreeType that doesn't contain a Type~1 or CFF driver. + */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Postscript Names to Unicode Values support + * + * By default, FreeType~2 is built with the 'psnames' module compiled in. + * Among other things, the module is used to convert a glyph name into a + * Unicode value. This is especially useful in order to synthesize on + * the fly a Unicode charmap from the CFF/Type~1 driver through a big + * table named the 'Adobe Glyph List' (AGL). + * + * Undefine this macro if you do not want the Adobe Glyph List compiled + * in your 'psnames' module. The Type~1 driver will not be able to + * synthesize a Unicode charmap out of the glyphs found in the fonts. + */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + + /************************************************************************** + * + * Support for Mac fonts + * + * Define this macro if you want support for outline fonts in Mac format + * (mac dfont, mac resource, macbinary containing a mac resource) on + * non-Mac platforms. + * + * Note that the 'FOND' resource isn't checked. + */ +#define FT_CONFIG_OPTION_MAC_FONTS + + + /************************************************************************** + * + * Guessing methods to access embedded resource forks + * + * Enable extra Mac fonts support on non-Mac platforms (e.g., GNU/Linux). + * + * Resource forks which include fonts data are stored sometimes in + * locations which users or developers don't expected. In some cases, + * resource forks start with some offset from the head of a file. In + * other cases, the actual resource fork is stored in file different from + * what the user specifies. If this option is activated, FreeType tries + * to guess whether such offsets or different file names must be used. + * + * Note that normal, direct access of resource forks is controlled via + * the `FT_CONFIG_OPTION_MAC_FONTS` option. + */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + + + /************************************************************************** + * + * Allow the use of `FT_Incremental_Interface` to load typefaces that + * contain no glyph data, but supply it via a callback function. This is + * required by clients supporting document formats which supply font data + * incrementally as the document is parsed, such as the Ghostscript + * interpreter for the PostScript language. + */ +#define FT_CONFIG_OPTION_INCREMENTAL + + + /************************************************************************** + * + * The size in bytes of the render pool used by the scan-line converter to + * do all of its work. + */ +#define FT_RENDER_POOL_SIZE 16384L + + + /************************************************************************** + * + * FT_MAX_MODULES + * + * The maximum number of modules that can be registered in a single + * FreeType library object. 32~is the default. + */ +#define FT_MAX_MODULES 32 + + + /************************************************************************** + * + * Debug level + * + * FreeType can be compiled in debug or trace mode. In debug mode, + * errors are reported through the 'ftdebug' component. In trace mode, + * additional messages are sent to the standard output during execution. + * + * Define `FT_DEBUG_LEVEL_ERROR` to build the library in debug mode. + * Define `FT_DEBUG_LEVEL_TRACE` to build it in trace mode. + * + * Don't define any of these macros to compile in 'release' mode! + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +/* #define FT_DEBUG_LOGGING */ + + + /************************************************************************** + * + * Autofitter debugging + * + * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to + * control the autofitter behaviour for debugging purposes with global + * boolean variables (consequently, you should **never** enable this + * while compiling in 'release' mode): + * + * ``` + * af_debug_disable_horz_hints_ + * af_debug_disable_vert_hints_ + * af_debug_disable_blue_hints_ + * ``` + * + * Additionally, the following functions provide dumps of various + * internal autofit structures to stdout (using `printf`): + * + * ``` + * af_glyph_hints_dump_points + * af_glyph_hints_dump_segments + * af_glyph_hints_dump_edges + * af_glyph_hints_get_num_segments + * af_glyph_hints_get_segment_offset + * ``` + * + * As an argument, they use another global variable: + * + * ``` + * af_debug_hints_ + * ``` + * + * Please have a look at the `ftgrid` demo program to see how those + * variables and macros should be used. + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_AUTOFIT */ + + + /************************************************************************** + * + * Memory Debugging + * + * FreeType now comes with an integrated memory debugger that is capable + * of detecting simple errors like memory leaks or double deletes. To + * compile it within your build of the library, you should define + * `FT_DEBUG_MEMORY` here. + * + * Note that the memory debugger is only activated at runtime when when + * the _environment_ variable `FT2_DEBUG_MEMORY` is defined also! + * + * Do not `#undef` this macro here since the build system might define it + * for certain configurations only. + */ +/* #define FT_DEBUG_MEMORY */ + + + /************************************************************************** + * + * Module errors + * + * If this macro is set (which is _not_ the default), the higher byte of + * an error code gives the module in which the error has occurred, while + * the lower byte is the real error code. + * + * Setting this macro makes sense for debugging purposes only, since it + * would break source compatibility of certain programs that use + * FreeType~2. + * + * More details can be found in the files `ftmoderr.h` and `fterrors.h`. + */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + + + /************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + + + /************************************************************************** + * + * Error Strings + * + * If this macro is set, `FT_Error_String` will return meaningful + * descriptions. This is not enabled by default to reduce the overall + * size of FreeType. + * + * More details can be found in the file `fterrors.h`. + */ +/* #define FT_CONFIG_OPTION_ERROR_STRINGS */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** S F N T D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_EMBEDDED_BITMAPS` if you want to support + * embedded bitmaps in all formats using the 'sfnt' module (namely + * TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored + * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' + * module (namely TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_COLOR_LAYERS + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_POSTSCRIPT_NAMES` if you want to be able to + * load and enumerate Postscript names of glyphs in a TrueType or OpenType + * file. + * + * Note that if you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` macro, the 'sfnt' module will + * contain additional code to read the PostScript name table from a font. + * + * (By default, the module uses 'psnames' to extract glyph names.) + */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SFNT_NAMES` if your applications need to access + * the internal name table in a SFNT-based format like TrueType or + * OpenType. The name table contains various strings used to describe the + * font, like family name, copyright, version, etc. It does not contain + * any glyph name though. + * + * Accessing SFNT names is done through the functions declared in + * `ftsnames.h`. + */ +#define TT_CONFIG_OPTION_SFNT_NAMES + + + /************************************************************************** + * + * TrueType CMap support + * + * Here you can fine-tune which TrueType CMap table format shall be + * supported. + */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` if you want to compile a + * bytecode interpreter in the TrueType driver. + * + * By undefining this, you will only compile the code necessary to load + * TrueType glyphs without hinting. + * + * Do not `#undef` this macro here, since the build system might define it + * for certain configurations only. + */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_SUBPIXEL_HINTING` if you want to compile + * subpixel hinting support into the TrueType driver. This modifies the + * TrueType hinting mechanism when anything but `FT_RENDER_MODE_MONO` is + * requested. + * + * In particular, it modifies the bytecode interpreter to interpret (or + * not) instructions in a certain way so that all TrueType fonts look like + * they do in a Windows ClearType (DirectWrite) environment. See [1] for a + * technical overview on what this means. See `ttinterp.h` for more + * details on this option. + * + * The new default mode focuses on applying a minimal set of rules to all + * fonts indiscriminately so that modern and web fonts render well while + * legacy fonts render okay. The corresponding interpreter version is v40. + * The so-called Infinality mode (v38) is no longer available in FreeType. + * + * By undefining these, you get rendering behavior like on Windows without + * ClearType, i.e., Windows XP without ClearType enabled and Win9x + * (interpreter version v35). Or not, depending on how much hinting blood + * and testing tears the font designer put into a given font. If you + * define one or both subpixel hinting options, you can switch between + * between v35 and the ones you define (using `FT_Property_Set`). + * + * This option requires `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` to be + * defined. + * + * [1] + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED` to compile the + * TrueType glyph loader to use Apple's definition of how to handle + * component offsets in composite glyphs. + * + * Apple and MS disagree on the default behavior of component offsets in + * composites. Apple says that they should be scaled by the scaling + * factors in the transformation matrix (roughly, it's more complex) while + * MS says they should not. OpenType defines two bits in the composite + * flags array which can be used to disambiguate, but old fonts will not + * have them. + * + * https://www.microsoft.com/typography/otspec/glyf.htm + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html + */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_GX_VAR_SUPPORT` if you want to include support + * for Apple's distortable font technology ('fvar', 'gvar', 'cvar', and + * 'avar' tables). Tagged 'Font Variations', this is now part of OpenType + * also. This has many similarities to Type~1 Multiple Masters support. + */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_NO_BORING_EXPANSION` if you want to exclude + * support for 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec + * + * Right now, the following features are covered: + * + * - 'avar' version 2.0 + * + * Most likely, this is a temporary configuration option to be removed in + * the near future, since it is assumed that eventually those features are + * added to the OpenType standard. + */ +/* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + + + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an + * embedded 'BDF~' table within SFNT-based bitmap formats. + */ +#define TT_CONFIG_OPTION_BDF + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES` controls the maximum + * number of bytecode instructions executed for a single run of the + * bytecode interpreter, needed to prevent infinite loops. You don't want + * to change this except for very special situations (e.g., making a + * library fuzzer spend less time to handle broken fonts). + * + * It is not expected that this value is ever modified by a configuring + * script; instead, it gets surrounded with `#ifndef ... #endif` so that + * the value can be set as a preprocessor option on the compiler's command + * line. + */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + + + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning + * implementation (for TrueType fonts only). With this defined, FreeType + * is able to get kerning pair data from the GPOS 'kern' feature as well as + * legacy 'kern' tables; without this defined, FreeType will only be able + * to use legacy 'kern' tables. + * + * Note that FreeType does not support more advanced GPOS layout features; + * even the 'kern' feature implemented here doesn't handle more + * sophisticated kerning variants. Use a higher-level library like + * HarfBuzz instead for that. + */ +/* #define TT_CONFIG_OPTION_GPOS_KERNING */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * `T1_MAX_DICT_DEPTH` is the maximum depth of nest dictionaries and arrays + * in the Type~1 stream (see `t1load.c`). A minimum of~4 is required. + */ +#define T1_MAX_DICT_DEPTH 5 + + + /************************************************************************** + * + * `T1_MAX_SUBRS_CALLS` details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 16 + + + /************************************************************************** + * + * `T1_MAX_CHARSTRING_OPERANDS` is the charstring stack's capacity. A + * minimum of~16 is required. + * + * The Chinese font 'MingTiEG-Medium' (covering the CNS 11643 character + * set) needs 256. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the 't1afm' module, which is in charge of reading Type~1 AFM files + * into an existing face. Note that if set, the Type~1 driver will be + * unable to produce kerning distances. + */ +#undef T1_CONFIG_OPTION_NO_AFM + + + /************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the Multiple Masters font support in the Type~1 driver. + */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /************************************************************************** + * + * `T1_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe Type~1 + * engine gets compiled into FreeType. If defined, it is possible to + * switch between the two engines using the `hinting-engine` property of + * the 'type1' driver module. + */ +/* #define T1_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** C F F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Using `CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4}` it is + * possible to set up the default values of the four control points that + * define the stem darkening behaviour of the (new) CFF engine. For more + * details please read the documentation of the `darkening-parameters` + * property (file `ftdriver.h`), which allows the control at run-time. + * + * Do **not** undefine these macros! + */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + + + /************************************************************************** + * + * `CFF_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe CFF engine + * gets compiled into FreeType. If defined, it is possible to switch + * between the two engines using the `hinting-engine` property of the 'cff' + * driver module. + */ +/* #define CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** P C F D R I V E R C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When selecting + * 'Fixed' in KDE or Gnome one gets results that appear rather random, the + * style changes often if one changes the size and one cannot select some + * fonts at all. This option makes the 'pcf' module prepend the foundry + * name (plus a space) to the family name. + * + * We also check whether we have 'wide' characters; all put together, we + * get family names like 'Sony Fixed' or 'Misc Fixed Wide'. + * + * If this option is activated, it can be controlled with the + * `no-long-family-names` property of the 'pcf' driver module. + */ +/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * Compile 'autofit' module with CJK (Chinese, Japanese, Korean) script + * support. + */ +#define AF_CONFIG_OPTION_CJK + + + /************************************************************************** + * + * Compile 'autofit' module with fallback Indic script support, covering + * some scripts that the 'latin' submodule of the 'autofit' module doesn't + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. + */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_CONFIG_OPTION_INDIC +#endif + + + /************************************************************************** + * + * Use TrueType-like size metrics for 'light' auto-hinting. + * + * It is strongly recommended to avoid this option, which exists only to + * help some legacy applications retain its appearance and behaviour with + * respect to auto-hinted TrueType fonts. + * + * The very reason this option exists at all are GNU/Linux distributions + * like Fedora that did not un-patch the following change (which was + * present in FreeType between versions 2.4.6 and 2.7.1, inclusive). + * + * ``` + * 2011-07-16 Steven Chu + * + * [truetype] Fix metrics on size request for scalable fonts. + * ``` + * + * This problematic commit is now reverted (more or less). + */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + + /* */ + + + /* + * This macro is obsolete. Support has been removed in FreeType version + * 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + + + /* + * The next two macros are defined if native TrueType hinting is + * requested by the definitions above. Don't change this. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif + + + /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + + + /* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set` in file `cffdrivr.c`. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + + +FT_END_HEADER + +#endif /* FTOPTION_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/ftstdlib.h b/Dependencies/freetype/freetype/include/freetype/config/ftstdlib.h new file mode 100644 index 00000000..e17aa7b8 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/ftstdlib.h @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * ftstdlib.h + * + * ANSI-specific library and header configuration file (specification + * only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to group all `#includes` to the ANSI~C library that + * FreeType normally requires. It also defines macros to rename the + * standard functions within the FreeType source code. + * + * Load a file which defines `FTSTDLIB_H_` before this one to override it. + * + */ + + +#ifndef FTSTDLIB_H_ +#define FTSTDLIB_H_ + + +#include + +#define ft_ptrdiff_t ptrdiff_t + + + /************************************************************************** + * + * integer limits + * + * `UINT_MAX` and `ULONG_MAX` are used to automatically compute the size of + * `int` and `long` in bytes at compile-time. So far, this works for all + * platforms the library has been tested on. We also check `ULLONG_MAX` + * to see whether we can use 64-bit `long long` later on. + * + * Note that on the extremely rare platforms that do not provide integer + * types that are _exactly_ 16 and 32~bits wide (e.g., some old Crays where + * `int` is 36~bits), we do not make any guarantee about the correct + * behaviour of FreeType~2 with all fonts. + * + * In these cases, `ftconfig.h` will refuse to compile anyway with a + * message like 'couldn't find 32-bit type' or something similar. + * + */ + + +#include + +#define FT_CHAR_BIT CHAR_BIT +#define FT_USHORT_MAX USHRT_MAX +#define FT_INT_MAX INT_MAX +#define FT_INT_MIN INT_MIN +#define FT_UINT_MAX UINT_MAX +#define FT_LONG_MIN LONG_MIN +#define FT_LONG_MAX LONG_MAX +#define FT_ULONG_MAX ULONG_MAX +#ifdef LLONG_MAX +#define FT_LLONG_MAX LLONG_MAX +#endif +#ifdef LLONG_MIN +#define FT_LLONG_MIN LLONG_MIN +#endif +#ifdef ULLONG_MAX +#define FT_ULLONG_MAX ULLONG_MAX +#endif + + + /************************************************************************** + * + * character and string processing + * + */ + + +#include + +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr + + + /************************************************************************** + * + * file handling + * + */ + + +#include + +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_snprintf snprintf + + + /************************************************************************** + * + * sorting + * + */ + + +#include + +#define ft_qsort qsort + + + /************************************************************************** + * + * memory allocation + * + */ + + +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc + + + /************************************************************************** + * + * miscellaneous + * + */ + + +#define ft_strtol strtol +#define ft_getenv getenv + + + /************************************************************************** + * + * execution control + * + */ + + +#include + +#define ft_jmp_buf jmp_buf /* note: this cannot be a typedef since */ + /* `jmp_buf` is defined as a macro */ + /* on certain platforms */ + +#define ft_longjmp longjmp +#define ft_setjmp( b ) setjmp( *(ft_jmp_buf*) &(b) ) /* same thing here */ + + + /* The following is only used for debugging purposes, i.e., if */ + /* `FT_DEBUG_LEVEL_ERROR` or `FT_DEBUG_LEVEL_TRACE` are defined. */ + +#include + + +#endif /* FTSTDLIB_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/integer-types.h b/Dependencies/freetype/freetype/include/freetype/config/integer-types.h new file mode 100644 index 00000000..c27505ff --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/integer-types.h @@ -0,0 +1,250 @@ +/**************************************************************************** + * + * config/integer-types.h + * + * FreeType integer types definitions. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ +#ifndef FREETYPE_CONFIG_INTEGER_TYPES_H_ +#define FREETYPE_CONFIG_INTEGER_TYPES_H_ + + /* There are systems (like the Texas Instruments 'C54x) where a `char` */ + /* has 16~bits. ANSI~C says that `sizeof(char)` is always~1. Since an */ + /* `int` has 16~bits also for this system, `sizeof(int)` gives~1 which */ + /* is probably unexpected. */ + /* */ + /* `CHAR_BIT` (defined in `limits.h`) gives the number of bits in a */ + /* `char` type. */ + +#ifndef FT_CHAR_BIT +#define FT_CHAR_BIT CHAR_BIT +#endif + +#ifndef FT_SIZEOF_INT + + /* The size of an `int` type. */ +#if FT_UINT_MAX == 0xFFFFUL +#define FT_SIZEOF_INT ( 16 / FT_CHAR_BIT ) +#elif FT_UINT_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_INT ( 32 / FT_CHAR_BIT ) +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_INT ( 64 / FT_CHAR_BIT ) +#else +#error "Unsupported size of `int' type!" +#endif + +#endif /* !defined(FT_SIZEOF_INT) */ + +#ifndef FT_SIZEOF_LONG + + /* The size of a `long` type. A five-byte `long` (as used e.g. on the */ + /* DM642) is recognized but avoided. */ +#if FT_ULONG_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_LONG ( 32 / FT_CHAR_BIT ) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL +#define FT_SIZEOF_LONG ( 32 / FT_CHAR_BIT ) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_LONG ( 64 / FT_CHAR_BIT ) +#else +#error "Unsupported size of `long' type!" +#endif + +#endif /* !defined(FT_SIZEOF_LONG) */ + +#ifndef FT_SIZEOF_LONG_LONG + + /* The size of a `long long` type if available */ +#if defined( FT_ULLONG_MAX ) && FT_ULLONG_MAX >= 0xFFFFFFFFFFFFFFFFULL +#define FT_SIZEOF_LONG_LONG ( 64 / FT_CHAR_BIT ) +#else +#define FT_SIZEOF_LONG_LONG 0 +#endif + +#endif /* !defined(FT_SIZEOF_LONG_LONG) */ + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @type: + * FT_Int16 + * + * @description: + * A typedef for a 16bit signed integer type. + */ + typedef signed short FT_Int16; + + + /************************************************************************** + * + * @type: + * FT_UInt16 + * + * @description: + * A typedef for a 16bit unsigned integer type. + */ + typedef unsigned short FT_UInt16; + + /* */ + + + /* this #if 0 ... #endif clause is for documentation purposes */ +#if 0 + + /************************************************************************** + * + * @type: + * FT_Int32 + * + * @description: + * A typedef for a 32bit signed integer type. The size depends on the + * configuration. + */ + typedef signed XXX FT_Int32; + + + /************************************************************************** + * + * @type: + * FT_UInt32 + * + * A typedef for a 32bit unsigned integer type. The size depends on the + * configuration. + */ + typedef unsigned XXX FT_UInt32; + + + /************************************************************************** + * + * @type: + * FT_Int64 + * + * A typedef for a 64bit signed integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef signed XXX FT_Int64; + + + /************************************************************************** + * + * @type: + * FT_UInt64 + * + * A typedef for a 64bit unsigned integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef unsigned XXX FT_UInt64; + + /* */ + +#endif + +#if FT_SIZEOF_INT == ( 32 / FT_CHAR_BIT ) + + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; + +#elif FT_SIZEOF_LONG == ( 32 / FT_CHAR_BIT ) + + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; + +#else +#error "no 32bit type found -- please check your configuration files" +#endif + + + /* look up an integer type that is at least 32~bits */ +#if FT_SIZEOF_INT >= ( 32 / FT_CHAR_BIT ) + + typedef int FT_Fast; + typedef unsigned int FT_UFast; + +#elif FT_SIZEOF_LONG >= ( 32 / FT_CHAR_BIT ) + + typedef long FT_Fast; + typedef unsigned long FT_UFast; + +#endif + + + /* determine whether we have a 64-bit integer type */ +#if FT_SIZEOF_LONG == ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long +#define FT_UINT64 unsigned long + +#elif FT_SIZEOF_LONG_LONG >= ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + + /************************************************************************** + * + * A 64-bit data type may create compilation problems if you compile in + * strict ANSI mode. To avoid them, we disable other 64-bit data types if + * `__STDC__` is defined. You can however ignore this rule by defining the + * `FT_CONFIG_OPTION_FORCE_INT64` configuration macro. + */ +#elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#if defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the `__int64` type */ +#define FT_INT64 __int64 +#define FT_UINT64 unsigned __int64 + +#elif defined( __BORLANDC__ ) /* Borland C++ */ + + /* XXXX: We should probably check the value of `__BORLANDC__` in order */ + /* to test the compiler version. */ + + /* this compiler provides the `__int64` type */ +#define FT_INT64 __int64 +#define FT_UINT64 unsigned __int64 + +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1100 /* Watcom C++ */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long` type */ +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#endif /* !__STDC__ */ + +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ + +#ifdef FT_INT64 + typedef FT_INT64 FT_Int64; + typedef FT_UINT64 FT_UInt64; +#endif + + +#endif /* FREETYPE_CONFIG_INTEGER_TYPES_H_ */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/mac-support.h b/Dependencies/freetype/freetype/include/freetype/config/mac-support.h new file mode 100644 index 00000000..07b6f915 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/mac-support.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * config/mac-support.h + * + * Mac/OS X support configuration header. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ +#ifndef FREETYPE_CONFIG_MAC_SUPPORT_H_ +#define FREETYPE_CONFIG_MAC_SUPPORT_H_ + + /************************************************************************** + * + * Mac support + * + * This is the only necessary change, so it is defined here instead + * providing a new configuration file. + */ +#if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* No Carbon frameworks for 64bit 10.4.x. */ + /* `AvailabilityMacros.h` is available since Mac OS X 10.2, */ + /* so guess the system version by maximum errno before inclusion. */ +#include +#ifdef ECANCELED /* defined since 10.2 */ +#include "AvailabilityMacros.h" +#endif +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#undef FT_MACINTOSH +#endif + +#elif defined( __SC__ ) || defined( __MRC__ ) + /* Classic MacOS compilers */ +#include "ConditionalMacros.h" +#if TARGET_OS_MAC +#define FT_MACINTOSH 1 +#endif + +#endif /* Mac support */ + +#endif /* FREETYPE_CONFIG_MAC_SUPPORT_H_ */ diff --git a/Dependencies/freetype/freetype/include/freetype/config/public-macros.h b/Dependencies/freetype/freetype/include/freetype/config/public-macros.h new file mode 100644 index 00000000..f56581a6 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/config/public-macros.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * + * config/public-macros.h + * + * Define a set of compiler macros used in public FreeType headers. + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* + * The definitions in this file are used by the public FreeType headers + * and thus should be considered part of the public API. + * + * Other compiler-specific macro definitions that are not exposed by the + * FreeType API should go into + * `include/freetype/internal/compiler-macros.h` instead. + */ +#ifndef FREETYPE_CONFIG_PUBLIC_MACROS_H_ +#define FREETYPE_CONFIG_PUBLIC_MACROS_H_ + + /* + * `FT_BEGIN_HEADER` and `FT_END_HEADER` might have already been defined + * by `freetype/config/ftheader.h`, but we don't want to include this + * header here, so redefine the macros here only when needed. Their + * definition is very stable, so keeping them in sync with the ones in the + * header should not be a maintenance issue. + */ +#ifndef FT_BEGIN_HEADER +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* empty */ +#endif +#endif /* FT_BEGIN_HEADER */ + +#ifndef FT_END_HEADER +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* empty */ +#endif +#endif /* FT_END_HEADER */ + + +FT_BEGIN_HEADER + + /* + * Mark a function declaration as public. This ensures it will be + * properly exported to client code. Place this before a function + * declaration. + * + * NOTE: This macro should be considered an internal implementation + * detail, and not part of the FreeType API. It is only defined here + * because it is needed by `FT_EXPORT`. + */ + + /* Visual C, mingw */ +#if defined( _WIN32 ) + +#if defined( FT2_BUILD_LIBRARY ) && defined( DLL_EXPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllexport ) +#elif defined( DLL_IMPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllimport ) +#endif + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "default" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __global +#endif + + +#ifndef FT_PUBLIC_FUNCTION_ATTRIBUTE +#define FT_PUBLIC_FUNCTION_ATTRIBUTE /* empty */ +#endif + + + /* + * Define a public FreeType API function. This ensures it is properly + * exported or imported at build time. The macro parameter is the + * function's return type as in: + * + * FT_EXPORT( FT_Bool ) + * FT_Object_Method( FT_Object obj, + * ... ); + * + * NOTE: This requires that all `FT_EXPORT` uses are inside + * `FT_BEGIN_HEADER ... FT_END_HEADER` blocks. This guarantees that the + * functions are exported with C linkage, even when the header is included + * by a C++ source file. + */ +#define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern x + + + /* + * `FT_UNUSED` indicates that a given parameter is not used -- this is + * only used to get rid of unpleasant compiler warnings. + * + * Technically, this was not meant to be part of the public API, but some + * third-party code depends on it. + */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /* + * Support for casts in both C and C++. + */ +#ifdef __cplusplus +#define FT_STATIC_CAST( type, var ) static_cast(var) +#define FT_REINTERPRET_CAST( type, var ) reinterpret_cast(var) + +#define FT_STATIC_BYTE_CAST( type, var ) \ + static_cast( static_cast( var ) ) +#else +#define FT_STATIC_CAST( type, var ) (type)(var) +#define FT_REINTERPRET_CAST( type, var ) (type)(var) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) +#endif + + +FT_END_HEADER + +#endif /* FREETYPE_CONFIG_PUBLIC_MACROS_H_ */ diff --git a/Dependencies/freetype/freetype/include/freetype/freetype.h b/Dependencies/freetype/freetype/include/freetype/freetype.h new file mode 100644 index 00000000..58fc33df --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/freetype.h @@ -0,0 +1,5289 @@ +/**************************************************************************** + * + * freetype.h + * + * FreeType high-level API and common types (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FREETYPE_H_ +#define FREETYPE_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include + + +FT_BEGIN_HEADER + + + + /************************************************************************** + * + * @section: + * preamble + * + * @title: + * Preamble + * + * @abstract: + * What FreeType is and isn't + * + * @description: + * FreeType is a library that provides access to glyphs in font files. It + * scales the glyph images and their metrics to a requested size, and it + * rasterizes the glyph images to produce pixel or subpixel alpha coverage + * bitmaps. + * + * Note that FreeType is _not_ a text layout engine. You have to use + * higher-level libraries like HarfBuzz, Pango, or ICU for that. + * + * Note also that FreeType does _not_ perform alpha blending or + * compositing the resulting bitmaps or pixmaps by itself. Use your + * favourite graphics library (for example, Cairo or Skia) to further + * process FreeType's output. + * + */ + + + /************************************************************************** + * + * @section: + * header_inclusion + * + * @title: + * FreeType's header inclusion scheme + * + * @abstract: + * How client applications should include FreeType header files. + * + * @description: + * To be as flexible as possible (and for historical reasons), you must + * load file `ft2build.h` first before other header files, for example + * + * ``` + * #include + * + * #include + * #include + * ``` + */ + + + /************************************************************************** + * + * @section: + * user_allocation + * + * @title: + * User allocation + * + * @abstract: + * How client applications should allocate FreeType data structures. + * + * @description: + * FreeType assumes that structures allocated by the user and passed as + * arguments are zeroed out except for the actual data. In other words, + * it is recommended to use `calloc` (or variants of it) instead of + * `malloc` for allocation. + * + */ + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + * @title: + * Font Testing Macros + * + * @abstract: + * Macros to test various properties of fonts. + * + * @description: + * Macros to test the most important font properties. + * + * It is recommended to use these high-level macros instead of directly + * testing the corresponding flags, which are scattered over various + * structures. + * + * @order: + * FT_HAS_HORIZONTAL + * FT_HAS_VERTICAL + * FT_HAS_KERNING + * FT_HAS_FIXED_SIZES + * FT_HAS_GLYPH_NAMES + * FT_HAS_COLOR + * FT_HAS_MULTIPLE_MASTERS + * FT_HAS_SVG + * FT_HAS_SBIX + * FT_HAS_SBIX_OVERLAY + * + * FT_IS_SFNT + * FT_IS_SCALABLE + * FT_IS_FIXED_WIDTH + * FT_IS_CID_KEYED + * FT_IS_TRICKY + * FT_IS_NAMED_INSTANCE + * FT_IS_VARIATION + * + */ + + + /************************************************************************** + * + * @section: + * library_setup + * + * @title: + * Library Setup + * + * @abstract: + * Functions to start and end the usage of the FreeType library. + * + * @description: + * Functions to start and end the usage of the FreeType library. + * + * Note that @FT_Library_Version and @FREETYPE_XXX are of limited use + * because even a new release of FreeType with only documentation + * changes increases the version number. + * + * @order: + * FT_Library + * FT_Init_FreeType + * FT_Done_FreeType + * + * FT_Library_Version + * FREETYPE_XXX + * + */ + + + /************************************************************************** + * + * @section: + * face_creation + * + * @title: + * Face Creation + * + * @abstract: + * Functions to manage fonts. + * + * @description: + * The functions and structures collected in this section operate on + * fonts globally. + * + * @order: + * FT_Face + * FT_FaceRec + * FT_FACE_FLAG_XXX + * FT_STYLE_FLAG_XXX + * + * FT_New_Face + * FT_Done_Face + * FT_Reference_Face + * FT_New_Memory_Face + * FT_Face_Properties + * FT_Open_Face + * FT_Open_Args + * FT_OPEN_XXX + * FT_Parameter + * FT_Attach_File + * FT_Attach_Stream + * + */ + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + * @title: + * Sizing and Scaling + * + * @abstract: + * Functions to manage font sizes. + * + * @description: + * The functions and structures collected in this section are related to + * selecting and manipulating the size of a font globally. + * + * @order: + * FT_Size + * FT_SizeRec + * FT_Size_Metrics + * + * FT_Bitmap_Size + * + * FT_Set_Char_Size + * FT_Set_Pixel_Sizes + * FT_Request_Size + * FT_Select_Size + * FT_Size_Request_Type + * FT_Size_RequestRec + * FT_Size_Request + * + * FT_Set_Transform + * FT_Get_Transform + * + */ + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + * @title: + * Glyph Retrieval + * + * @abstract: + * Functions to manage glyphs. + * + * @description: + * The functions and structures collected in this section operate on + * single glyphs, of which @FT_Load_Glyph is most important. + * + * @order: + * FT_GlyphSlot + * FT_GlyphSlotRec + * FT_Glyph_Metrics + * + * FT_Load_Glyph + * FT_LOAD_XXX + * FT_LOAD_TARGET_MODE + * FT_LOAD_TARGET_XXX + * + * FT_Render_Glyph + * FT_Render_Mode + * FT_Get_Kerning + * FT_Kerning_Mode + * FT_Get_Track_Kerning + * + */ + + + /************************************************************************** + * + * @section: + * character_mapping + * + * @title: + * Character Mapping + * + * @abstract: + * Functions to manage character-to-glyph maps. + * + * @description: + * This section holds functions and structures that are related to + * mapping character input codes to glyph indices. + * + * Note that for many scripts the simplistic approach used by FreeType + * of mapping a single character to a single glyph is not valid or + * possible! In general, a higher-level library like HarfBuzz or ICU + * should be used for handling text strings. + * + * @order: + * FT_CharMap + * FT_CharMapRec + * FT_Encoding + * FT_ENC_TAG + * + * FT_Select_Charmap + * FT_Set_Charmap + * FT_Get_Charmap_Index + * + * FT_Get_Char_Index + * FT_Get_First_Char + * FT_Get_Next_Char + * FT_Load_Char + * + */ + + + /************************************************************************** + * + * @section: + * information_retrieval + * + * @title: + * Information Retrieval + * + * @abstract: + * Functions to retrieve font and glyph information. + * + * @description: + * Functions to retrieve font and glyph information. Only some very + * basic data is covered; see also the chapter on the format-specific + * API for more. + * + * + * @order: + * FT_Get_Name_Index + * FT_Get_Glyph_Name + * FT_Get_Postscript_Name + * FT_Get_FSType_Flags + * FT_FSTYPE_XXX + * FT_Get_SubGlyph_Info + * FT_SUBGLYPH_FLAG_XXX + * + */ + + + /************************************************************************** + * + * @section: + * other_api_data + * + * @title: + * Other API Data + * + * @abstract: + * Other structures, enumerations, and macros. + * + * @description: + * Other structures, enumerations, and macros. Deprecated functions are + * also listed here. + * + * @order: + * FT_Face_Internal + * FT_Size_Internal + * FT_Slot_Internal + * + * FT_SubGlyph + * + * FT_HAS_FAST_GLYPHS + * FT_Face_CheckTrueTypePatents + * FT_Face_SetUnpatentedHinting + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S I C T Y P E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @struct: + * FT_Glyph_Metrics + * + * @description: + * A structure to model the metrics of a single glyph. The values are + * expressed in 26.6 fractional pixel format; if the flag + * @FT_LOAD_NO_SCALE has been used while loading the glyph, values are + * expressed in font units instead. + * + * @fields: + * width :: + * The glyph's width. + * + * height :: + * The glyph's height. + * + * horiBearingX :: + * Left side bearing for horizontal layout. + * + * horiBearingY :: + * Top side bearing for horizontal layout. + * + * horiAdvance :: + * Advance width for horizontal layout. + * + * vertBearingX :: + * Left side bearing for vertical layout. + * + * vertBearingY :: + * Top side bearing for vertical layout. Larger positive values mean + * further below the vertical glyph origin. + * + * vertAdvance :: + * Advance height for vertical layout. Positive values mean the glyph + * has a positive advance downward. + * + * @note: + * If not disabled with @FT_LOAD_NO_HINTING, the values represent + * dimensions of the hinted glyph (in case hinting is applicable). + * + * Stroking a glyph with an outside border does not increase + * `horiAdvance` or `vertAdvance`; you have to manually adjust these + * values to account for the added width and height. + * + * FreeType doesn't use the 'VORG' table data for CFF fonts because it + * doesn't have an interface to quickly retrieve the glyph height. The + * y~coordinate of the vertical origin can be simply computed as + * `vertBearingY + height` after loading a glyph. + */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + + } FT_Glyph_Metrics; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @struct: + * FT_Bitmap_Size + * + * @description: + * This structure models the metrics of a bitmap strike (i.e., a set of + * glyphs for a given point size and resolution) in a bitmap font. It is + * used for the `available_sizes` field of @FT_Face. + * + * @fields: + * height :: + * The vertical distance, in pixels, between two consecutive baselines. + * It is always positive. + * + * width :: + * The average width, in pixels, of all glyphs in the strike. + * + * size :: + * The nominal size of the strike in 26.6 fractional points. This + * field is not very useful. + * + * x_ppem :: + * The horizontal ppem (nominal width) in 26.6 fractional pixels. + * + * y_ppem :: + * The vertical ppem (nominal height) in 26.6 fractional pixels. + * + * @note: + * Windows FNT: + * The nominal size given in a FNT font is not reliable. If the driver + * finds it incorrect, it sets `size` to some calculated values, and + * `x_ppem` and `y_ppem` to the pixel width and height given in the + * font, respectively. + * + * TrueType embedded bitmaps: + * `size`, `width`, and `height` values are not contained in the bitmap + * strike itself. They are computed from the global font parameters. + */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; + + } FT_Bitmap_Size; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @type: + * FT_Library + * + * @description: + * A handle to a FreeType library instance. Each 'library' is completely + * independent from the others; it is the 'root' of a set of objects like + * fonts, faces, sizes, etc. + * + * It also embeds a memory manager (see @FT_Memory), as well as a + * scan-line converter object (see @FT_Raster). + * + * [Since 2.5.6] In multi-threaded applications it is easiest to use one + * `FT_Library` object per thread. In case this is too cumbersome, a + * single `FT_Library` object across threads is possible also, as long as + * a mutex lock is used around @FT_New_Face and @FT_Done_Face. + * + * @note: + * Library objects are normally created by @FT_Init_FreeType, and + * destroyed with @FT_Done_FreeType. If you need reference-counting + * (cf. @FT_Reference_Library), use @FT_New_Library and @FT_Done_Library. + */ + typedef struct FT_LibraryRec_ *FT_Library; + + + /************************************************************************** + * + * @section: + * module_management + * + */ + + /************************************************************************** + * + * @type: + * FT_Module + * + * @description: + * A handle to a given FreeType module object. A module can be a font + * driver, a renderer, or anything else that provides services to the + * former. + */ + typedef struct FT_ModuleRec_* FT_Module; + + + /************************************************************************** + * + * @type: + * FT_Driver + * + * @description: + * A handle to a given FreeType font driver object. A font driver is a + * module capable of creating faces from font files. + */ + typedef struct FT_DriverRec_* FT_Driver; + + + /************************************************************************** + * + * @type: + * FT_Renderer + * + * @description: + * A handle to a given FreeType renderer. A renderer is a module in + * charge of converting a glyph's outline image to a bitmap. It supports + * a single glyph image format, and one or more target surface depths. + */ + typedef struct FT_RendererRec_* FT_Renderer; + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @type: + * FT_Face + * + * @description: + * A handle to a typographic face object. A face object models a given + * typeface, in a given style. + * + * @note: + * A face object also owns a single @FT_GlyphSlot object, as well as one + * or more @FT_Size objects. + * + * Use @FT_New_Face or @FT_Open_Face to create a new face object from a + * given filepath or a custom input stream. + * + * Use @FT_Done_Face to destroy it (along with its slot and sizes). + * + * An `FT_Face` object can only be safely used from one thread at a time. + * Similarly, creation and destruction of `FT_Face` with the same + * @FT_Library object can only be done from one thread at a time. On the + * other hand, functions like @FT_Load_Glyph and its siblings are + * thread-safe and do not need the lock to be held as long as the same + * `FT_Face` object is not used from multiple threads at the same time. + * + * @also: + * See @FT_FaceRec for the publicly accessible fields of a given face + * object. + */ + typedef struct FT_FaceRec_* FT_Face; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @type: + * FT_Size + * + * @description: + * A handle to an object that models a face scaled to a given character + * size. + * + * @note: + * An @FT_Face has one _active_ `FT_Size` object that is used by + * functions like @FT_Load_Glyph to determine the scaling transformation + * that in turn is used to load and hint glyphs and metrics. + * + * A newly created `FT_Size` object contains only meaningless zero values. + * You must use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, @FT_Request_Size + * or even @FT_Select_Size to change the content (i.e., the scaling + * values) of the active `FT_Size`. Otherwise, the scaling and hinting + * will not be performed. + * + * You can use @FT_New_Size to create additional size objects for a given + * @FT_Face, but they won't be used by other functions until you activate + * it through @FT_Activate_Size. Only one size can be activated at any + * given time per face. + * + * @also: + * See @FT_SizeRec for the publicly accessible fields of a given size + * object. + */ + typedef struct FT_SizeRec_* FT_Size; + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @type: + * FT_GlyphSlot + * + * @description: + * A handle to a given 'glyph slot'. A slot is a container that can hold + * any of the glyphs contained in its parent face. + * + * In other words, each time you call @FT_Load_Glyph or @FT_Load_Char, + * the slot's content is erased by the new glyph data, i.e., the glyph's + * metrics, its image (bitmap or outline), and other control information. + * + * @also: + * See @FT_GlyphSlotRec for the publicly accessible glyph fields. + */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @type: + * FT_CharMap + * + * @description: + * A handle to a character map (usually abbreviated to 'charmap'). A + * charmap is used to translate character codes in a given encoding into + * glyph indexes for its parent's face. Some font formats may provide + * several charmaps per font. + * + * Each face object owns zero or more charmaps, but only one of them can + * be 'active', providing the data used by @FT_Get_Char_Index or + * @FT_Load_Char. + * + * The list of available charmaps in a face is available through the + * `face->num_charmaps` and `face->charmaps` fields of @FT_FaceRec. + * + * The currently active charmap is available as `face->charmap`. You + * should call @FT_Set_Charmap to change it. + * + * @note: + * When a new face is created (either through @FT_New_Face or + * @FT_Open_Face), the library looks for a Unicode charmap within the + * list and automatically activates it. If there is no Unicode charmap, + * FreeType doesn't set an 'active' charmap. + * + * @also: + * See @FT_CharMapRec for the publicly accessible fields of a given + * character map. + */ + typedef struct FT_CharMapRec_* FT_CharMap; + + + /************************************************************************** + * + * @macro: + * FT_ENC_TAG + * + * @description: + * This macro converts four-letter tags into an unsigned long. It is + * used to define 'encoding' identifiers (see @FT_Encoding). + * + * @note: + * Since many 16-bit compilers don't like 32-bit enumerations, you should + * redefine this macro in case of problems to something like this: + * + * ``` + * #define FT_ENC_TAG( value, a, b, c, d ) value + * ``` + * + * to get a simple enumeration without assigning special numbers. + */ + +#ifndef FT_ENC_TAG + +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( FT_STATIC_BYTE_CAST( FT_UInt32, a ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, b ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, c ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_UInt32, d ) ) + +#endif /* FT_ENC_TAG */ + + + /************************************************************************** + * + * @enum: + * FT_Encoding + * + * @description: + * An enumeration to specify character sets supported by charmaps. Used + * in the @FT_Select_Charmap API function. + * + * @note: + * Despite the name, this enumeration lists specific character + * repertoires (i.e., charsets), and not text encoding methods (e.g., + * UTF-8, UTF-16, etc.). + * + * Other encodings might be defined in the future. + * + * @values: + * FT_ENCODING_NONE :: + * The encoding value~0 is reserved for all formats except BDF, PCF, + * and Windows FNT; see below for more information. + * + * FT_ENCODING_UNICODE :: + * The Unicode character set. This value covers all versions of the + * Unicode repertoire, including ASCII and Latin-1. Most fonts include + * a Unicode charmap, but not all of them. + * + * For example, if you want to access Unicode value U+1F028 (and the + * font contains it), use value 0x1F028 as the input value for + * @FT_Get_Char_Index. + * + * FT_ENCODING_MS_SYMBOL :: + * Microsoft Symbol encoding, used to encode mathematical symbols and + * wingdings. For more information, see + * 'https://www.microsoft.com/typography/otspec/recom.htm#non-standard-symbol-fonts', + * 'http://www.kostis.net/charsets/symbol.htm', and + * 'http://www.kostis.net/charsets/wingding.htm'. + * + * This encoding uses character codes from the PUA (Private Unicode + * Area) in the range U+F020-U+F0FF. + * + * FT_ENCODING_SJIS :: + * Shift JIS encoding for Japanese. More info at + * 'https://en.wikipedia.org/wiki/Shift_JIS'. See note on multi-byte + * encodings below. + * + * FT_ENCODING_PRC :: + * Corresponds to encoding systems mainly for Simplified Chinese as + * used in People's Republic of China (PRC). The encoding layout is + * based on GB~2312 and its supersets GBK and GB~18030. + * + * FT_ENCODING_BIG5 :: + * Corresponds to an encoding system for Traditional Chinese as used in + * Taiwan and Hong Kong. + * + * FT_ENCODING_WANSUNG :: + * Corresponds to the Korean encoding system known as Extended Wansung + * (MS Windows code page 949). For more information see + * 'https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit949.txt'. + * + * FT_ENCODING_JOHAB :: + * The Korean standard character set (KS~C 5601-1992), which + * corresponds to MS Windows code page 1361. This character set + * includes all possible Hangul character combinations. + * + * FT_ENCODING_ADOBE_LATIN_1 :: + * Corresponds to a Latin-1 encoding as defined in a Type~1 PostScript + * font. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_STANDARD :: + * Adobe Standard encoding, as found in Type~1, CFF, and OpenType/CFF + * fonts. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_EXPERT :: + * Adobe Expert encoding, as found in Type~1, CFF, and OpenType/CFF + * fonts. It is limited to 256 character codes. + * + * FT_ENCODING_ADOBE_CUSTOM :: + * Corresponds to a custom encoding, as found in Type~1, CFF, and + * OpenType/CFF fonts. It is limited to 256 character codes. + * + * FT_ENCODING_APPLE_ROMAN :: + * Apple roman encoding. Many TrueType and OpenType fonts contain a + * charmap for this 8-bit encoding, since older versions of Mac OS are + * able to use it. + * + * FT_ENCODING_OLD_LATIN_2 :: + * This value is deprecated and was neither used nor reported by + * FreeType. Don't use or test for it. + * + * FT_ENCODING_MS_SJIS :: + * Same as FT_ENCODING_SJIS. Deprecated. + * + * FT_ENCODING_MS_GB2312 :: + * Same as FT_ENCODING_PRC. Deprecated. + * + * FT_ENCODING_MS_BIG5 :: + * Same as FT_ENCODING_BIG5. Deprecated. + * + * FT_ENCODING_MS_WANSUNG :: + * Same as FT_ENCODING_WANSUNG. Deprecated. + * + * FT_ENCODING_MS_JOHAB :: + * Same as FT_ENCODING_JOHAB. Deprecated. + * + * @note: + * When loading a font, FreeType makes a Unicode charmap active if + * possible (either if the font provides such a charmap, or if FreeType + * can synthesize one from PostScript glyph name dictionaries; in either + * case, the charmap is tagged with `FT_ENCODING_UNICODE`). If such a + * charmap is synthesized, it is placed at the first position of the + * charmap array. + * + * All other encodings are considered legacy and tagged only if + * explicitly defined in the font file. Otherwise, `FT_ENCODING_NONE` is + * used. + * + * `FT_ENCODING_NONE` is set by the BDF and PCF drivers if the charmap is + * neither Unicode nor ISO-8859-1 (otherwise it is set to + * `FT_ENCODING_UNICODE`). Use @FT_Get_BDF_Charset_ID to find out which + * encoding is really present. If, for example, the `cs_registry` field + * is 'KOI8' and the `cs_encoding` field is 'R', the font is encoded in + * KOI8-R. + * + * `FT_ENCODING_NONE` is always set (with a single exception) by the + * winfonts driver. Use @FT_Get_WinFNT_Header and examine the `charset` + * field of the @FT_WinFNT_HeaderRec structure to find out which encoding + * is really present. For example, @FT_WinFNT_ID_CP1251 (204) means + * Windows code page 1251 (for Russian). + * + * `FT_ENCODING_NONE` is set if `platform_id` is @TT_PLATFORM_MACINTOSH + * and `encoding_id` is not `TT_MAC_ID_ROMAN` (otherwise it is set to + * `FT_ENCODING_APPLE_ROMAN`). + * + * If `platform_id` is @TT_PLATFORM_MACINTOSH, use the function + * @FT_Get_CMap_Language_ID to query the Mac language ID that may be + * needed to be able to distinguish Apple encoding variants. See + * + * https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt + * + * to get an idea how to do that. Basically, if the language ID is~0, + * don't use it, otherwise subtract 1 from the language ID. Then examine + * `encoding_id`. If, for example, `encoding_id` is `TT_MAC_ID_ROMAN` + * and the language ID (minus~1) is `TT_MAC_LANGID_GREEK`, it is the + * Greek encoding, not Roman. `TT_MAC_ID_ARABIC` with + * `TT_MAC_LANGID_FARSI` means the Farsi variant of the Arabic encoding. + */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_PRC, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backward compatibility */ + FT_ENCODING_GB2312 = FT_ENCODING_PRC, + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_PRC, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + + } FT_Encoding; + + + /* these constants are deprecated; use the corresponding `FT_Encoding` */ + /* values instead */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_PRC +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + + + /************************************************************************** + * + * @struct: + * FT_CharMapRec + * + * @description: + * The base charmap structure. + * + * @fields: + * face :: + * A handle to the parent face object. + * + * encoding :: + * An @FT_Encoding tag identifying the charmap. Use this with + * @FT_Select_Charmap. + * + * platform_id :: + * An ID number describing the platform for the following encoding ID. + * This comes directly from the TrueType specification and gets + * emulated for other formats. + * + * encoding_id :: + * A platform-specific encoding number. This also comes from the + * TrueType specification and gets emulated similarly. + */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + + } FT_CharMapRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* B A S E O B J E C T C L A S S E S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @type: + * FT_Face_Internal + * + * @description: + * An opaque handle to an `FT_Face_InternalRec` structure that models the + * private data of a given @FT_Face object. + * + * This structure might change between releases of FreeType~2 and is not + * generally available to client applications. + */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @struct: + * FT_FaceRec + * + * @description: + * FreeType root face class structure. A face object models a typeface + * in a font file. + * + * @fields: + * num_faces :: + * The number of faces in the font file. Some font formats can have + * multiple faces in a single font file. + * + * face_index :: + * This field holds two different values. Bits 0-15 are the index of + * the face in the font file (starting with value~0). They are set + * to~0 if there is only one face in the font file. + * + * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation + * fonts only, holding the named instance index for the current face + * index (starting with value~1; value~0 indicates font access without + * a named instance). For non-variation fonts, bits 16-30 are ignored. + * If we have the third named instance of face~4, say, `face_index` is + * set to 0x00030004. + * + * Bit 31 is always zero (that is, `face_index` is always a positive + * value). + * + * [Since 2.9] Changing the design coordinates with + * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does + * not influence the named instance index value (only + * @FT_Set_Named_Instance does that). + * + * face_flags :: + * A set of bit flags that give important information about the face; + * see @FT_FACE_FLAG_XXX for the details. + * + * style_flags :: + * The lower 16~bits contain a set of bit flags indicating the style of + * the face; see @FT_STYLE_FLAG_XXX for the details. + * + * [Since 2.6.1] Bits 16-30 hold the number of named instances + * available for the current face if we have a GX or OpenType variation + * (sub)font. Bit 31 is always zero (that is, `style_flags` is always + * a positive value). Note that a variation font has always at least + * one named instance, namely the default instance. + * + * num_glyphs :: + * The number of glyphs in the face. If the face is scalable and has + * sbits (see `num_fixed_sizes`), it is set to the number of outline + * glyphs. + * + * For CID-keyed fonts (not in an SFNT wrapper) this value gives the + * highest CID used in the font. + * + * family_name :: + * The face's family name. This is an ASCII string, usually in + * English, that describes the typeface's family (like 'Times New + * Roman', 'Bodoni', 'Garamond', etc). This is a least common + * denominator used to list fonts. Some formats (TrueType & OpenType) + * provide localized and Unicode versions of this string. Applications + * should use the format-specific interface to access them. Can be + * `NULL` (e.g., in fonts embedded in a PDF file). + * + * In case the font doesn't provide a specific family name entry, + * FreeType tries to synthesize one, deriving it from other name + * entries. + * + * style_name :: + * The face's style name. This is an ASCII string, usually in English, + * that describes the typeface's style (like 'Italic', 'Bold', + * 'Condensed', etc). Not all font formats provide a style name, so + * this field is optional, and can be set to `NULL`. As for + * `family_name`, some formats provide localized and Unicode versions + * of this string. Applications should use the format-specific + * interface to access them. + * + * num_fixed_sizes :: + * The number of bitmap strikes in the face. Even if the face is + * scalable, there might still be bitmap strikes, which are called + * 'sbits' in that case. + * + * available_sizes :: + * An array of @FT_Bitmap_Size for all bitmap strikes in the face. It + * is set to `NULL` if there is no bitmap strike. + * + * Note that FreeType tries to sanitize the strike data since they are + * sometimes sloppy or incorrect, but this can easily fail. + * + * num_charmaps :: + * The number of charmaps in the face. + * + * charmaps :: + * An array of the charmaps of the face. + * + * generic :: + * A field reserved for client uses. See the @FT_Generic type + * description. + * + * bbox :: + * The font bounding box. Coordinates are expressed in font units (see + * `units_per_EM`). The box is large enough to contain any glyph from + * the font. Thus, `bbox.yMax` can be seen as the 'maximum ascender', + * and `bbox.yMin` as the 'minimum descender'. Only relevant for + * scalable formats. + * + * Note that the bounding box might be off by (at least) one pixel for + * hinted fonts. See @FT_Size_Metrics for further discussion. + * + * Note that the bounding box does not vary in OpenType variation fonts + * and should only be used in relation to the default instance. + * + * units_per_EM :: + * The number of font units per EM square for this face. This is + * typically 2048 for TrueType fonts, and 1000 for Type~1 fonts. Only + * relevant for scalable formats. + * + * ascender :: + * The typographic ascender of the face, expressed in font units. For + * font formats not having this information, it is set to `bbox.yMax`. + * Only relevant for scalable formats. + * + * descender :: + * The typographic descender of the face, expressed in font units. For + * font formats not having this information, it is set to `bbox.yMin`. + * Note that this field is negative for values below the baseline. + * Only relevant for scalable formats. + * + * height :: + * This value is the vertical distance between two consecutive + * baselines, expressed in font units. It is always positive. Only + * relevant for scalable formats. + * + * If you want the global glyph height, use `ascender - descender`. + * + * max_advance_width :: + * The maximum advance width, in font units, for all glyphs in this + * face. This can be used to make word wrapping computations faster. + * Only relevant for scalable formats. + * + * max_advance_height :: + * The maximum advance height, in font units, for all glyphs in this + * face. This is only relevant for vertical layouts, and is set to + * `height` for fonts that do not provide vertical metrics. Only + * relevant for scalable formats. + * + * underline_position :: + * The position, in font units, of the underline line for this face. + * It is the center of the underlining stem. Only relevant for + * scalable formats. + * + * underline_thickness :: + * The thickness, in font units, of the underline for this face. Only + * relevant for scalable formats. + * + * glyph :: + * The face's associated glyph slot(s). + * + * size :: + * The current active size for this face. + * + * charmap :: + * The current active charmap for this face. + * + * @note: + * Fields may be changed after a call to @FT_Attach_File or + * @FT_Attach_Stream. + * + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `ascender`, `descender`, `height`, + * `underline_position`, and `underline_thickness`. + * + * Especially for TrueType fonts see also the documentation for + * @FT_Size_Metrics. + */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /* The following member variables (down to `underline_thickness`) */ + /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /* for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /* private fields, internal to FreeType */ + + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; /* face-specific auto-hinter data */ + void* extensions; /* unused */ + + FT_Face_Internal internal; + + } FT_FaceRec; + + + /************************************************************************** + * + * @enum: + * FT_FACE_FLAG_XXX + * + * @description: + * A list of bit flags used in the `face_flags` field of the @FT_FaceRec + * structure. They inform client applications of properties of the + * corresponding face. + * + * @values: + * FT_FACE_FLAG_SCALABLE :: + * The face contains outline glyphs. Note that a face can contain + * bitmap strikes also, i.e., a face can have both this flag and + * @FT_FACE_FLAG_FIXED_SIZES set. + * + * FT_FACE_FLAG_FIXED_SIZES :: + * The face contains bitmap strikes. See also the `num_fixed_sizes` + * and `available_sizes` fields of @FT_FaceRec. + * + * FT_FACE_FLAG_FIXED_WIDTH :: + * The face contains fixed-width characters (like Courier, Lucida, + * MonoType, etc.). + * + * FT_FACE_FLAG_SFNT :: + * The face uses the SFNT storage scheme. For now, this means TrueType + * and OpenType. + * + * FT_FACE_FLAG_HORIZONTAL :: + * The face contains horizontal glyph metrics. This should be set for + * all common formats. + * + * FT_FACE_FLAG_VERTICAL :: + * The face contains vertical glyph metrics. This is only available in + * some formats, not all of them. + * + * FT_FACE_FLAG_KERNING :: + * The face contains kerning information. If set, the kerning distance + * can be retrieved using the function @FT_Get_Kerning. Otherwise the + * function always returns the vector (0,0). + * + * Note that for TrueType fonts only, FreeType supports both the 'kern' + * table and the basic, pair-wise kerning feature from the 'GPOS' table + * (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though FreeType does + * not support the more advanced GPOS layout features; use a library + * like HarfBuzz for those instead. + * + * FT_FACE_FLAG_FAST_GLYPHS :: + * THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. + * + * FT_FACE_FLAG_MULTIPLE_MASTERS :: + * The face contains multiple masters and is capable of interpolating + * between them. Supported formats are Adobe MM, TrueType GX, and + * OpenType variation fonts. + * + * See section @multiple_masters for API details. + * + * FT_FACE_FLAG_GLYPH_NAMES :: + * The face contains glyph names, which can be retrieved using + * @FT_Get_Glyph_Name. Note that some TrueType fonts contain broken + * glyph name tables. Use the function @FT_Has_PS_Glyph_Names when + * needed. + * + * FT_FACE_FLAG_EXTERNAL_STREAM :: + * Used internally by FreeType to indicate that a face's stream was + * provided by the client application and should not be destroyed when + * @FT_Done_Face is called. Don't read or test this flag. + * + * FT_FACE_FLAG_HINTER :: + * The font driver has a hinting machine of its own. For example, with + * TrueType fonts, it makes sense to use data from the SFNT 'gasp' + * table only if the native TrueType hinting engine (with the bytecode + * interpreter) is available and active. + * + * FT_FACE_FLAG_CID_KEYED :: + * The face is CID-keyed. In that case, the face is not accessed by + * glyph indices but by CID values. For subsetted CID-keyed fonts this + * has the consequence that not all index values are a valid argument + * to @FT_Load_Glyph. Only the CID values for which corresponding + * glyphs in the subsetted font exist make `FT_Load_Glyph` return + * successfully; in all other cases you get an + * `FT_Err_Invalid_Argument` error. + * + * Note that CID-keyed fonts that are in an SFNT wrapper (that is, all + * OpenType/CFF fonts) don't have this flag set since the glyphs are + * accessed in the normal way (using contiguous indices); the + * 'CID-ness' isn't visible to the application. + * + * FT_FACE_FLAG_TRICKY :: + * The face is 'tricky', that is, it always needs the font format's + * native hinting engine to get a reasonable result. A typical example + * is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that + * uses TrueType bytecode instructions to move and scale all of its + * subglyphs. + * + * It is not possible to auto-hint such fonts using + * @FT_LOAD_FORCE_AUTOHINT; it will also ignore @FT_LOAD_NO_HINTING. + * You have to set both @FT_LOAD_NO_HINTING and @FT_LOAD_NO_AUTOHINT to + * really disable hinting; however, you probably never want this except + * for demonstration purposes. + * + * Currently, there are about a dozen TrueType fonts in the list of + * tricky fonts; they are hard-coded in file `ttobjs.c`. + * + * FT_FACE_FLAG_COLOR :: + * [Since 2.5.1] The face has color glyph tables. See @FT_LOAD_COLOR + * for more information. + * + * FT_FACE_FLAG_VARIATION :: + * [Since 2.9] Set if the current face (or named instance) has been + * altered with @FT_Set_MM_Design_Coordinates, + * @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or + * @FT_Set_MM_WeightVector to select a non-default instance. + * + * FT_FACE_FLAG_SVG :: + * [Since 2.12] The face has an 'SVG~' OpenType table. + * + * FT_FACE_FLAG_SBIX :: + * [Since 2.12] The face has an 'sbix' OpenType table *and* outlines. + * For such fonts, @FT_FACE_FLAG_SCALABLE is not set by default to + * retain backward compatibility. + * + * FT_FACE_FLAG_SBIX_OVERLAY :: + * [Since 2.12] The face has an 'sbix' OpenType table where outlines + * should be drawn on top of bitmap strikes. + * + */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) +#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) +#define FT_FACE_FLAG_TRICKY ( 1L << 13 ) +#define FT_FACE_FLAG_COLOR ( 1L << 14 ) +#define FT_FACE_FLAG_VARIATION ( 1L << 15 ) +#define FT_FACE_FLAG_SVG ( 1L << 16 ) +#define FT_FACE_FLAG_SBIX ( 1L << 17 ) +#define FT_FACE_FLAG_SBIX_OVERLAY ( 1L << 18 ) + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_HORIZONTAL + * + * @description: + * A macro that returns true whenever a face object contains horizontal + * metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_HORIZONTAL ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_VERTICAL + * + * @description: + * A macro that returns true whenever a face object contains real + * vertical metrics (and not only synthesized ones). + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_VERTICAL ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_KERNING + * + * @description: + * A macro that returns true whenever a face object contains kerning data + * that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_KERNING ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_SCALABLE + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type~1, Type~42, CID, OpenType/CFF, and + * PFR font formats). + * + */ +#define FT_IS_SCALABLE( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SCALABLE ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_SFNT + * + * @description: + * A macro that returns true whenever a face object contains a font whose + * format is based on the SFNT storage scheme. This usually means: + * TrueType fonts, OpenType fonts, as well as SFNT-based embedded bitmap + * fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SFNT ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_FIXED_WIDTH + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or 'monospace', 'fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_FIXED_SIZES + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes` field of the @FT_FaceRec + * structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_FAST_GLYPHS + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 + + + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + + /************************************************************************** + * + * @macro: + * FT_HAS_GLYPH_NAMES + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_NAMED_INSTANCE + * + * @description: + * A macro that returns true whenever a face object is a named instance + * of a GX or OpenType variation font. + * + * [Since 2.9] Changing the design coordinates with + * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does + * not influence the return value of this macro (only + * @FT_Set_Named_Instance does that). + * + * @since: + * 2.7 + * + */ +#define FT_IS_NAMED_INSTANCE( face ) \ + ( !!( (face)->face_index & 0x7FFF0000L ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_VARIATION + * + * @description: + * A macro that returns true whenever a face object has been altered by + * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, + * @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector. + * + * @since: + * 2.9 + * + */ +#define FT_IS_VARIATION( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_VARIATION ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_CID_KEYED + * + * @description: + * A macro that returns true whenever a face object contains a CID-keyed + * font. See the discussion of @FT_FACE_FLAG_CID_KEYED for more details. + * + * If this macro is true, all functions defined in @FT_CID_H are + * available. + * + */ +#define FT_IS_CID_KEYED( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_CID_KEYED ) ) + + + /************************************************************************** + * + * @macro: + * FT_IS_TRICKY + * + * @description: + * A macro that returns true whenever a face represents a 'tricky' font. + * See the discussion of @FT_FACE_FLAG_TRICKY for more details. + * + */ +#define FT_IS_TRICKY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_TRICKY ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_COLOR + * + * @description: + * A macro that returns true whenever a face object contains tables for + * color glyphs. + * + * @since: + * 2.5.1 + * + */ +#define FT_HAS_COLOR( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_COLOR ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SVG + * + * @description: + * A macro that returns true whenever a face object contains an 'SVG~' + * OpenType table. + * + * @since: + * 2.12 + */ +#define FT_HAS_SVG( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SVG ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table *and* outline glyphs. + * + * Currently, FreeType only supports bitmap glyphs in PNG format for this + * table (i.e., JPEG and TIFF formats are unsupported, as are + * Apple-specific formats not part of the OpenType specification). + * + * @note: + * For backward compatibility, a font with an 'sbix' table is treated as + * a bitmap-only face. Using @FT_Open_Face with + * @FT_PARAM_TAG_IGNORE_SBIX, an application can switch off 'sbix' + * handling so that the face is treated as an ordinary outline font with + * scalable outlines. + * + * Here is some pseudo code that roughly illustrates how to implement + * 'sbix' handling according to the OpenType specification. + * + * ``` + * if ( FT_HAS_SBIX( face ) ) + * { + * // open font as a scalable one without sbix handling + * FT_Face face2; + * FT_Parameter param = { FT_PARAM_TAG_IGNORE_SBIX, NULL }; + * FT_Open_Args args = { FT_OPEN_PARAMS | ..., + * ..., + * 1, ¶m }; + * + * + * FT_Open_Face( library, &args, 0, &face2 ); + * + * available_size` as necessary into + * `preferred_sizes`[*]> + * + * for ( i = 0; i < face->num_fixed_sizes; i++ ) + * { + * size = preferred_sizes[i].size; + * + * error = FT_Set_Pixel_Sizes( face, size, size ); + * + * + * // check whether we have a glyph in a bitmap strike + * error = FT_Load_Glyph( face, + * glyph_index, + * FT_LOAD_SBITS_ONLY | + * FT_LOAD_BITMAP_METRICS_ONLY ); + * if ( error == FT_Err_Invalid_Argument ) + * continue; + * else if ( error ) + * + * else + * break; + * } + * + * if ( i != face->num_fixed_sizes ) + * + * + * if ( i == face->num_fixed_sizes || + * FT_HAS_SBIX_OVERLAY( face ) ) + * + * } + * ``` + * + * [*] Assuming a target value of 400dpi and available strike sizes 100, + * 200, 300, and 400dpi, a possible order might be [400, 200, 300, 100]: + * scaling 200dpi to 400dpi usually gives better results than scaling + * 300dpi to 400dpi; it is also much faster. However, scaling 100dpi to + * 400dpi can yield a too pixelated result, thus the preference might be + * 300dpi over 100dpi. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX_OVERLAY + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table with bit~1 in its `flags` field set, instructing the + * application to overlay the bitmap strike with the corresponding + * outline glyph. See @FT_HAS_SBIX for pseudo code how to use it. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX_OVERLAY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX_OVERLAY ) ) + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @enum: + * FT_STYLE_FLAG_XXX + * + * @description: + * A list of bit flags to indicate the style of a given face. These are + * used in the `style_flags` field of @FT_FaceRec. + * + * @values: + * FT_STYLE_FLAG_ITALIC :: + * The face style is italic or oblique. + * + * FT_STYLE_FLAG_BOLD :: + * The face is bold. + * + * @note: + * The style information as provided by FreeType is very basic. More + * details are beyond the scope and should be done on a higher level (for + * example, by analyzing various fields of the 'OS/2' table in SFNT based + * fonts). + */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @type: + * FT_Size_Internal + * + * @description: + * An opaque handle to an `FT_Size_InternalRec` structure, used to model + * private data of a given @FT_Size object. + */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @struct: + * FT_Size_Metrics + * + * @description: + * The size metrics structure gives the metrics of a size object. + * + * @fields: + * x_ppem :: + * The width of the scaled EM square in pixels, hence the term 'ppem' + * (pixels per EM). It is also referred to as 'nominal width'. + * + * y_ppem :: + * The height of the scaled EM square in pixels, hence the term 'ppem' + * (pixels per EM). It is also referred to as 'nominal height'. + * + * x_scale :: + * A 16.16 fractional scaling value to convert horizontal metrics from + * font units to 26.6 fractional pixels. Only relevant for scalable + * font formats. + * + * y_scale :: + * A 16.16 fractional scaling value to convert vertical metrics from + * font units to 26.6 fractional pixels. Only relevant for scalable + * font formats. + * + * ascender :: + * The ascender in 26.6 fractional pixels, rounded up to an integer + * value. See @FT_FaceRec for the details. + * + * descender :: + * The descender in 26.6 fractional pixels, rounded down to an integer + * value. See @FT_FaceRec for the details. + * + * height :: + * The height in 26.6 fractional pixels, rounded to an integer value. + * See @FT_FaceRec for the details. + * + * max_advance :: + * The maximum advance width in 26.6 fractional pixels, rounded to an + * integer value. See @FT_FaceRec for the details. + * + * @note: + * The scaling values, if relevant, are determined first during a size + * changing operation. The remaining fields are then set by the driver. + * For scalable formats, they are usually set to scaled values of the + * corresponding fields in @FT_FaceRec. Some values like ascender or + * descender are rounded for historical reasons; more precise values (for + * outline fonts) can be derived by scaling the corresponding @FT_FaceRec + * values manually, with code similar to the following. + * + * ``` + * scaled_ascender = FT_MulFix( face->ascender, + * size_metrics->y_scale ); + * ``` + * + * Note that due to glyph hinting and the selected rendering mode these + * values are usually not exact; consequently, they must be treated as + * unreliable with an error margin of at least one pixel! + * + * Indeed, the only way to get the exact metrics is to render _all_ + * glyphs. As this would be a definite performance hit, it is up to + * client applications to perform such computations. + * + * The `FT_Size_Metrics` structure is valid for bitmap fonts also. + * + * + * **TrueType fonts with native bytecode hinting** + * + * All applications that handle TrueType fonts with native hinting must + * be aware that TTFs expect different rounding of vertical font + * dimensions. The application has to cater for this, especially if it + * wants to rely on a TTF's vertical data (for example, to properly align + * box characters vertically). + * + * Only the application knows _in advance_ that it is going to use native + * hinting for TTFs! FreeType, on the other hand, selects the hinting + * mode not at the time of creating an @FT_Size object but much later, + * namely while calling @FT_Load_Glyph. + * + * Here is some pseudo code that illustrates a possible solution. + * + * ``` + * font_format = FT_Get_Font_Format( face ); + * + * if ( !strcmp( font_format, "TrueType" ) && + * do_native_bytecode_hinting ) + * { + * ascender = ROUND( FT_MulFix( face->ascender, + * size_metrics->y_scale ) ); + * descender = ROUND( FT_MulFix( face->descender, + * size_metrics->y_scale ) ); + * } + * else + * { + * ascender = size_metrics->ascender; + * descender = size_metrics->descender; + * } + * + * height = size_metrics->height; + * max_advance = size_metrics->max_advance; + * ``` + */ + typedef struct FT_Size_Metrics_ + { + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ + + } FT_Size_Metrics; + + + /************************************************************************** + * + * @struct: + * FT_SizeRec + * + * @description: + * FreeType root size class structure. A size object models a face + * object at a given size. + * + * @fields: + * face :: + * Handle to the parent face object. + * + * generic :: + * A typeless pointer, unused by the FreeType library or any of its + * drivers. It can be used by client applications to link their own + * data to each size object. + * + * metrics :: + * Metrics for this size object. This field is read-only. + */ + typedef struct FT_SizeRec_ + { + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; + + } FT_SizeRec; + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @struct: + * FT_SubGlyph + * + * @description: + * The subglyph structure is an internal object used to describe + * subglyphs (for example, in the case of composites). + * + * @note: + * The subglyph implementation is not part of the high-level API, hence + * the forward structure declaration. + * + * You can however retrieve subglyph information with + * @FT_Get_SubGlyph_Info. + */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; + + + /************************************************************************** + * + * @type: + * FT_Slot_Internal + * + * @description: + * An opaque handle to an `FT_Slot_InternalRec` structure, used to model + * private data of a given @FT_GlyphSlot object. + */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @struct: + * FT_GlyphSlotRec + * + * @description: + * FreeType root glyph slot class structure. A glyph slot is a container + * where individual glyphs can be loaded, be they in outline or bitmap + * format. + * + * @fields: + * library :: + * A handle to the FreeType library instance this slot belongs to. + * + * face :: + * A handle to the parent face object. + * + * next :: + * In some cases (like some font tools), several glyph slots per face + * object can be a good thing. As this is rare, the glyph slots are + * listed through a direct, single-linked list using its `next` field. + * + * glyph_index :: + * [Since 2.10] The glyph index passed as an argument to @FT_Load_Glyph + * while initializing the glyph slot. + * + * generic :: + * A typeless pointer unused by the FreeType library or any of its + * drivers. It can be used by client applications to link their own + * data to each glyph slot object. + * + * metrics :: + * The metrics of the last loaded glyph in the slot. The returned + * values depend on the last load flags (see the @FT_Load_Glyph API + * function) and can be expressed either in 26.6 fractional pixels or + * font units. + * + * Note that even when the glyph image is transformed, the metrics are + * not. + * + * linearHoriAdvance :: + * The advance width of the unhinted glyph. Its value is expressed in + * 16.16 fractional pixels, unless @FT_LOAD_LINEAR_DESIGN is set when + * loading the glyph. This field can be important to perform correct + * WYSIWYG layout. Only relevant for scalable glyphs. + * + * linearVertAdvance :: + * The advance height of the unhinted glyph. Its value is expressed in + * 16.16 fractional pixels, unless @FT_LOAD_LINEAR_DESIGN is set when + * loading the glyph. This field can be important to perform correct + * WYSIWYG layout. Only relevant for scalable glyphs. + * + * advance :: + * This shorthand is, depending on @FT_LOAD_IGNORE_TRANSFORM, the + * transformed (hinted) advance width for the glyph, in 26.6 fractional + * pixel format. As specified with @FT_LOAD_VERTICAL_LAYOUT, it uses + * either the `horiAdvance` or the `vertAdvance` value of `metrics` + * field. + * + * format :: + * This field indicates the format of the image contained in the glyph + * slot. Typically @FT_GLYPH_FORMAT_BITMAP, @FT_GLYPH_FORMAT_OUTLINE, + * or @FT_GLYPH_FORMAT_COMPOSITE, but other values are possible. + * + * bitmap :: + * This field is used as a bitmap descriptor. Note that the address + * and content of the bitmap buffer can change between calls of + * @FT_Load_Glyph and a few other functions. + * + * bitmap_left :: + * The bitmap's left bearing expressed in integer pixels. + * + * bitmap_top :: + * The bitmap's top bearing expressed in integer pixels. This is the + * distance from the baseline to the top-most glyph scanline, upwards + * y~coordinates being **positive**. + * + * outline :: + * The outline descriptor for the current glyph image if its format is + * @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is loaded, `outline` can be + * transformed, distorted, emboldened, etc. However, it must not be + * freed. + * + * [Since 2.10.1] If @FT_LOAD_NO_SCALE is set, outline coordinates of + * OpenType variation fonts for a selected instance are internally + * handled as 26.6 fractional font units but returned as (rounded) + * integers, as expected. To get unrounded font units, don't use + * @FT_LOAD_NO_SCALE but load the glyph with @FT_LOAD_NO_HINTING and + * scale it, using the font's `units_per_EM` value as the ppem. + * + * num_subglyphs :: + * The number of subglyphs in a composite glyph. This field is only + * valid for the composite glyph format that should normally only be + * loaded with the @FT_LOAD_NO_RECURSE flag. + * + * subglyphs :: + * An array of subglyph descriptors for composite glyphs. There are + * `num_subglyphs` elements in there. Currently internal to FreeType. + * + * control_data :: + * Certain font drivers can also return the control data for a given + * glyph image (e.g. TrueType bytecode, Type~1 charstrings, etc.). + * This field is a pointer to such data; it is currently internal to + * FreeType. + * + * control_len :: + * This is the length in bytes of the control data. Currently internal + * to FreeType. + * + * other :: + * Reserved. + * + * lsb_delta :: + * The difference between hinted and unhinted left side bearing while + * auto-hinting is active. Zero otherwise. + * + * rsb_delta :: + * The difference between hinted and unhinted right side bearing while + * auto-hinting is active. Zero otherwise. + * + * @note: + * If @FT_Load_Glyph is called with default flags (see @FT_LOAD_DEFAULT) + * the glyph image is loaded in the glyph slot in its native format + * (e.g., an outline glyph for TrueType and Type~1 formats). [Since 2.9] + * The prospective bitmap metrics are calculated according to + * @FT_LOAD_TARGET_XXX and other flags even for the outline glyph, even + * if @FT_LOAD_RENDER is not set. + * + * This image can later be converted into a bitmap by calling + * @FT_Render_Glyph. This function searches the current renderer for the + * native image's format, then invokes it. + * + * The renderer is in charge of transforming the native image through the + * slot's face transformation fields, then converting it into a bitmap + * that is returned in `slot->bitmap`. + * + * Note that `slot->bitmap_left` and `slot->bitmap_top` are also used to + * specify the position of the bitmap relative to the current pen + * position (e.g., coordinates (0,0) on the baseline). Of course, + * `slot->format` is also changed to @FT_GLYPH_FORMAT_BITMAP. + * + * Here is a small pseudo code fragment that shows how to use `lsb_delta` + * and `rsb_delta` to do fractional positioning of glyphs: + * + * ``` + * FT_GlyphSlot slot = face->glyph; + * FT_Pos origin_x = 0; + * + * + * for all glyphs do + * + * + * FT_Outline_Translate( slot->outline, origin_x & 63, 0 ); + * + * + * + * + * + * origin_x += slot->advance.x; + * origin_x += slot->lsb_delta - slot->rsb_delta; + * endfor + * ``` + * + * Here is another small pseudo code fragment that shows how to use + * `lsb_delta` and `rsb_delta` to improve integer positioning of glyphs: + * + * ``` + * FT_GlyphSlot slot = face->glyph; + * FT_Pos origin_x = 0; + * FT_Pos prev_rsb_delta = 0; + * + * + * for all glyphs do + * + * + * + * + * if ( prev_rsb_delta - slot->lsb_delta > 32 ) + * origin_x -= 64; + * else if ( prev_rsb_delta - slot->lsb_delta < -31 ) + * origin_x += 64; + * + * prev_rsb_delta = slot->rsb_delta; + * + * + * + * origin_x += slot->advance.x; + * endfor + * ``` + * + * If you use strong auto-hinting, you **must** apply these delta values! + * Otherwise you will experience far too large inter-glyph spacing at + * small rendering sizes in most cases. Note that it doesn't harm to use + * the above code for other hinting modes also, since the delta values + * are zero then. + */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt glyph_index; /* new in 2.10; was reserved previously */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; + + } FT_GlyphSlotRec; + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* F U N C T I O N S */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @function: + * FT_Init_FreeType + * + * @description: + * Initialize a new FreeType library object. The set of modules that are + * registered by this function is determined at build time. + * + * @output: + * alibrary :: + * A handle to a new library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * In case you want to provide your own memory allocating routines, use + * @FT_New_Library instead, followed by a call to @FT_Add_Default_Modules + * (or a series of calls to @FT_Add_Module) and + * @FT_Set_Default_Properties. + * + * See the documentation of @FT_Library and @FT_Face for multi-threading + * issues. + * + * If you need reference-counting (cf. @FT_Reference_Library), use + * @FT_New_Library and @FT_Done_Library. + * + * If compilation option `FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES` is + * set, this function reads the `FREETYPE_PROPERTIES` environment + * variable to control driver properties. See section @properties for + * more. + */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); + + + /************************************************************************** + * + * @function: + * FT_Done_FreeType + * + * @description: + * Destroy a given FreeType library object and all of its children, + * including resources, drivers, faces, sizes, etc. + * + * @input: + * library :: + * A handle to the target library object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @enum: + * FT_OPEN_XXX + * + * @description: + * A list of bit field constants used within the `flags` field of the + * @FT_Open_Args structure. + * + * @values: + * FT_OPEN_MEMORY :: + * This is a memory-based stream. + * + * FT_OPEN_STREAM :: + * Copy the stream from the `stream` field. + * + * FT_OPEN_PATHNAME :: + * Create a new input stream from a C~path name. + * + * FT_OPEN_DRIVER :: + * Use the `driver` field. + * + * FT_OPEN_PARAMS :: + * Use the `num_params` and `params` fields. + * + * @note: + * The `FT_OPEN_MEMORY`, `FT_OPEN_STREAM`, and `FT_OPEN_PATHNAME` flags + * are mutually exclusive. + */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + + + /* these constants are deprecated; use the corresponding `FT_OPEN_XXX` */ + /* values instead */ +#define ft_open_memory FT_OPEN_MEMORY +#define ft_open_stream FT_OPEN_STREAM +#define ft_open_pathname FT_OPEN_PATHNAME +#define ft_open_driver FT_OPEN_DRIVER +#define ft_open_params FT_OPEN_PARAMS + + + /************************************************************************** + * + * @struct: + * FT_Parameter + * + * @description: + * A simple structure to pass more or less generic parameters to + * @FT_Open_Face and @FT_Face_Properties. + * + * @fields: + * tag :: + * A four-byte identification tag. + * + * data :: + * A pointer to the parameter data. + * + * @note: + * The ID and function of parameters are driver-specific. See section + * @parameter_tags for more information. + */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + + } FT_Parameter; + + + /************************************************************************** + * + * @struct: + * FT_Open_Args + * + * @description: + * A structure to indicate how to open a new font file or stream. A + * pointer to such a structure can be used as a parameter for the + * functions @FT_Open_Face and @FT_Attach_Stream. + * + * @fields: + * flags :: + * A set of bit flags indicating how to use the structure. + * + * memory_base :: + * The first byte of the file in memory. + * + * memory_size :: + * The size in bytes of the file in memory. + * + * pathname :: + * A pointer to an 8-bit file pathname, which must be a C~string (i.e., + * no null bytes except at the very end). The pointer is not owned by + * FreeType. + * + * stream :: + * A handle to a source stream object. + * + * driver :: + * This field is exclusively used by @FT_Open_Face; it simply specifies + * the font driver to use for opening the face. If set to `NULL`, + * FreeType tries to load the face with each one of the drivers in its + * list. + * + * num_params :: + * The number of extra parameters. + * + * params :: + * Extra parameters passed to the font driver when opening a new face. + * + * @note: + * The stream type is determined by the contents of `flags`: + * + * If the @FT_OPEN_MEMORY bit is set, assume that this is a memory file + * of `memory_size` bytes, located at `memory_address`. The data are not + * copied, and the client is responsible for releasing and destroying + * them _after_ the corresponding call to @FT_Done_Face. + * + * Otherwise, if the @FT_OPEN_STREAM bit is set, assume that a custom + * input stream `stream` is used. + * + * Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this is a + * normal file and use `pathname` to open it. + * + * If none of the above bits are set or if multiple are set at the same + * time, the flags are invalid and @FT_Open_Face fails. + * + * If the @FT_OPEN_DRIVER bit is set, @FT_Open_Face only tries to open + * the file with the driver whose handler is in `driver`. + * + * If the @FT_OPEN_PARAMS bit is set, the parameters given by + * `num_params` and `params` is used. They are ignored otherwise. + * + * Ideally, both the `pathname` and `params` fields should be tagged as + * 'const'; this is missing for API backward compatibility. In other + * words, applications should treat them as read-only. + */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + + } FT_Open_Args; + + + /************************************************************************** + * + * @function: + * FT_New_Face + * + * @description: + * Call @FT_Open_Face to open a font by its pathname. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * pathname :: + * A path to the font file. + * + * face_index :: + * See @FT_Open_Face for a detailed description of this parameter. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `pathname` string should be recognizable as such by a standard + * `fopen` call on your system; in particular, this means that `pathname` + * must not contain null bytes. If that is not sufficient to address all + * file name possibilities (for example, to handle wide character file + * names on Windows in UTF-16 encoding) you might use @FT_Open_Face to + * pass a memory array or a stream object instead. + * + * Use @FT_Done_Face to destroy the created @FT_Face object (along with + * its slot and sizes). + */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_New_Memory_Face + * + * @description: + * Call @FT_Open_Face to open a font that has been loaded into memory. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * file_base :: + * A pointer to the beginning of the font data. + * + * file_size :: + * The size of the memory chunk used by the font data. + * + * face_index :: + * See @FT_Open_Face for a detailed description of this parameter. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You must not deallocate the memory before calling @FT_Done_Face. + */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_Open_Face + * + * @description: + * Create a face object from a given resource described by @FT_Open_Args. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * args :: + * A pointer to an `FT_Open_Args` structure that must be filled by the + * caller. + * + * face_index :: + * This field holds two different values. Bits 0-15 are the index of + * the face in the font file (starting with value~0). Set it to~0 if + * there is only one face in the font file. + * + * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation + * fonts only, specifying the named instance index for the current face + * index (starting with value~1; value~0 makes FreeType ignore named + * instances). For non-variation fonts, bits 16-30 are ignored. + * Assuming that you want to access the third named instance in face~4, + * `face_index` should be set to 0x00030004. If you want to access + * face~4 without variation handling, simply set `face_index` to + * value~4. + * + * `FT_Open_Face` and its siblings can be used to quickly check whether + * the font format of a given font resource is supported by FreeType. + * In general, if the `face_index` argument is negative, the function's + * return value is~0 if the font format is recognized, or non-zero + * otherwise. The function allocates a more or less empty face handle + * in `*aface` (if `aface` isn't `NULL`); the only two useful fields in + * this special case are `face->num_faces` and `face->style_flags`. + * For any negative value of `face_index`, `face->num_faces` gives the + * number of faces within the font file. For the negative value + * '-(N+1)' (with 'N' a non-negative 16-bit value), bits 16-30 in + * `face->style_flags` give the number of named instances in face 'N' + * if we have a variation font (or zero otherwise). After examination, + * the returned @FT_Face structure should be deallocated with a call to + * @FT_Done_Face. + * + * @output: + * aface :: + * A handle to a new face object. If `face_index` is greater than or + * equal to zero, it must be non-`NULL`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Unlike FreeType 1.x, this function automatically creates a glyph slot + * for the face object that can be accessed directly through + * `face->glyph`. + * + * Each new face object created with this function also owns a default + * @FT_Size object, accessible as `face->size`. + * + * One @FT_Library instance can have multiple face objects, that is, + * @FT_Open_Face and its siblings can be called multiple times using the + * same `library` argument. + * + * See the discussion of reference counters in the description of + * @FT_Reference_Face. + * + * If `FT_OPEN_STREAM` is set in `args->flags`, the stream in + * `args->stream` is automatically closed before this function returns + * any error (including `FT_Err_Invalid_Argument`). + * + * @example: + * To loop over all faces, use code similar to the following snippet + * (omitting the error handling). + * + * ``` + * ... + * FT_Face face; + * FT_Long i, num_faces; + * + * + * error = FT_Open_Face( library, args, -1, &face ); + * if ( error ) { ... } + * + * num_faces = face->num_faces; + * FT_Done_Face( face ); + * + * for ( i = 0; i < num_faces; i++ ) + * { + * ... + * error = FT_Open_Face( library, args, i, &face ); + * ... + * FT_Done_Face( face ); + * ... + * } + * ``` + * + * To loop over all valid values for `face_index`, use something similar + * to the following snippet, again without error handling. The code + * accesses all faces immediately (thus only a single call of + * `FT_Open_Face` within the do-loop), with and without named instances. + * + * ``` + * ... + * FT_Face face; + * + * FT_Long num_faces = 0; + * FT_Long num_instances = 0; + * + * FT_Long face_idx = 0; + * FT_Long instance_idx = 0; + * + * + * do + * { + * FT_Long id = ( instance_idx << 16 ) + face_idx; + * + * + * error = FT_Open_Face( library, args, id, &face ); + * if ( error ) { ... } + * + * num_faces = face->num_faces; + * num_instances = face->style_flags >> 16; + * + * ... + * + * FT_Done_Face( face ); + * + * if ( instance_idx < num_instances ) + * instance_idx++; + * else + * { + * face_idx++; + * instance_idx = 0; + * } + * + * } while ( face_idx < num_faces ) + * ``` + */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); + + + /************************************************************************** + * + * @function: + * FT_Attach_File + * + * @description: + * Call @FT_Attach_Stream to attach a file. + * + * @inout: + * face :: + * The target face object. + * + * @input: + * filepathname :: + * The pathname. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); + + + /************************************************************************** + * + * @function: + * FT_Attach_Stream + * + * @description: + * 'Attach' data to a face object. Normally, this is used to read + * additional information for the face object. For example, you can + * attach an AFM file that comes with a Type~1 font to get the kerning + * values and other metrics. + * + * @inout: + * face :: + * The target face object. + * + * @input: + * parameters :: + * A pointer to @FT_Open_Args that must be filled by the caller. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The meaning of the 'attach' (i.e., what really happens when the new + * file is read) is not fixed by FreeType itself. It really depends on + * the font format (and thus the font driver). + * + * Client applications are expected to know what they are doing when + * invoking this function. Most drivers simply do not implement file or + * stream attachments. + */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ); + + + /************************************************************************** + * + * @function: + * FT_Reference_Face + * + * @description: + * A counter gets initialized to~1 at the time an @FT_Face structure is + * created. This function increments the counter. @FT_Done_Face then + * only destroys a face if the counter is~1, otherwise it simply + * decrements the counter. + * + * This function helps in managing life-cycles of structures that + * reference @FT_Face objects. + * + * @input: + * face :: + * A handle to a target face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.4.2 + * + */ + FT_EXPORT( FT_Error ) + FT_Reference_Face( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Done_Face + * + * @description: + * Discard a given face object, as well as all of its child slots and + * sizes. + * + * @input: + * face :: + * A handle to a target face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Face. + */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @function: + * FT_Select_Size + * + * @description: + * Select a bitmap strike. To be more precise, this function sets the + * scaling factors of the active @FT_Size object in a face so that + * bitmaps from this particular strike are taken by @FT_Load_Glyph and + * friends. + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * strike_index :: + * The index of the bitmap strike in the `available_sizes` field of + * @FT_FaceRec structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For bitmaps embedded in outline fonts it is common that only a subset + * of the available glyphs at a given ppem value is available. FreeType + * silently uses outlines if there is no bitmap for a given glyph index. + * + * For GX and OpenType variation fonts, a bitmap strike makes sense only + * if the default instance is active (that is, no glyph variation takes + * place); otherwise, FreeType simply ignores bitmap strikes. The same + * is true for all named instances that are different from the default + * instance. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); + + + /************************************************************************** + * + * @enum: + * FT_Size_Request_Type + * + * @description: + * An enumeration type that lists the supported size request types, i.e., + * what input size (in font units) maps to the requested output size (in + * pixels, as computed from the arguments of @FT_Size_Request). + * + * @values: + * FT_SIZE_REQUEST_TYPE_NOMINAL :: + * The nominal size. The `units_per_EM` field of @FT_FaceRec is used + * to determine both scaling values. + * + * This is the standard scaling found in most applications. In + * particular, use this size request type for TrueType fonts if they + * provide optical scaling or something similar. Note, however, that + * `units_per_EM` is a rather abstract value which bears no relation to + * the actual size of the glyphs in a font. + * + * FT_SIZE_REQUEST_TYPE_REAL_DIM :: + * The real dimension. The sum of the `ascender` and (minus of) the + * `descender` fields of @FT_FaceRec is used to determine both scaling + * values. + * + * FT_SIZE_REQUEST_TYPE_BBOX :: + * The font bounding box. The width and height of the `bbox` field of + * @FT_FaceRec are used to determine the horizontal and vertical + * scaling value, respectively. + * + * FT_SIZE_REQUEST_TYPE_CELL :: + * The `max_advance_width` field of @FT_FaceRec is used to determine + * the horizontal scaling value; the vertical scaling value is + * determined the same way as @FT_SIZE_REQUEST_TYPE_REAL_DIM does. + * Finally, both scaling values are set to the smaller one. This type + * is useful if you want to specify the font size for, say, a window of + * a given dimension and 80x24 cells. + * + * FT_SIZE_REQUEST_TYPE_SCALES :: + * Specify the scaling values directly. + * + * @note: + * The above descriptions only apply to scalable formats. For bitmap + * formats, the behaviour is up to the driver. + * + * See the note section of @FT_Size_Metrics if you wonder how size + * requesting relates to scaling values. + */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + + } FT_Size_Request_Type; + + + /************************************************************************** + * + * @struct: + * FT_Size_RequestRec + * + * @description: + * A structure to model a size request. + * + * @fields: + * type :: + * See @FT_Size_Request_Type. + * + * width :: + * The desired width, given as a 26.6 fractional point value (with 72pt + * = 1in). + * + * height :: + * The desired height, given as a 26.6 fractional point value (with + * 72pt = 1in). + * + * horiResolution :: + * The horizontal resolution (dpi, i.e., pixels per inch). If set to + * zero, `width` is treated as a 26.6 fractional **pixel** value, which + * gets internally rounded to an integer. + * + * vertResolution :: + * The vertical resolution (dpi, i.e., pixels per inch). If set to + * zero, `height` is treated as a 26.6 fractional **pixel** value, + * which gets internally rounded to an integer. + * + * @note: + * If `width` is zero, the horizontal scaling value is set equal to the + * vertical scaling value, and vice versa. + * + * If `type` is `FT_SIZE_REQUEST_TYPE_SCALES`, `width` and `height` are + * interpreted directly as 16.16 fractional scaling values, without any + * further modification, and both `horiResolution` and `vertResolution` + * are ignored. + */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + + } FT_Size_RequestRec; + + + /************************************************************************** + * + * @struct: + * FT_Size_Request + * + * @description: + * A handle to a size request structure. + */ + typedef struct FT_Size_RequestRec_ *FT_Size_Request; + + + /************************************************************************** + * + * @function: + * FT_Request_Size + * + * @description: + * Resize the scale of the active @FT_Size object in a face. + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * req :: + * A pointer to a @FT_Size_RequestRec. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Although drivers may select the bitmap strike matching the request, + * you should not rely on this if you intend to select a particular + * bitmap strike. Use @FT_Select_Size instead in that case. + * + * The relation between the requested size and the resulting glyph size + * is dependent entirely on how the size is defined in the source face. + * The font designer chooses the final size of each glyph relative to + * this size. For more information refer to + * 'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'. + * + * Contrary to @FT_Set_Char_Size, this function doesn't have special code + * to normalize zero-valued widths, heights, or resolutions, which are + * treated as @FT_LOAD_NO_SCALE. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); + + + /************************************************************************** + * + * @function: + * FT_Set_Char_Size + * + * @description: + * Call @FT_Request_Size to request the nominal size (in points). + * + * @inout: + * face :: + * A handle to a target face object. + * + * @input: + * char_width :: + * The nominal width, in 26.6 fractional points. + * + * char_height :: + * The nominal height, in 26.6 fractional points. + * + * horz_resolution :: + * The horizontal resolution in dpi. + * + * vert_resolution :: + * The vertical resolution in dpi. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * While this function allows fractional points as input values, the + * resulting ppem value for the given resolution is always rounded to the + * nearest integer. + * + * If either the character width or height is zero, it is set equal to + * the other value. + * + * If either the horizontal or vertical resolution is zero, it is set + * equal to the other value. + * + * A character width or height smaller than 1pt is set to 1pt; if both + * resolution values are zero, they are set to 72dpi. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + + /************************************************************************** + * + * @function: + * FT_Set_Pixel_Sizes + * + * @description: + * Call @FT_Request_Size to request the nominal size (in pixels). + * + * @inout: + * face :: + * A handle to the target face object. + * + * @input: + * pixel_width :: + * The nominal width, in pixels. + * + * pixel_height :: + * The nominal height, in pixels. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should not rely on the resulting glyphs matching or being + * constrained to this pixel size. Refer to @FT_Request_Size to + * understand how requested sizes relate to actual sizes. + * + * Don't use this function if you are using the FreeType cache API. + */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @function: + * FT_Load_Glyph + * + * @description: + * Load a glyph into the glyph slot of a face object. + * + * @inout: + * face :: + * A handle to the target face object where the glyph is loaded. + * + * @input: + * glyph_index :: + * The index of the glyph in the font file. For CID-keyed fonts + * (either in PS or in CFF format) this argument specifies the CID + * value. + * + * load_flags :: + * A flag indicating what to load for this glyph. The @FT_LOAD_XXX + * flags can be used to control the glyph loading process (e.g., + * whether the outline should be scaled, whether to load bitmaps or + * not, whether to hint the outline, etc). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For proper scaling and hinting, the active @FT_Size object owned by + * the face has to be meaningfully initialized by calling + * @FT_Set_Char_Size before this function, for example. The loaded + * glyph may be transformed. See @FT_Set_Transform for the details. + * + * For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned + * for invalid CID values (that is, for CID values that don't have a + * corresponding glyph in the font). See the discussion of the + * @FT_FACE_FLAG_CID_KEYED flag for more details. + * + * If you receive `FT_Err_Glyph_Too_Big`, try getting the glyph outline + * at EM size, then scale it manually and fill it as a graphics + * operation. + */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @function: + * FT_Load_Char + * + * @description: + * Load a glyph into the glyph slot of a face object, accessed by its + * character code. + * + * @inout: + * face :: + * A handle to a target face object where the glyph is loaded. + * + * @input: + * char_code :: + * The glyph's character code, according to the current charmap used in + * the face. + * + * load_flags :: + * A flag indicating what to load for this glyph. The @FT_LOAD_XXX + * constants can be used to control the glyph loading process (e.g., + * whether the outline should be scaled, whether to load bitmaps or + * not, whether to hint the outline, etc). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. + * + * Many fonts contain glyphs that can't be loaded by this function since + * its glyph indices are not listed in any of the font's charmaps. + * + * If no active cmap is set up (i.e., `face->charmap` is zero), the call + * to @FT_Get_Char_Index is omitted, and the function behaves identically + * to @FT_Load_Glyph. + */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit field constants for @FT_Load_Glyph to indicate what kind + * of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to~0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. The + * bitmap data can be accessed from the glyph slot (see note below). + * + * 2. If no embedded bitmap is searched for or found, FreeType looks + * for a scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then 'hinted' to the pixel grid in + * order to optimize it. The outline data can be accessed from the + * glyph slot (see note below). + * + * Note that by default the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the loaded outline glyph but keep it in font units. + * This flag is also assumed if @FT_Size owned by the face was not + * properly initialized. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * If the font is 'tricky' (see @FT_FACE_FLAG_TRICKY for more), using + * `FT_LOAD_NO_SCALE` usually yields meaningless outlines because the + * subglyphs must be scaled and positioned with hinting instructions. + * This can be solved by loading the font without `FT_LOAD_NO_SCALE` + * and setting the character size to `font->units_per_EM`. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates 'blurrier' bitmap glyphs + * when the glyphs are rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_SBITS_ONLY :: + * [Since 2.12] This is the opposite of @FT_LOAD_NO_BITMAP, more or + * less: @FT_Load_Glyph returns `FT_Err_Invalid_Argument` if the face + * contains a bitmap strike for the given size (or the strike selected + * by @FT_Select_Size) but there is no glyph in the strike. + * + * Note that this load flag was part of FreeType since version 2.0.6 + * but previously tagged as internal. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. In particular, the + * `advance` value in the @FT_GlyphSlotRec structure is set to the + * `vertAdvance` value of the `metrics` field. + * + * In case @FT_HAS_VERTICAL doesn't return true, you shouldn't use this + * flag currently. Reason is that in this case vertical metrics get + * synthesized, and those values are not always consistent across + * various font formats. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Prefer the auto-hinter over the font's native hinter. See also the + * note below. + * + * FT_LOAD_PEDANTIC :: + * Make the font driver perform pedantic verifications during glyph + * loading and hinting. This is mostly used to detect broken glyphs in + * fonts. By default, FreeType tries to handle broken fonts also. + * + * In particular, errors from the TrueType bytecode engine are not + * passed to the application if this flag is not set; this might result + * in partially hinted or distorted glyphs in case a glyph's bytecode + * is buggy. + * + * FT_LOAD_NO_RECURSE :: + * Don't load composite glyphs recursively. Instead, the font driver + * fills the `num_subglyph` and `subglyphs` values of the glyph slot; + * it also sets `glyph->format` to @FT_GLYPH_FORMAT_COMPOSITE. The + * description of subglyphs can then be accessed with + * @FT_Get_SubGlyph_Info. + * + * Don't use this flag for retrieving metrics information since some + * font drivers only return rudimentary data. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Ignore the transform matrix set by @FT_Set_Transform. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8~pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should rather use @FT_LOAD_TARGET_MONO so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Keep `linearHoriAdvance` and `linearVertAdvance` fields of + * @FT_GlyphSlotRec in font units. See @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable the auto-hinter. See also the note below. + * + * FT_LOAD_COLOR :: + * Load colored glyphs. FreeType searches in the following order; + * there are slight differences depending on the font format. + * + * [Since 2.5] Load embedded color bitmap images (provided + * @FT_LOAD_NO_BITMAP is not set). The resulting color bitmaps, if + * available, have the @FT_PIXEL_MODE_BGRA format, with pre-multiplied + * color channels. If the flag is not set and color bitmaps are found, + * they are converted to 256-level gray bitmaps, using the + * @FT_PIXEL_MODE_GRAY format. + * + * [Since 2.12] If the glyph index maps to an entry in the face's + * 'SVG~' table, load the associated SVG document from this table and + * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG + * ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set). Note that + * FreeType itself can't render SVG documents; however, the library + * provides hooks to seamlessly integrate an external renderer. See + * sections @ot_svg_driver and @svg_fonts for more. + * + * [Since 2.10, experimental] If the glyph index maps to an entry in + * the face's 'COLR' table with a 'CPAL' palette table (as defined in + * the OpenType specification), make @FT_Render_Glyph provide a default + * blending of the color glyph layers associated with the glyph index, + * using the same bitmap format as embedded color bitmap images. This + * is mainly for convenience and works only for glyphs in 'COLR' v0 + * tables (or glyphs in 'COLR' v1 tables that exclusively use v0 + * features). For full control of color layers use + * @FT_Get_Color_Glyph_Layer and FreeType's color functions like + * @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering + * so that the client application can handle blending by itself. + * + * FT_LOAD_NO_SVG :: + * [Since 2.13.1] Ignore SVG glyph data when loading. + * + * FT_LOAD_COMPUTE_METRICS :: + * [Since 2.6.1] Compute glyph metrics from the glyph data, without the + * use of bundled metrics tables (for example, the 'hdmx' table in + * TrueType fonts). This flag is mainly used by font validating or + * font editing applications, which need to ignore, verify, or edit + * those tables. + * + * Currently, this flag is only implemented for TrueType fonts. + * + * FT_LOAD_BITMAP_METRICS_ONLY :: + * [Since 2.7.1] Request loading of the metrics and bitmap image + * information of a (possibly embedded) bitmap glyph without allocating + * or copying the bitmap image data itself. No effect if the target + * glyph is not a bitmap image. + * + * This flag unsets @FT_LOAD_RENDER. + * + * FT_LOAD_CROP_BITMAP :: + * Ignored. Deprecated. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Ignored. Deprecated. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be used + * at all. + * + * See the description of @FT_FACE_FLAG_TRICKY for a special exception + * (affecting only a handful of Asian fonts). + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + * + * Note that the auto-hinter needs a valid Unicode cmap (either a native + * one or synthesized by FreeType) for producing correct results. If a + * font provides an incorrect mapping (for example, assigning the + * character code U+005A, LATIN CAPITAL LETTER~Z, to a glyph depicting a + * mathematical integral sign), the auto-hinter might produce useless + * results. + * + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE ( 1L << 0 ) +#define FT_LOAD_NO_HINTING ( 1L << 1 ) +#define FT_LOAD_RENDER ( 1L << 2 ) +#define FT_LOAD_NO_BITMAP ( 1L << 3 ) +#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) +#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) +#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) +#define FT_LOAD_PEDANTIC ( 1L << 7 ) +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) +#define FT_LOAD_NO_RECURSE ( 1L << 10 ) +#define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) +#define FT_LOAD_MONOCHROME ( 1L << 12 ) +#define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) +#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) +#define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) + /* Bits 16-19 are used by `FT_LOAD_TARGET_` */ +#define FT_LOAD_COLOR ( 1L << 20 ) +#define FT_LOAD_COMPUTE_METRICS ( 1L << 21 ) +#define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 ) +#define FT_LOAD_NO_SVG ( 1L << 24 ) + + /* */ + + /* used internally only by certain font drivers */ +#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) +#define FT_LOAD_SVG_ONLY ( 1L << 23 ) + + + /************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values to select a specific hinting algorithm for the + * hinter. You should OR one of these values to your `load_flags` when + * calling @FT_Load_Glyph. + * + * Note that a font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * The default hinting algorithm, optimized for standard gray-level + * rendering. For monochrome output, use @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for gray-level modes. Many generated + * glyphs are fuzzier but better resemble their original shape. This + * is achieved by snapping glyphs to the pixel grid only vertically + * (Y-axis), as is done by FreeType's new CFF engine or Microsoft's + * ClearType font renderer. This preserves inter-glyph spacing in + * horizontal text. The snapping is done either by the native font + * driver, if the driver itself and the font support it, or by the + * auto-hinter. + * + * Advance widths are rounded to integer values; however, using the + * `lsb_delta` and `rsb_delta` fields of @FT_GlyphSlotRec, it is + * possible to get fractional advance widths for subpixel positioning + * (which is recommended to use). + * + * If configuration option `AF_CONFIG_OPTION_TT_SIZE_METRICS` is + * active, TrueType-like metrics are used to make this mode behave + * similarly as in unpatched FreeType versions between 2.4.6 and 2.7.1 + * (inclusive). + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * Note that for outline fonts only the TrueType font driver has proper + * monochrome hinting support, provided the TTFs contain hints for B/W + * rendering (which most fonts no longer provide). If these conditions + * are not met it is very likely that you get ugly results at smaller + * sizes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_LIGHT optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the `FT_LOAD_TARGET_XXX` values in your + * `load_flags`. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode that matches the used algorithm + * best). An exception is `FT_LOAD_TARGET_MONO` since it implies + * @FT_LOAD_MONOCHROME. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the 'light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * ``` + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * ``` + * + * In general, you should stick with one rendering mode. For example, + * switching between @FT_LOAD_TARGET_NORMAL and @FT_LOAD_TARGET_MONO + * enforces a lot of recomputation for TrueType fonts, which is slow. + * Another reason is caching: Selecting a different mode usually causes + * changes in both the outlines and the rasterized bitmaps; it is thus + * necessary to empty the cache after a mode switch to avoid false hits. + * + */ +#define FT_LOAD_TARGET_( x ) ( FT_STATIC_CAST( FT_Int32, (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + + + /************************************************************************** + * + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + * + */ +#define FT_LOAD_TARGET_MODE( x ) \ + FT_STATIC_CAST( FT_Render_Mode, ( (x) >> 16 ) & 15 ) + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + + /************************************************************************** + * + * @function: + * FT_Set_Transform + * + * @description: + * Set the transformation that is applied to glyph images when they are + * loaded into a glyph slot through @FT_Load_Glyph. + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * matrix :: + * A pointer to the transformation's 2x2 matrix. Use `NULL` for the + * identity matrix. + * delta :: + * A pointer to the translation vector. Use `NULL` for the null + * vector. + * + * @note: + * This function is provided as a convenience, but keep in mind that + * @FT_Matrix coefficients are only 16.16 fixed-point values, which can + * limit the accuracy of the results. Using floating-point computations + * to perform the transform directly in client code instead will always + * yield better numbers. + * + * The transformation is only applied to scalable image formats after the + * glyph has been loaded. It means that hinting is unaltered by the + * transformation and is performed on the character size given in the + * last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. + * + * Note that this also transforms the `face.glyph.advance` field, but + * **not** the values in `face.glyph.metrics`. + */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * + * @function: + * FT_Get_Transform + * + * @description: + * Return the transformation that is applied to glyph images when they + * are loaded into a glyph slot through @FT_Load_Glyph. See + * @FT_Set_Transform for more details. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * matrix :: + * A pointer to a transformation's 2x2 matrix. Set this to NULL if you + * are not interested in the value. + * + * delta :: + * A pointer to a translation vector. Set this to NULL if you are not + * interested in the value. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + + /************************************************************************** + * + * @enum: + * FT_Render_Mode + * + * @description: + * Render modes supported by FreeType~2. Each mode corresponds to a + * specific type of scanline conversion performed on the outline. + * + * For bitmap fonts and embedded bitmaps the `bitmap->pixel_mode` field + * in the @FT_GlyphSlotRec structure gives the format of the returned + * bitmap. + * + * All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity, + * indicating pixel coverage. Use linear alpha blending and gamma + * correction to correctly render non-monochrome glyph bitmaps onto a + * surface; see @FT_Render_Glyph. + * + * The @FT_RENDER_MODE_SDF is a special render mode that uses up to 256 + * distance values, indicating the signed distance from the grid position + * to the nearest outline. + * + * @values: + * FT_RENDER_MODE_NORMAL :: + * Default render mode; it corresponds to 8-bit anti-aliased bitmaps. + * + * FT_RENDER_MODE_LIGHT :: + * This is equivalent to @FT_RENDER_MODE_NORMAL. It is only defined as + * a separate value because render modes are also used indirectly to + * define hinting algorithm selectors. See @FT_LOAD_TARGET_XXX for + * details. + * + * FT_RENDER_MODE_MONO :: + * This mode corresponds to 1-bit bitmaps (with 2~levels of opacity). + * + * FT_RENDER_MODE_LCD :: + * This mode corresponds to horizontal RGB and BGR subpixel displays + * like LCD screens. It produces 8-bit bitmaps that are 3~times the + * width of the original glyph outline in pixels, and which use the + * @FT_PIXEL_MODE_LCD mode. + * + * FT_RENDER_MODE_LCD_V :: + * This mode corresponds to vertical RGB and BGR subpixel displays + * (like PDA screens, rotated LCD displays, etc.). It produces 8-bit + * bitmaps that are 3~times the height of the original glyph outline in + * pixels and use the @FT_PIXEL_MODE_LCD_V mode. + * + * FT_RENDER_MODE_SDF :: + * The positive (unsigned) 8-bit bitmap values can be converted to the + * single-channel signed distance field (SDF) by subtracting 128, with + * the positive and negative results corresponding to the inside and + * the outside of a glyph contour, respectively. The distance units are + * arbitrarily determined by an adjustable @spread property. + * + * @note: + * The selected render mode only affects scalable vector glyphs of a font. + * Embedded bitmaps often have a different pixel mode like + * @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them + * into 8-bit pixmaps. + * + */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_SDF, + + FT_RENDER_MODE_MAX + + } FT_Render_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Render_Mode` values instead */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO + + + /************************************************************************** + * + * @function: + * FT_Render_Glyph + * + * @description: + * Convert a given glyph image to a bitmap. It does so by inspecting the + * glyph image format, finding the relevant renderer, and invoking it. + * + * @inout: + * slot :: + * A handle to the glyph slot containing the image to convert. + * + * @input: + * render_mode :: + * The render mode used to render the glyph image into a bitmap. See + * @FT_Render_Mode for a list of possible values. + * + * If @FT_RENDER_MODE_NORMAL is used, a previous call of @FT_Load_Glyph + * with flag @FT_LOAD_COLOR makes `FT_Render_Glyph` provide a default + * blending of colored glyph layers associated with the current glyph + * slot (provided the font contains such layers) instead of rendering + * the glyph slot's outline. This is an experimental feature; see + * @FT_LOAD_COLOR for more information. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When FreeType outputs a bitmap of a glyph, it really outputs an alpha + * coverage map. If a pixel is completely covered by a filled-in + * outline, the bitmap contains 0xFF at that pixel, meaning that + * 0xFF/0xFF fraction of that pixel is covered, meaning the pixel is 100% + * black (or 0% bright). If a pixel is only 50% covered (value 0x80), + * the pixel is made 50% black (50% bright or a middle shade of grey). + * 0% covered means 0% black (100% bright or white). + * + * On high-DPI screens like on smartphones and tablets, the pixels are so + * small that their chance of being completely covered and therefore + * completely black are fairly good. On the low-DPI screens, however, + * the situation is different. The pixels are too large for most of the + * details of a glyph and shades of gray are the norm rather than the + * exception. + * + * This is relevant because all our screens have a second problem: they + * are not linear. 1~+~1 is not~2. Twice the value does not result in + * twice the brightness. When a pixel is only 50% covered, the coverage + * map says 50% black, and this translates to a pixel value of 128 when + * you use 8~bits per channel (0-255). However, this does not translate + * to 50% brightness for that pixel on our sRGB and gamma~2.2 screens. + * Due to their non-linearity, they dwell longer in the darks and only a + * pixel value of about 186 results in 50% brightness -- 128 ends up too + * dark on both bright and dark backgrounds. The net result is that dark + * text looks burnt-out, pixely and blotchy on bright background, bright + * text too frail on dark backgrounds, and colored text on colored + * background (for example, red on green) seems to have dark halos or + * 'dirt' around it. The situation is especially ugly for diagonal stems + * like in 'w' glyph shapes where the quality of FreeType's anti-aliasing + * depends on the correct display of grays. On high-DPI screens where + * smaller, fully black pixels reign supreme, this doesn't matter, but on + * our low-DPI screens with all the gray shades, it does. 0% and 100% + * brightness are the same things in linear and non-linear space, just + * all the shades in-between aren't. + * + * The blending function for placing text over a background is + * + * ``` + * dst = alpha * src + (1 - alpha) * dst , + * ``` + * + * which is known as the OVER operator. + * + * To correctly composite an anti-aliased pixel of a glyph onto a + * surface, + * + * 1. take the foreground and background colors (e.g., in sRGB space) + * and apply gamma to get them in a linear space, + * + * 2. use OVER to blend the two linear colors using the glyph pixel + * as the alpha value (remember, the glyph bitmap is an alpha coverage + * bitmap), and + * + * 3. apply inverse gamma to the blended pixel and write it back to + * the image. + * + * Internal testing at Adobe found that a target inverse gamma of~1.8 for + * step~3 gives good results across a wide range of displays with an sRGB + * gamma curve or a similar one. + * + * This process can cost performance. There is an approximation that + * does not need to know about the background color; see + * https://bel.fi/alankila/lcd/ and + * https://bel.fi/alankila/lcd/alpcor.html for details. + * + * **ATTENTION**: Linear blending is even more important when dealing + * with subpixel-rendered glyphs to prevent color-fringing! A + * subpixel-rendered glyph must first be filtered with a filter that + * gives equal weight to the three color primaries and does not exceed a + * sum of 0x100, see section @lcd_rendering. Then the only difference to + * gray linear blending is that subpixel-rendered linear blending is done + * 3~times per pixel: red foreground subpixel to red background subpixel + * and so on for green and blue. + */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + + /************************************************************************** + * + * @enum: + * FT_Kerning_Mode + * + * @description: + * An enumeration to specify the format of kerning values returned by + * @FT_Get_Kerning. + * + * @values: + * FT_KERNING_DEFAULT :: + * Return grid-fitted kerning distances in 26.6 fractional pixels. + * + * FT_KERNING_UNFITTED :: + * Return un-grid-fitted kerning distances in 26.6 fractional pixels. + * + * FT_KERNING_UNSCALED :: + * Return the kerning vector in original font units. + * + * @note: + * `FT_KERNING_DEFAULT` returns full pixel values; it also makes FreeType + * heuristically scale down kerning distances at small ppem values so + * that they don't become too big. + * + * Both `FT_KERNING_DEFAULT` and `FT_KERNING_UNFITTED` use the current + * horizontal scaling factor (as set e.g. with @FT_Set_Char_Size) to + * convert font units to pixels. + */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + + } FT_Kerning_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Kerning_Mode` values instead */ +#define ft_kerning_default FT_KERNING_DEFAULT +#define ft_kerning_unfitted FT_KERNING_UNFITTED +#define ft_kerning_unscaled FT_KERNING_UNSCALED + + + /************************************************************************** + * + * @function: + * FT_Get_Kerning + * + * @description: + * Return the kerning vector between two glyphs of the same face. + * + * @input: + * face :: + * A handle to a source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * kern_mode :: + * See @FT_Kerning_Mode for more information. Determines the scale and + * dimension of the returned kerning vector. + * + * @output: + * akerning :: + * The kerning vector. This is either in font units, fractional pixels + * (26.6 format), or pixels for scalable formats, and in pixels for + * fixed-sizes formats. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Only horizontal layouts (left-to-right & right-to-left) are supported + * by this method. Other layouts, or more sophisticated kernings, are + * out of the scope of this API function -- they can be implemented + * through format-specific interfaces. + * + * Note that, for TrueType fonts only, this can extract data from both + * the 'kern' table and the basic, pair-wise kerning feature from the + * GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though + * FreeType does not support the more advanced GPOS layout features; use + * a library like HarfBuzz for those instead. If a font has both a + * 'kern' table and kern features of a GPOS table, the 'kern' table will + * be used. + * + * Also note for right-to-left scripts, the functionality may differ for + * fonts with GPOS tables vs. 'kern' tables. For GPOS, right-to-left + * fonts typically use both a placement offset and an advance for pair + * positioning, which this API does not support, so it would output + * kerning values of zero; though if the right-to-left font used only + * advances in GPOS pair positioning, then this API could output kerning + * values for it, but it would use `left_glyph` to mean the first glyph + * for that case. Whereas 'kern' tables are always advance-only and + * always store the left glyph first. + * + * Use @FT_HAS_KERNING to find out whether a font has data that can be + * extracted with `FT_Get_Kerning`. + */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); + + + /************************************************************************** + * + * @function: + * FT_Get_Track_Kerning + * + * @description: + * Return the track kerning for a given face object at a given size. + * + * @input: + * face :: + * A handle to a source face object. + * + * point_size :: + * The point size in 16.16 fractional points. + * + * degree :: + * The degree of tightness. Increasingly negative values represent + * tighter track kerning, while increasingly positive values represent + * looser track kerning. Value zero means no track kerning. + * + * @output: + * akerning :: + * The kerning in 16.16 fractional points, to be uniformly applied + * between all glyphs. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Currently, only the Type~1 font driver supports track kerning, using + * data from AFM files (if attached with @FT_Attach_File or + * @FT_Attach_Stream). + * + * Only very few AFM files come with track kerning data; please refer to + * Adobe's AFM specification for more details. + */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + + /************************************************************************** + * + * @section: + * character_mapping + * + */ + + /************************************************************************** + * + * @function: + * FT_Select_Charmap + * + * @description: + * Select a given charmap by its encoding tag (as listed in + * `freetype.h`). + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * encoding :: + * A handle to the selected encoding. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function returns an error if no charmap in the face corresponds + * to the encoding queried here. + * + * Because many fonts contain more than a single cmap for Unicode + * encoding, this function has some special code to select the one that + * covers Unicode best ('best' in the sense that a UCS-4 cmap is + * preferred to a UCS-2 cmap). It is thus preferable to @FT_Set_Charmap + * in this case. + */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); + + + /************************************************************************** + * + * @function: + * FT_Set_Charmap + * + * @description: + * Select a given charmap for character code to glyph index mapping. + * + * @inout: + * face :: + * A handle to the source face object. + * + * @input: + * charmap :: + * A handle to the selected charmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function returns an error if the charmap is not part of the face + * (i.e., if it is not listed in the `face->charmaps` table). + * + * It also fails if an OpenType type~14 charmap is selected (which + * doesn't map character codes to glyph indices at all). + */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap` belongs. If an error occurs, -1 is returned. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_Char_Index + * + * @description: + * Return the glyph index of a given character code. This function uses + * the currently selected charmap to do the mapping. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character code. + * + * @return: + * The glyph index. 0~means 'undefined character code'. + * + * @note: + * If you use FreeType to manipulate the contents of font files directly, + * be aware that the glyph index returned by this function doesn't always + * correspond to the internal indices used within the file. This is done + * to ensure that value~0 always corresponds to the 'missing glyph'. If + * the first glyph is not named '.notdef', then for Type~1 and Type~42 + * fonts, '.notdef' will be moved into the glyph ID~0 position, and + * whatever was there will be moved to the position '.notdef' had. For + * Type~1 fonts, if there is no '.notdef' glyph at all, then one will be + * created at index~0 and whatever was there will be moved to the last + * index -- Type~42 fonts are considered invalid under this condition. + */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); + + + /************************************************************************** + * + * @function: + * FT_Get_First_Char + * + * @description: + * Return the first character code in the current charmap of a given + * face, together with its corresponding glyph index. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * agindex :: + * Glyph index of first character code. 0~if charmap is empty. + * + * @return: + * The charmap's first character code. + * + * @note: + * You should use this function together with @FT_Get_Next_Char to parse + * all character codes available in a given charmap. The code should + * look like this: + * + * ``` + * FT_ULong charcode; + * FT_UInt gindex; + * + * + * charcode = FT_Get_First_Char( face, &gindex ); + * while ( gindex != 0 ) + * { + * ... do something with (charcode,gindex) pair ... + * + * charcode = FT_Get_Next_Char( face, charcode, &gindex ); + * } + * ``` + * + * Be aware that character codes can have values up to 0xFFFFFFFF; this + * might happen for non-Unicode or malformed cmaps. However, even with + * regular Unicode encoding, so-called 'last resort fonts' (using SFNT + * cmap format 13, see function @FT_Get_CMap_Format) normally have + * entries for all Unicode characters up to 0x1FFFFF, which can cause *a + * lot* of iterations. + * + * Note that `*agindex` is set to~0 if the charmap is empty. The result + * itself can be~0 in two cases: if the charmap is empty or if the + * value~0 is the first valid character code. + */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); + + + /************************************************************************** + * + * @function: + * FT_Get_Next_Char + * + * @description: + * Return the next character code in the current charmap of a given face + * following the value `char_code`, as well as the corresponding glyph + * index. + * + * @input: + * face :: + * A handle to the source face object. + * + * char_code :: + * The starting character code. + * + * @output: + * agindex :: + * Glyph index of next character code. 0~if charmap is empty. + * + * @return: + * The charmap's next character code. + * + * @note: + * You should use this function with @FT_Get_First_Char to walk over all + * character codes available in a given charmap. See the note for that + * function for a simple code example. + * + * Note that `*agindex` is set to~0 when there are no more codes in the + * charmap. + */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + + /************************************************************************** + * + * @function: + * FT_Face_Properties + * + * @description: + * Set or override certain (library or module-wide) properties on a + * face-by-face basis. Useful for finer-grained control and avoiding + * locks on shared structures (threads can modify their own faces as they + * see fit). + * + * Contrary to @FT_Property_Set, this function uses @FT_Parameter so that + * you can pass multiple properties to the target face in one call. Note + * that only a subset of the available properties can be controlled. + * + * * @FT_PARAM_TAG_STEM_DARKENING (stem darkening, corresponding to the + * property `no-stem-darkening` provided by the 'autofit', 'cff', + * 'type1', and 't1cid' modules; see @no-stem-darkening). + * + * * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (LCD filter weights, corresponding + * to function @FT_Library_SetLcdFilterWeights). + * + * * @FT_PARAM_TAG_RANDOM_SEED (seed value for the CFF, Type~1, and CID + * 'random' operator, corresponding to the `random-seed` property + * provided by the 'cff', 'type1', and 't1cid' modules; see + * @random-seed). + * + * Pass `NULL` as `data` in @FT_Parameter for a given tag to reset the + * option and use the library or module default again. + * + * @input: + * face :: + * A handle to the source face object. + * + * num_properties :: + * The number of properties that follow. + * + * properties :: + * A handle to an @FT_Parameter array with `num_properties` elements. + * + * @return: + * FreeType error code. 0~means success. + * + * @example: + * Here is an example that sets three properties. You must define + * `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` to make the LCD filter examples + * work. + * + * ``` + * FT_Parameter property1; + * FT_Bool darken_stems = 1; + * + * FT_Parameter property2; + * FT_LcdFiveTapFilter custom_weight = + * { 0x11, 0x44, 0x56, 0x44, 0x11 }; + * + * FT_Parameter property3; + * FT_Int32 random_seed = 314159265; + * + * FT_Parameter properties[3] = { property1, + * property2, + * property3 }; + * + * + * property1.tag = FT_PARAM_TAG_STEM_DARKENING; + * property1.data = &darken_stems; + * + * property2.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS; + * property2.data = custom_weight; + * + * property3.tag = FT_PARAM_TAG_RANDOM_SEED; + * property3.data = &random_seed; + * + * FT_Face_Properties( face, 3, properties ); + * ``` + * + * The next example resets a single property to its default value. + * + * ``` + * FT_Parameter property; + * + * + * property.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS; + * property.data = NULL; + * + * FT_Face_Properties( face, 1, &property ); + * ``` + * + * @since: + * 2.8 + * + */ + FT_EXPORT( FT_Error ) + FT_Face_Properties( FT_Face face, + FT_UInt num_properties, + FT_Parameter* properties ); + + + /************************************************************************** + * + * @section: + * information_retrieval + * + */ + + /************************************************************************** + * + * @function: + * FT_Get_Name_Index + * + * @description: + * Return the glyph index of a given glyph name. This only works + * for those faces where @FT_HAS_GLYPH_NAMES returns true. + * + * @input: + * face :: + * A handle to the source face object. + * + * glyph_name :: + * The glyph name. + * + * @return: + * The glyph index. 0~means 'undefined character code'. + * + * @note: + * Acceptable glyph names might come from the [Adobe Glyph + * List](https://github.com/adobe-type-tools/agl-aglfn). See + * @FT_Get_Glyph_Name for the inverse functionality. + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). + */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + const FT_String* glyph_name ); + + + /************************************************************************** + * + * @function: + * FT_Get_Glyph_Name + * + * @description: + * Retrieve the ASCII name of a given glyph in a face. This only works + * for those faces where @FT_HAS_GLYPH_NAMES returns true. + * + * @input: + * face :: + * A handle to a source face object. + * + * glyph_index :: + * The glyph index. + * + * buffer_max :: + * The maximum number of bytes available in the buffer. + * + * @output: + * buffer :: + * A pointer to a target buffer where the name is copied to. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An error is returned if the face doesn't provide glyph names or if the + * glyph index is invalid. In all cases of failure, the first byte of + * `buffer` is set to~0 to indicate an empty name. + * + * The glyph name is truncated to fit within the buffer if it is too + * long. The returned string is always zero-terminated. + * + * Be aware that FreeType reorders glyph indices internally so that glyph + * index~0 always corresponds to the 'missing glyph' (called '.notdef'). + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). + */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + + /************************************************************************** + * + * @function: + * FT_Get_Postscript_Name + * + * @description: + * Retrieve the ASCII PostScript name of a given face, if available. + * This only works with PostScript, TrueType, and OpenType fonts. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * A pointer to the face's PostScript name. `NULL` if unavailable. + * + * @note: + * The returned pointer is owned by the face and is destroyed with it. + * + * For variation fonts, this string changes if you select a different + * instance, and you have to call `FT_Get_PostScript_Name` again to + * retrieve it. FreeType follows Adobe TechNote #5902, 'Generating + * PostScript Names for Fonts Using OpenType Font Variations'. + * + * https://download.macromedia.com/pub/developer/opentype/tech-notes/5902.AdobePSNameGeneration.html + * + * [Since 2.9] Special PostScript names for named instances are only + * returned if the named instance is set with @FT_Set_Named_Instance (and + * the font has corresponding entries in its 'fvar' table or is the + * default named instance). If @FT_IS_VARIATION returns true, the + * algorithmically derived PostScript name is provided, not looking up + * special entries for named instances. + */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + + /************************************************************************** + * + * @enum: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants describing subglyphs. Please refer to the 'glyf' + * table description in the OpenType specification for the meaning of the + * various flags (which get synthesized for non-OpenType subglyphs). + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 + + + /************************************************************************** + * + * @function: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format` is @FT_GLYPH_FORMAT_COMPOSITE; an error is returned + * otherwise. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of the subglyph. Must be less than + * `glyph->num_subglyphs`. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The values of `*p_arg1`, `*p_arg2`, and `*p_transform` must be + * interpreted depending on the flags returned in `*p_flags`. See the + * OpenType specification for details. + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); + + + /************************************************************************** + * + * @enum: + * FT_FSTYPE_XXX + * + * @description: + * A list of bit flags used in the `fsType` field of the OS/2 table in a + * TrueType or OpenType font and the `FSType` entry in a PostScript font. + * These bit flags are returned by @FT_Get_FSType_Flags; they inform + * client applications of embedding and subsetting restrictions + * associated with a font. + * + * See + * https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/FontPolicies.pdf + * for more details. + * + * @values: + * FT_FSTYPE_INSTALLABLE_EMBEDDING :: + * Fonts with no fsType bit set may be embedded and permanently + * installed on the remote system by an application. + * + * FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING :: + * Fonts that have only this bit set must not be modified, embedded or + * exchanged in any manner without first obtaining permission of the + * font software copyright owner. + * + * FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING :: + * The font may be embedded and temporarily loaded on the remote + * system. Documents containing Preview & Print fonts must be opened + * 'read-only'; no edits can be applied to the document. + * + * FT_FSTYPE_EDITABLE_EMBEDDING :: + * The font may be embedded but must only be installed temporarily on + * other systems. In contrast to Preview & Print fonts, documents + * containing editable fonts may be opened for reading, editing is + * permitted, and changes may be saved. + * + * FT_FSTYPE_NO_SUBSETTING :: + * The font may not be subsetted prior to embedding. + * + * FT_FSTYPE_BITMAP_EMBEDDING_ONLY :: + * Only bitmaps contained in the font may be embedded; no outline data + * may be embedded. If there are no bitmaps available in the font, + * then the font is unembeddable. + * + * @note: + * The flags are ORed together, thus more than a single value can be + * returned. + * + * While the `fsType` flags can indicate that a font may be embedded, a + * license with the font vendor may be separately required to use the + * font in this way. + */ +#define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000 +#define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002 +#define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004 +#define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008 +#define FT_FSTYPE_NO_SUBSETTING 0x0100 +#define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200 + + + /************************************************************************** + * + * @function: + * FT_Get_FSType_Flags + * + * @description: + * Return the `fsType` flags for a font. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * The `fsType` flags, see @FT_FSTYPE_XXX. + * + * @note: + * Use this function rather than directly reading the `fs_type` field in + * the @PS_FontInfoRec structure, which is only guaranteed to return the + * correct results for Type~1 fonts. + * + * @since: + * 2.3.8 + * + */ + FT_EXPORT( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ); + + + /************************************************************************** + * + * @section: + * glyph_variants + * + * @title: + * Unicode Variation Sequences + * + * @abstract: + * The FreeType~2 interface to Unicode Variation Sequences (UVS), using + * the SFNT cmap format~14. + * + * @description: + * Many characters, especially for CJK scripts, have variant forms. They + * are a sort of grey area somewhere between being totally irrelevant and + * semantically distinct; for this reason, the Unicode consortium decided + * to introduce Variation Sequences (VS), consisting of a Unicode base + * character and a variation selector instead of further extending the + * already huge number of characters. + * + * Unicode maintains two different sets, namely 'Standardized Variation + * Sequences' and registered 'Ideographic Variation Sequences' (IVS), + * collected in the 'Ideographic Variation Database' (IVD). + * + * https://unicode.org/Public/UCD/latest/ucd/StandardizedVariants.txt + * https://unicode.org/reports/tr37/ https://unicode.org/ivd/ + * + * To date (January 2017), the character with the most ideographic + * variations is U+9089, having 32 such IVS. + * + * Three Mongolian Variation Selectors have the values U+180B-U+180D; 256 + * generic Variation Selectors are encoded in the ranges U+FE00-U+FE0F + * and U+E0100-U+E01EF. IVS currently use Variation Selectors from the + * range U+E0100-U+E01EF only. + * + * A VS consists of the base character value followed by a single + * Variation Selector. For example, to get the first variation of + * U+9089, you have to write the character sequence `U+9089 U+E0100`. + * + * Adobe and MS decided to support both standardized and ideographic VS + * with a new cmap subtable (format~14). It is an odd subtable because + * it is not a mapping of input code points to glyphs, but contains lists + * of all variations supported by the font. + * + * A variation may be either 'default' or 'non-default' for a given font. + * A default variation is the one you will get for that code point if you + * look it up in the standard Unicode cmap. A non-default variation is a + * different glyph. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharVariantIndex + * + * @description: + * Return the glyph index of a given character code as modified by the + * variation selector. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character code point in Unicode. + * + * variantSelector :: + * The Unicode code point of the variation selector. + * + * @return: + * The glyph index. 0~means either 'undefined character code', or + * 'undefined selector code', or 'no variation selector cmap subtable', + * or 'current CharMap is not Unicode'. + * + * @note: + * If you use FreeType to manipulate the contents of font files directly, + * be aware that the glyph index returned by this function doesn't always + * correspond to the internal indices used within the file. This is done + * to ensure that value~0 always corresponds to the 'missing glyph'. + * + * This function is only meaningful if + * a) the font has a variation selector cmap sub table, and + * b) the current charmap has a Unicode encoding. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharVariantIsDefault + * + * @description: + * Check whether this variation of this Unicode character is the one to + * be found in the charmap. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character codepoint in Unicode. + * + * variantSelector :: + * The Unicode codepoint of the variation selector. + * + * @return: + * 1~if found in the standard (Unicode) cmap, 0~if found in the variation + * selector cmap, or -1 if it is not a variation. + * + * @note: + * This function is only meaningful if the font has a variation selector + * cmap subtable. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetVariantSelectors + * + * @description: + * Return a zero-terminated list of Unicode variation selectors found in + * the font. + * + * @input: + * face :: + * A handle to the source face object. + * + * @return: + * A pointer to an array of selector code points, or `NULL` if there is + * no valid variation selector cmap subtable. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetVariantsOfChar + * + * @description: + * Return a zero-terminated list of Unicode variation selectors found for + * the specified character code. + * + * @input: + * face :: + * A handle to the source face object. + * + * charcode :: + * The character codepoint in Unicode. + * + * @return: + * A pointer to an array of variation selector code points that are + * active for the given character, or `NULL` if the corresponding list is + * empty. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ); + + + /************************************************************************** + * + * @function: + * FT_Face_GetCharsOfVariant + * + * @description: + * Return a zero-terminated list of Unicode character codes found for the + * specified variation selector. + * + * @input: + * face :: + * A handle to the source face object. + * + * variantSelector :: + * The variation selector code point in Unicode. + * + * @return: + * A list of all the code points that are specified by this selector + * (both default and non-default codes are returned) or `NULL` if there + * is no valid cmap or the variation selector is invalid. + * + * @note: + * The last item in the array is~0; the array is owned by the @FT_Face + * object but can be overwritten or released on the next call to a + * FreeType function. + * + * @since: + * 2.3.6 + * + */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ); + + + /************************************************************************** + * + * @section: + * computations + * + * @title: + * Computations + * + * @abstract: + * Crunching fixed numbers and vectors. + * + * @description: + * This section contains various functions used to perform computations + * on 16.16 fixed-point numbers or 2D vectors. FreeType does not use + * floating-point data types. + * + * **Attention**: Most arithmetic functions take `FT_Long` as arguments. + * For historical reasons, FreeType was designed under the assumption + * that `FT_Long` is a 32-bit integer; results can thus be undefined if + * the arguments don't fit into 32 bits. + * + * @order: + * FT_MulDiv + * FT_MulFix + * FT_DivFix + * FT_RoundFix + * FT_CeilFix + * FT_FloorFix + * FT_Vector_Transform + * FT_Matrix_Multiply + * FT_Matrix_Invert + * + */ + + + /************************************************************************** + * + * @function: + * FT_MulDiv + * + * @description: + * Compute `(a*b)/c` with maximum accuracy, using a 64-bit intermediate + * integer whenever necessary. + * + * This function isn't necessarily as fast as some processor-specific + * operations, but is at least completely portable. + * + * @input: + * a :: + * The first multiplier. + * + * b :: + * The second multiplier. + * + * c :: + * The divisor. + * + * @return: + * The result of `(a*b)/c`. This function never traps when trying to + * divide by zero; it simply returns 'MaxInt' or 'MinInt' depending on + * the signs of `a` and `b`. + */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); + + + /************************************************************************** + * + * @function: + * FT_MulFix + * + * @description: + * Compute `(a*b)/0x10000` with maximum accuracy. Its main use is to + * multiply a given value by a 16.16 fixed-point factor. + * + * @input: + * a :: + * The first multiplier. + * + * b :: + * The second multiplier. Use a 16.16 factor here whenever possible + * (see note below). + * + * @return: + * The result of `(a*b)/0x10000`. + * + * @note: + * This function has been optimized for the case where the absolute value + * of `a` is less than 2048, and `b` is a 16.16 scaling factor. As this + * happens mainly when scaling from notional units to fractional pixels + * in FreeType, it resulted in noticeable speed improvements between + * versions 2.x and 1.x. + * + * As a conclusion, always try to place a 16.16 factor as the _second_ + * argument of this function; this can make a great difference. + */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); + + + /************************************************************************** + * + * @function: + * FT_DivFix + * + * @description: + * Compute `(a*0x10000)/b` with maximum accuracy. Its main use is to + * divide a given value by a 16.16 fixed-point factor. + * + * @input: + * a :: + * The numerator. + * + * b :: + * The denominator. Use a 16.16 factor here. + * + * @return: + * The result of `(a*0x10000)/b`. + */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); + + + /************************************************************************** + * + * @function: + * FT_RoundFix + * + * @description: + * Round a 16.16 fixed number. + * + * @input: + * a :: + * The number to be rounded. + * + * @return: + * `a` rounded to the nearest 16.16 fixed integer, halfway cases away + * from zero. + * + * @note: + * The function uses wrap-around arithmetic. + */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_CeilFix + * + * @description: + * Compute the smallest following integer of a 16.16 fixed number. + * + * @input: + * a :: + * The number for which the ceiling function is to be computed. + * + * @return: + * `a` rounded towards plus infinity. + * + * @note: + * The function uses wrap-around arithmetic. + */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_FloorFix + * + * @description: + * Compute the largest previous integer of a 16.16 fixed number. + * + * @input: + * a :: + * The number for which the floor function is to be computed. + * + * @return: + * `a` rounded towards minus infinity. + */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Transform + * + * @description: + * Transform a single vector through a 2x2 matrix. + * + * @inout: + * vector :: + * The target vector to transform. + * + * @input: + * matrix :: + * A pointer to the source 2x2 matrix. + * + * @note: + * The result is undefined if either `vector` or `matrix` is invalid. + */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ); + + + /************************************************************************** + * + * @section: + * library_setup + * + */ + + /************************************************************************** + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. Use + * @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: + * The major version number. + * FREETYPE_MINOR :: + * The minor version number. + * FREETYPE_PATCH :: + * The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library with + * the 'libtool' package is _not_ controlled by these three macros. + * + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 13 +#define FREETYPE_PATCH 3 + + + /************************************************************************** + * + * @function: + * FT_Library_Version + * + * @description: + * Return the version of the FreeType library being used. This is useful + * when dynamically linking to the library, since one cannot use the + * macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and @FREETYPE_PATCH. + * + * @input: + * library :: + * A source library handle. + * + * @output: + * amajor :: + * The major version number. + * + * aminor :: + * The minor version number. + * + * apatch :: + * The patch version number. + * + * @note: + * The reason why this function takes a `library` argument is because + * certain programs implement library initialization in a custom way that + * doesn't use @FT_Init_FreeType. + * + * In such cases, the library version might not be available before the + * library object has been created. + */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); + + + /************************************************************************** + * + * @section: + * other_api_data + * + */ + + /************************************************************************** + * + * @function: + * FT_Face_CheckTrueTypePatents + * + * @description: + * Deprecated, does nothing. + * + * @input: + * face :: + * A face handle. + * + * @return: + * Always returns false. + * + * @note: + * Since May 2010, TrueType hinting is no longer patented. + * + * @since: + * 2.3.5 + * + */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Face_SetUnpatentedHinting + * + * @description: + * Deprecated, does nothing. + * + * @input: + * face :: + * A face handle. + * + * value :: + * New boolean setting. + * + * @return: + * Always returns false. + * + * @note: + * Since May 2010, TrueType hinting is no longer patented. + * + * @since: + * 2.3.5 + * + */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); + + /* */ + + +FT_END_HEADER + +#endif /* FREETYPE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftadvanc.h b/Dependencies/freetype/freetype/include/freetype/ftadvanc.h new file mode 100644 index 00000000..85b8ba25 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftadvanc.h @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * ftadvanc.h + * + * Quick computation of advance widths (specification only). + * + * Copyright (C) 2008-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTADVANC_H_ +#define FTADVANC_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * quick_advance + * + * @title: + * Quick retrieval of advance values + * + * @abstract: + * Retrieve horizontal and vertical advance values without processing + * glyph outlines, if possible. + * + * @description: + * This section contains functions to quickly extract advance values + * without handling glyph outlines, if possible. + * + * @order: + * FT_Get_Advance + * FT_Get_Advances + * + */ + + + /************************************************************************** + * + * @enum: + * FT_ADVANCE_FLAG_FAST_ONLY + * + * @description: + * A bit-flag to be OR-ed with the `flags` parameter of the + * @FT_Get_Advance and @FT_Get_Advances functions. + * + * If set, it indicates that you want these functions to fail if the + * corresponding hinting mode or font driver doesn't allow for very quick + * advance computation. + * + * Typically, glyphs that are either unscaled, unhinted, bitmapped, or + * light-hinted can have their advance width computed very quickly. + * + * Normal and bytecode hinted modes that require loading, scaling, and + * hinting of the glyph outline, are extremely slow by comparison. + */ +#define FT_ADVANCE_FLAG_FAST_ONLY 0x20000000L + + + /************************************************************************** + * + * @function: + * FT_Get_Advance + * + * @description: + * Retrieve the advance value of a given glyph outline in an @FT_Face. + * + * @input: + * face :: + * The source @FT_Face handle. + * + * gindex :: + * The glyph index. + * + * load_flags :: + * A set of bit flags similar to those used when calling + * @FT_Load_Glyph, used to determine what kind of advances you need. + * + * @output: + * padvance :: + * The advance value. If scaling is performed (based on the value of + * `load_flags`), the advance value is in 16.16 format. Otherwise, it + * is in font units. + * + * If @FT_LOAD_VERTICAL_LAYOUT is set, this is the vertical advance + * corresponding to a vertical layout. Otherwise, it is the horizontal + * advance in a horizontal layout. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and if + * the corresponding font backend doesn't have a quick way to retrieve + * the advances. + * + * A scaled advance is returned in 16.16 format but isn't transformed by + * the affine transformation specified by @FT_Set_Transform. + */ + FT_EXPORT( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags, + FT_Fixed *padvance ); + + + /************************************************************************** + * + * @function: + * FT_Get_Advances + * + * @description: + * Retrieve the advance values of several glyph outlines in an @FT_Face. + * + * @input: + * face :: + * The source @FT_Face handle. + * + * start :: + * The first glyph index. + * + * count :: + * The number of advance values you want to retrieve. + * + * load_flags :: + * A set of bit flags similar to those used when calling + * @FT_Load_Glyph. + * + * @output: + * padvance :: + * The advance values. This array, to be provided by the caller, must + * contain at least `count` elements. + * + * If scaling is performed (based on the value of `load_flags`), the + * advance values are in 16.16 format. Otherwise, they are in font + * units. + * + * If @FT_LOAD_VERTICAL_LAYOUT is set, these are the vertical advances + * corresponding to a vertical layout. Otherwise, they are the + * horizontal advances in a horizontal layout. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and if + * the corresponding font backend doesn't have a quick way to retrieve + * the advances. + * + * Scaled advances are returned in 16.16 format but aren't transformed by + * the affine transformation specified by @FT_Set_Transform. + */ + FT_EXPORT( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed *padvances ); + + /* */ + + +FT_END_HEADER + +#endif /* FTADVANC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftbbox.h b/Dependencies/freetype/freetype/include/freetype/ftbbox.h new file mode 100644 index 00000000..12bbfa63 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftbbox.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * + * ftbbox.h + * + * FreeType exact bbox computation (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component has a _single_ role: to compute exact outline bounding + * boxes. + * + * It is separated from the rest of the engine for various technical + * reasons. It may well be integrated in 'ftoutln' later. + * + */ + + +#ifndef FTBBOX_H_ +#define FTBBOX_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * outline_processing + * + */ + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_BBox + * + * @description: + * Compute the exact bounding box of an outline. This is slower than + * computing the control box. However, it uses an advanced algorithm + * that returns _very_ quickly when the two boxes coincide. Otherwise, + * the outline Bezier arcs are traversed to extract their extrema. + * + * @input: + * outline :: + * A pointer to the source outline. + * + * @output: + * abbox :: + * The outline's exact bounding box. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the font is tricky and the glyph has been loaded with + * @FT_LOAD_NO_SCALE, the resulting BBox is meaningless. To get + * reasonable values for the BBox it is necessary to load the glyph at a + * large ppem value (so that the hinting instructions can properly shift + * and scale the subglyphs), then extracting the BBox, which can be + * eventually converted back to font units. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); + + /* */ + + +FT_END_HEADER + +#endif /* FTBBOX_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftbdf.h b/Dependencies/freetype/freetype/include/freetype/ftbdf.h new file mode 100644 index 00000000..6f63b0b1 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftbdf.h @@ -0,0 +1,212 @@ +/**************************************************************************** + * + * ftbdf.h + * + * FreeType API for accessing BDF-specific strings (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBDF_H_ +#define FTBDF_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * bdf_fonts + * + * @title: + * BDF and PCF Files + * + * @abstract: + * BDF and PCF specific API. + * + * @description: + * This section contains the declaration of functions specific to BDF and + * PCF fonts. + * + */ + + + /************************************************************************** + * + * @enum: + * BDF_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value~0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + + } BDF_PropertyType; + + + /************************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given BDF/PCF + * property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; + + + /************************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. May be + * `NULL`, indicating an empty string. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + + } u; + + } BDF_PropertyRec; + + + /************************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieve a BDF font character set identity, according to the BDF + * specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C~string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C~string, owned by the face. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + + /************************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieve a BDF property from a BDF or PCF font file. + * + * @input: + * face :: + * A handle to the input face. + * + * name :: + * The property name. + * + * @output: + * aproperty :: + * The property. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * A 'property' is a either key-value pair within the STARTPROPERTIES + * ... ENDPROPERTIES block of a BDF font or a key-value pair from the + * `info->props` array within a `FontRec` structure of a PCF font. + * + * Integer properties are always stored as 'signed' within PCF fonts; + * consequently, @BDF_PROPERTY_TYPE_CARDINAL is a possible return value + * for BDF fonts only. + * + * In case of error, `aproperty->type` is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + /* */ + +FT_END_HEADER + +#endif /* FTBDF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftbitmap.h b/Dependencies/freetype/freetype/include/freetype/ftbitmap.h new file mode 100644 index 00000000..df9d4626 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftbitmap.h @@ -0,0 +1,329 @@ +/**************************************************************************** + * + * ftbitmap.h + * + * FreeType utility functions for bitmaps (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBITMAP_H_ +#define FTBITMAP_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * bitmap_handling + * + * @title: + * Bitmap Handling + * + * @abstract: + * Handling FT_Bitmap objects. + * + * @description: + * This section contains functions for handling @FT_Bitmap objects, + * automatically adjusting the target's bitmap buffer size as needed. + * + * Note that none of the functions changes the bitmap's 'flow' (as + * indicated by the sign of the `pitch` field in @FT_Bitmap). + * + * To set the flow, assign an appropriate positive or negative value to + * the `pitch` field of the target @FT_Bitmap object after calling + * @FT_Bitmap_Init but before calling any of the other functions + * described here. + */ + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Init + * + * @description: + * Initialize a pointer to an @FT_Bitmap structure. + * + * @inout: + * abitmap :: + * A pointer to the bitmap structure. + * + * @note: + * A deprecated name for the same function is `FT_Bitmap_New`. + */ + FT_EXPORT( void ) + FT_Bitmap_Init( FT_Bitmap *abitmap ); + + + /* deprecated */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Copy + * + * @description: + * Copy a bitmap into another one. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * A handle to the source bitmap. + * + * @output: + * target :: + * A handle to the target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Embolden + * + * @description: + * Embolden a bitmap. The new bitmap will be about `xStrength` pixels + * wider and `yStrength` pixels higher. The left and bottom borders are + * kept unchanged. + * + * @input: + * library :: + * A handle to a library object. + * + * xStrength :: + * How strong the glyph is emboldened horizontally. Expressed in 26.6 + * pixel format. + * + * yStrength :: + * How strong the glyph is emboldened vertically. Expressed in 26.6 + * pixel format. + * + * @inout: + * bitmap :: + * A handle to the target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The current implementation restricts `xStrength` to be less than or + * equal to~8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. + * + * If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, you + * should call @FT_GlyphSlot_Own_Bitmap on the slot first. + * + * Bitmaps in @FT_PIXEL_MODE_GRAY2 and @FT_PIXEL_MODE_GRAY@ format are + * converted to @FT_PIXEL_MODE_GRAY format (i.e., 8bpp). + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Convert + * + * @description: + * Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, 8bpp or 32bpp to + * a bitmap object with depth 8bpp, making the number of used bytes per + * line (a.k.a. the 'pitch') a multiple of `alignment`. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * The source bitmap. + * + * alignment :: + * The pitch of the bitmap is a multiple of this argument. Common + * values are 1, 2, or 4. + * + * @output: + * target :: + * The target bitmap. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * It is possible to call @FT_Bitmap_Convert multiple times without + * calling @FT_Bitmap_Done (the memory is simply reallocated). + * + * Use @FT_Bitmap_Done to finally remove the bitmap object. + * + * The `library` argument is taken to have access to FreeType's memory + * handling functions. + * + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Blend + * + * @description: + * Blend a bitmap onto another bitmap, using a given color. + * + * @input: + * library :: + * A handle to a library object. + * + * source :: + * The source bitmap, which can have any @FT_Pixel_Mode format. + * + * source_offset :: + * The offset vector to the upper left corner of the source bitmap in + * 26.6 pixel format. It should represent an integer offset; the + * function will set the lowest six bits to zero to enforce that. + * + * color :: + * The color used to draw `source` onto `target`. + * + * @inout: + * target :: + * A handle to an `FT_Bitmap` object. It should be either initialized + * as empty with a call to @FT_Bitmap_Init, or it should be of type + * @FT_PIXEL_MODE_BGRA. + * + * atarget_offset :: + * The offset vector to the upper left corner of the target bitmap in + * 26.6 pixel format. It should represent an integer offset; the + * function will set the lowest six bits to zero to enforce that. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function doesn't perform clipping. + * + * The bitmap in `target` gets allocated or reallocated as needed; the + * vector `atarget_offset` is updated accordingly. + * + * In case of allocation or reallocation, the bitmap's pitch is set to + * `4 * width`. Both `source` and `target` must have the same bitmap + * flow (as indicated by the sign of the `pitch` field). + * + * `source->buffer` and `target->buffer` must neither be equal nor + * overlap. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Blend( FT_Library library, + const FT_Bitmap* source, + const FT_Vector source_offset, + FT_Bitmap* target, + FT_Vector *atarget_offset, + FT_Color color ); + + + /************************************************************************** + * + * @function: + * FT_GlyphSlot_Own_Bitmap + * + * @description: + * Make sure that a glyph slot owns `slot->bitmap`. + * + * @input: + * slot :: + * The glyph slot. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is to be used in combination with @FT_Bitmap_Embolden. + */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); + + + /************************************************************************** + * + * @function: + * FT_Bitmap_Done + * + * @description: + * Destroy a bitmap object initialized with @FT_Bitmap_Init. + * + * @input: + * library :: + * A handle to a library object. + * + * bitmap :: + * The bitmap object to be freed. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `library` argument is taken to have access to FreeType's memory + * handling functions. + */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTBITMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftbzip2.h b/Dependencies/freetype/freetype/include/freetype/ftbzip2.h new file mode 100644 index 00000000..c5baea85 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftbzip2.h @@ -0,0 +1,102 @@ +/**************************************************************************** + * + * ftbzip2.h + * + * Bzip2-compressed stream support. + * + * Copyright (C) 2010-2024 by + * Joel Klinghed. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBZIP2_H_ +#define FTBZIP2_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * bzip2 + * + * @title: + * BZIP2 Streams + * + * @abstract: + * Using bzip2-compressed font files. + * + * @description: + * In certain builds of the library, bzip2 compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a bzip2 compressed + * stream from it and re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of Bzip2-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Stream_OpenBzip2 + * + * @description: + * Open a new stream to parse bzip2-compressed font files. This is + * mainly used to support the compressed `*.pcf.bz2` fonts that come with + * XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with bzip2 support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* FTBZIP2_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftcache.h b/Dependencies/freetype/freetype/include/freetype/ftcache.h new file mode 100644 index 00000000..140df4c9 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftcache.h @@ -0,0 +1,1087 @@ +/**************************************************************************** + * + * ftcache.h + * + * FreeType Cache subsystem (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCACHE_H_ +#define FTCACHE_H_ + + +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * cache_subsystem + * + * @title: + * Cache Sub-System + * + * @abstract: + * How to cache face, size, and glyph data with FreeType~2. + * + * @description: + * This section describes the FreeType~2 cache sub-system, which is used + * to limit the number of concurrently opened @FT_Face and @FT_Size + * objects, as well as caching information like character maps and glyph + * images while limiting their maximum memory usage. + * + * Note that all types and functions begin with the `FTC_` prefix rather + * than the usual `FT_` prefix in the rest of FreeType. + * + * The cache is highly portable and, thus, doesn't know anything about + * the fonts installed on your system, or how to access them. Therefore, + * it requires the following. + * + * * @FTC_FaceID, an arbitrary non-zero value that uniquely identifies + * available or installed font faces, has to be provided to the + * cache by the client. Note that the cache only stores and compares + * these values and doesn't try to interpret them in any way, but they + * have to be persistent on the client side. + * + * * @FTC_Face_Requester, a method to convert an @FTC_FaceID into a new + * @FT_Face object when necessary, has to be provided to the cache by + * the client. The @FT_Face object is completely managed by the cache, + * including its termination through @FT_Done_Face. To monitor + * termination of face objects, the finalizer callback in the `generic` + * field of the @FT_Face object can be used, which might also be used + * to store the @FTC_FaceID of the face. + * + * Clients are free to map face IDs to anything useful. The most simple + * usage is, for example, to associate them to a `{pathname,face_index}` + * pair that is then used by @FTC_Face_Requester to call @FT_New_Face. + * However, more complex schemes are also possible. + * + * Note that for the cache to work correctly, the face ID values must be + * **persistent**, which means that the contents they point to should not + * change at runtime, or that their value should not become invalid. + * If this is unavoidable (e.g., when a font is uninstalled at runtime), + * you should call @FTC_Manager_RemoveFaceID as soon as possible to let + * the cache get rid of any references to the old @FTC_FaceID it may keep + * internally. Failure to do so will lead to incorrect behaviour or even + * crashes in @FTC_Face_Requester. + * + * To use the cache, start with calling @FTC_Manager_New to create a new + * @FTC_Manager object, which models a single cache instance. You can + * then look up @FT_Face and @FT_Size objects with + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively, and + * use them in any FreeType work stream. You can also cache other + * FreeType objects as follows. + * + * * If you want to use the charmap caching, call @FTC_CMapCache_New, + * then later use @FTC_CMapCache_Lookup to perform the equivalent of + * @FT_Get_Char_Index, only much faster. + * + * * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New, + * then later use @FTC_ImageCache_Lookup to retrieve the corresponding + * @FT_Glyph objects from the cache. + * + * * If you need lots of small bitmaps, it is much more memory-efficient + * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This + * returns @FTC_SBitRec structures, which are used to store small + * bitmaps directly. (A small bitmap is one whose metrics and + * dimensions all fit into 8-bit integers). + * + * @order: + * FTC_Manager + * FTC_FaceID + * FTC_Face_Requester + * + * FTC_Manager_New + * FTC_Manager_Reset + * FTC_Manager_Done + * FTC_Manager_LookupFace + * FTC_Manager_LookupSize + * FTC_Manager_RemoveFaceID + * + * FTC_Node + * FTC_Node_Unref + * + * FTC_ImageCache + * FTC_ImageCache_New + * FTC_ImageCache_Lookup + * + * FTC_SBit + * FTC_SBitCache + * FTC_SBitCache_New + * FTC_SBitCache_Lookup + * + * FTC_CMapCache + * FTC_CMapCache_New + * FTC_CMapCache_Lookup + * + *************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC TYPE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @type: + * FTC_FaceID + * + * @description: + * An opaque pointer type that is used to identity face objects. The + * contents of such objects is application-dependent. + * + * These pointers are typically used to point to a user-defined structure + * containing a font file path, and face index. + * + * @note: + * Never use `NULL` as a valid @FTC_FaceID. + * + * Face IDs are passed by the client to the cache manager that calls, + * when needed, the @FTC_Face_Requester to translate them into new + * @FT_Face objects. + * + * If the content of a given face ID changes at runtime, or if the value + * becomes invalid (e.g., when uninstalling a font), you should + * immediately call @FTC_Manager_RemoveFaceID before any other cache + * function. + * + * Failure to do so will result in incorrect behaviour or even memory + * leaks and crashes. + */ + typedef FT_Pointer FTC_FaceID; + + + /************************************************************************** + * + * @functype: + * FTC_Face_Requester + * + * @description: + * A callback function provided by client applications. It is used by + * the cache manager to translate a given @FTC_FaceID into a new valid + * @FT_Face object, on demand. + * + * @input: + * face_id :: + * The face ID to resolve. + * + * library :: + * A handle to a FreeType library object. + * + * req_data :: + * Application-provided request data (see note below). + * + * @output: + * aface :: + * A new @FT_Face handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The third parameter `req_data` is the same as the one passed by the + * client when @FTC_Manager_New is called. + * + * The face requester should not perform funny things on the returned + * face object, like creating a new @FT_Size for it, or setting a + * transformation through @FT_Set_Transform! + */ + typedef FT_Error + (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Library library, + FT_Pointer req_data, + FT_Face* aface ); + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @type: + * FTC_Manager + * + * @description: + * This object corresponds to one instance of the cache-subsystem. It is + * used to cache one or more @FT_Face objects, along with corresponding + * @FT_Size objects. + * + * The manager intentionally limits the total number of opened @FT_Face + * and @FT_Size objects to control memory usage. See the `max_faces` and + * `max_sizes` parameters of @FTC_Manager_New. + * + * The manager is also used to cache 'nodes' of various types while + * limiting their total memory usage. + * + * All limitations are enforced by keeping lists of managed objects in + * most-recently-used order, and flushing old nodes to make room for new + * ones. + */ + typedef struct FTC_ManagerRec_* FTC_Manager; + + + /************************************************************************** + * + * @type: + * FTC_Node + * + * @description: + * An opaque handle to a cache node object. Each cache node is + * reference-counted. A node with a count of~0 might be flushed out of a + * full cache whenever a lookup request is performed. + * + * If you look up nodes, you have the ability to 'acquire' them, i.e., to + * increment their reference count. This will prevent the node from + * being flushed out of the cache until you explicitly 'release' it (see + * @FTC_Node_Unref). + * + * See also @FTC_SBitCache_Lookup and @FTC_ImageCache_Lookup. + */ + typedef struct FTC_NodeRec_* FTC_Node; + + + /************************************************************************** + * + * @function: + * FTC_Manager_New + * + * @description: + * Create a new cache manager. + * + * @input: + * library :: + * The parent FreeType library handle to use. + * + * max_faces :: + * Maximum number of opened @FT_Face objects managed by this cache + * instance. Use~0 for defaults. + * + * max_sizes :: + * Maximum number of opened @FT_Size objects managed by this cache + * instance. Use~0 for defaults. + * + * max_bytes :: + * Maximum number of bytes to use for cached data nodes. Use~0 for + * defaults. Note that this value does not account for managed + * @FT_Face and @FT_Size objects. + * + * requester :: + * An application-provided callback used to translate face IDs into + * real @FT_Face objects. + * + * req_data :: + * A generic pointer that is passed to the requester each time it is + * called (see @FTC_Face_Requester). + * + * @output: + * amanager :: + * A handle to a new manager object. 0~in case of failure. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_Reset + * + * @description: + * Empty a given cache manager. This simply gets rid of all the + * currently cached @FT_Face and @FT_Size objects within the manager. + * + * @inout: + * manager :: + * A handle to the manager. + */ + FT_EXPORT( void ) + FTC_Manager_Reset( FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_Done + * + * @description: + * Destroy a given manager after emptying it. + * + * @input: + * manager :: + * A handle to the target cache manager object. + */ + FT_EXPORT( void ) + FTC_Manager_Done( FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_LookupFace + * + * @description: + * Retrieve the @FT_Face object that corresponds to a given face ID + * through a cache manager. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * face_id :: + * The ID of the face object. + * + * @output: + * aface :: + * A handle to the face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned @FT_Face object is always owned by the manager. You + * should never try to discard it yourself. + * + * The @FT_Face object doesn't necessarily have a current size object + * (i.e., face->size can be~0). If you need a specific 'font size', use + * @FTC_Manager_LookupSize instead. + * + * Never change the face's transformation matrix (i.e., never call the + * @FT_Set_Transform function) on a returned face! If you need to + * transform glyphs, do it yourself after glyph loading. + * + * When you perform a lookup, out-of-memory errors are detected _within_ + * the lookup and force incremental flushes of the cache until enough + * memory is released for the lookup to succeed. + * + * If a lookup fails with `FT_Err_Out_Of_Memory` the cache has already + * been completely flushed, and still no memory was available for the + * operation. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + + /************************************************************************** + * + * @struct: + * FTC_ScalerRec + * + * @description: + * A structure used to describe a given character size in either pixels + * or points to the cache manager. See @FTC_Manager_LookupSize. + * + * @fields: + * face_id :: + * The source face ID. + * + * width :: + * The character width. + * + * height :: + * The character height. + * + * pixel :: + * A Boolean. If 1, the `width` and `height` fields are interpreted as + * integer pixel character sizes. Otherwise, they are expressed as + * 1/64 of points. + * + * x_res :: + * Only used when `pixel` is value~0 to indicate the horizontal + * resolution in dpi. + * + * y_res :: + * Only used when `pixel` is value~0 to indicate the vertical + * resolution in dpi. + * + * @note: + * This type is mainly used to retrieve @FT_Size objects through the + * cache manager. + */ + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec; + + + /************************************************************************** + * + * @struct: + * FTC_Scaler + * + * @description: + * A handle to an @FTC_ScalerRec structure. + */ + typedef struct FTC_ScalerRec_* FTC_Scaler; + + + /************************************************************************** + * + * @function: + * FTC_Manager_LookupSize + * + * @description: + * Retrieve the @FT_Size object that corresponds to a given + * @FTC_ScalerRec pointer through a cache manager. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * scaler :: + * A scaler handle. + * + * @output: + * asize :: + * A handle to the size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned @FT_Size object is always owned by the manager. You + * should never try to discard it by yourself. + * + * You can access the parent @FT_Face object simply as `size->face` if + * you need it. Note that this object is also owned by the manager. + * + * @note: + * When you perform a lookup, out-of-memory errors are detected _within_ + * the lookup and force incremental flushes of the cache until enough + * memory is released for the lookup to succeed. + * + * If a lookup fails with `FT_Err_Out_Of_Memory` the cache has already + * been completely flushed, and still no memory is available for the + * operation. + */ + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); + + + /************************************************************************** + * + * @function: + * FTC_Node_Unref + * + * @description: + * Decrement a cache node's internal reference count. When the count + * reaches 0, it is not destroyed but becomes eligible for subsequent + * cache flushes. + * + * @input: + * node :: + * The cache node handle. + * + * manager :: + * The cache manager handle. + */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /************************************************************************** + * + * @function: + * FTC_Manager_RemoveFaceID + * + * @description: + * A special function used to indicate to the cache manager that a given + * @FTC_FaceID is no longer valid, either because its content changed, or + * because it was deallocated or uninstalled. + * + * @input: + * manager :: + * The cache manager handle. + * + * face_id :: + * The @FTC_FaceID to be removed. + * + * @note: + * This function flushes all nodes from the cache corresponding to this + * `face_id`, with the exception of nodes with a non-null reference + * count. + * + * Such nodes are however modified internally so as to never appear in + * later lookups with the same `face_id` value, and to be immediately + * destroyed when released by all their users. + * + */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /************************************************************************** + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to model a charmap cache. This cache is to hold + * character codes -> glyph indices mappings. + * + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /************************************************************************** + * + * @function: + * FTC_CMapCache_New + * + * @description: + * Create a new charmap cache. + * + * @input: + * manager :: + * A handle to the cache manager. + * + * @output: + * acache :: + * A new cache handle. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Like all other caches, this one will be destroyed with the cache + * manager. + * + */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_CMapCache_Lookup + * + * @description: + * Translate a character code into a glyph index, using the charmap + * cache. + * + * @input: + * cache :: + * A charmap cache handle. + * + * face_id :: + * The source face ID. + * + * cmap_index :: + * The index of the charmap in the source face. Any negative value + * means to use the cache @FT_Face's default charmap. + * + * char_code :: + * The character code (in the corresponding charmap). + * + * @return: + * Glyph index. 0~means 'no glyph'. + * + */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FTC_ImageTypeRec + * + * @description: + * A structure used to model the type of images in a glyph cache. + * + * @fields: + * face_id :: + * The face ID. + * + * width :: + * The width in pixels. + * + * height :: + * The height in pixels. + * + * flags :: + * The load flags, as in @FT_Load_Glyph. + * + */ + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + + /************************************************************************** + * + * @type: + * FTC_ImageType + * + * @description: + * A handle to an @FTC_ImageTypeRec structure. + * + */ + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + + /* */ + + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( (d1)->face_id == (d2)->face_id && \ + (d1)->width == (d2)->width && \ + (d1)->flags == (d2)->flags ) + + + /************************************************************************** + * + * @type: + * FTC_ImageCache + * + * @description: + * A handle to a glyph image cache object. They are designed to hold + * many distinct glyph images while not exceeding a certain memory + * threshold. + */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_New + * + * @description: + * Create a new glyph image cache. + * + * @input: + * manager :: + * The parent manager for the image cache. + * + * @output: + * acache :: + * A handle to the new glyph image cache object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_Lookup + * + * @description: + * Retrieve a given glyph image from a glyph image cache. + * + * @input: + * cache :: + * A handle to the source glyph image cache. + * + * type :: + * A pointer to a glyph image type descriptor. + * + * gindex :: + * The glyph index to retrieve. + * + * @output: + * aglyph :: + * The corresponding @FT_Glyph object. 0~in case of failure. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned glyph is owned and managed by the glyph image cache. + * Never try to transform or discard it manually! You can however create + * a copy with @FT_Glyph_Copy and modify the new one. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the glyph image, after increasing its reference count. + * This ensures that the node (as well as the @FT_Glyph) will always be + * kept in the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the @FT_Glyph could be flushed out of the cache on the next call + * to one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /************************************************************************** + * + * @function: + * FTC_ImageCache_LookupScaler + * + * @description: + * A variant of @FTC_ImageCache_Lookup that uses an @FTC_ScalerRec to + * specify the face ID and its size. + * + * @input: + * cache :: + * A handle to the source glyph image cache. + * + * scaler :: + * A pointer to a scaler descriptor. + * + * load_flags :: + * The corresponding load flags. + * + * gindex :: + * The glyph index to retrieve. + * + * @output: + * aglyph :: + * The corresponding @FT_Glyph object. 0~in case of failure. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned glyph is owned and managed by the glyph image cache. + * Never try to transform or discard it manually! You can however create + * a copy with @FT_Glyph_Copy and modify the new one. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the glyph image, after increasing its reference count. + * This ensures that the node (as well as the @FT_Glyph) will always be + * kept in the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the @FT_Glyph could be flushed out of the cache on the next call + * to one of the caching sub-system APIs. Don't assume that it is + * persistent! + * + * Calls to @FT_Set_Char_Size and friends have no effect on cached + * glyphs; you should always use the FreeType cache API instead. + */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + + /************************************************************************** + * + * @type: + * FTC_SBit + * + * @description: + * A handle to a small bitmap descriptor. See the @FTC_SBitRec structure + * for details. + */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /************************************************************************** + * + * @struct: + * FTC_SBitRec + * + * @description: + * A very compact structure used to describe a small glyph bitmap. + * + * @fields: + * width :: + * The bitmap width in pixels. + * + * height :: + * The bitmap height in pixels. + * + * left :: + * The horizontal distance from the pen position to the left bitmap + * border (a.k.a. 'left side bearing', or 'lsb'). + * + * top :: + * The vertical distance from the pen position (on the baseline) to the + * upper bitmap border (a.k.a. 'top side bearing'). The distance is + * positive for upwards y~coordinates. + * + * format :: + * The format of the glyph bitmap (monochrome or gray). + * + * max_grays :: + * Maximum gray level value (in the range 1 to~255). + * + * pitch :: + * The number of bytes per bitmap line. May be positive or negative. + * + * xadvance :: + * The horizontal advance width in pixels. + * + * yadvance :: + * The vertical advance height in pixels. + * + * buffer :: + * A pointer to the bitmap pixels. + */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /************************************************************************** + * + * @type: + * FTC_SBitCache + * + * @description: + * A handle to a small bitmap cache. These are special cache objects + * used to store small glyph bitmaps (and anti-aliased pixmaps) in a much + * more efficient way than the traditional glyph image cache implemented + * by @FTC_ImageCache. + */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_New + * + * @description: + * Create a new cache to store small glyph bitmaps. + * + * @input: + * manager :: + * A handle to the source cache manager. + * + * @output: + * acache :: + * A handle to the new sbit cache. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_Lookup + * + * @description: + * Look up a given small glyph bitmap in a given sbit cache and 'lock' it + * to prevent its flushing from the cache until needed. + * + * @input: + * cache :: + * A handle to the source sbit cache. + * + * type :: + * A pointer to the glyph image type descriptor. + * + * gindex :: + * The glyph index. + * + * @output: + * sbit :: + * A handle to a small bitmap descriptor. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The small bitmap descriptor and its bit buffer are owned by the cache + * and should never be freed by the application. They might as well + * disappear from memory on the next cache lookup, so don't treat them as + * persistent data. + * + * The descriptor's `buffer` field is set to~0 to indicate a missing + * glyph bitmap. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the bitmap, after increasing its reference count. This + * ensures that the node (as well as the image) will always be kept in + * the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the bitmap could be flushed out of the cache on the next call to + * one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + + /************************************************************************** + * + * @function: + * FTC_SBitCache_LookupScaler + * + * @description: + * A variant of @FTC_SBitCache_Lookup that uses an @FTC_ScalerRec to + * specify the face ID and its size. + * + * @input: + * cache :: + * A handle to the source sbit cache. + * + * scaler :: + * A pointer to the scaler descriptor. + * + * load_flags :: + * The corresponding load flags. + * + * gindex :: + * The glyph index. + * + * @output: + * sbit :: + * A handle to a small bitmap descriptor. + * + * anode :: + * Used to return the address of the corresponding cache node after + * incrementing its reference count (see note below). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The small bitmap descriptor and its bit buffer are owned by the cache + * and should never be freed by the application. They might as well + * disappear from memory on the next cache lookup, so don't treat them as + * persistent data. + * + * The descriptor's `buffer` field is set to~0 to indicate a missing + * glyph bitmap. + * + * If `anode` is _not_ `NULL`, it receives the address of the cache node + * containing the bitmap, after increasing its reference count. This + * ensures that the node (as well as the image) will always be kept in + * the cache until you call @FTC_Node_Unref to 'release' it. + * + * If `anode` is `NULL`, the cache node is left unchanged, which means + * that the bitmap could be flushed out of the cache on the next call to + * one of the caching sub-system APIs. Don't assume that it is + * persistent! + */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCACHE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftchapters.h b/Dependencies/freetype/freetype/include/freetype/ftchapters.h new file mode 100644 index 00000000..7566fbd1 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftchapters.h @@ -0,0 +1,168 @@ +/**************************************************************************** + * + * This file defines the structure of the FreeType reference. + * It is used by the python script that generates the HTML files. + * + */ + + + /************************************************************************** + * + * @chapter: + * general_remarks + * + * @title: + * General Remarks + * + * @sections: + * preamble + * header_inclusion + * user_allocation + * + */ + + + /************************************************************************** + * + * @chapter: + * core_api + * + * @title: + * Core API + * + * @sections: + * basic_types + * library_setup + * face_creation + * font_testing_macros + * sizing_and_scaling + * glyph_retrieval + * character_mapping + * information_retrieval + * other_api_data + * + */ + + + /************************************************************************** + * + * @chapter: + * extended_api + * + * @title: + * Extended API + * + * @sections: + * glyph_variants + * color_management + * layer_management + * glyph_management + * mac_specific + * sizes_management + * header_file_macros + * + */ + + + /************************************************************************** + * + * @chapter: + * format_specific + * + * @title: + * Format-Specific API + * + * @sections: + * multiple_masters + * truetype_tables + * type1_tables + * sfnt_names + * bdf_fonts + * cid_fonts + * pfr_fonts + * winfnt_fonts + * svg_fonts + * font_formats + * gasp_table + * + */ + + + /************************************************************************** + * + * @chapter: + * module_specific + * + * @title: + * Controlling FreeType Modules + * + * @sections: + * auto_hinter + * cff_driver + * t1_cid_driver + * tt_driver + * pcf_driver + * ot_svg_driver + * properties + * parameter_tags + * lcd_rendering + * + */ + + + /************************************************************************** + * + * @chapter: + * cache_subsystem + * + * @title: + * Cache Sub-System + * + * @sections: + * cache_subsystem + * + */ + + + /************************************************************************** + * + * @chapter: + * support_api + * + * @title: + * Support API + * + * @sections: + * computations + * list_processing + * outline_processing + * quick_advance + * bitmap_handling + * raster + * glyph_stroker + * system_interface + * module_management + * gzip + * lzw + * bzip2 + * debugging_apis + * + */ + + + /************************************************************************** + * + * @chapter: + * error_codes + * + * @title: + * Error Codes + * + * @sections: + * error_enumerations + * error_code_values + * + */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftcid.h b/Dependencies/freetype/freetype/include/freetype/ftcid.h new file mode 100644 index 00000000..96b2a90f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftcid.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * + * ftcid.h + * + * FreeType API for accessing CID font information (specification). + * + * Copyright (C) 2007-2024 by + * Dereg Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCID_H_ +#define FTCID_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * cid_fonts + * + * @title: + * CID Fonts + * + * @abstract: + * CID-keyed font-specific API. + * + * @description: + * This section contains the declaration of CID-keyed font-specific + * functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_CID_Registry_Ordering_Supplement + * + * @description: + * Retrieve the Registry/Ordering/Supplement triple (also known as the + * "R/O/S") from a CID-keyed font. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * registry :: + * The registry, as a C~string, owned by the face. + * + * ordering :: + * The ordering, as a C~string, owned by the face. + * + * supplement :: + * The supplement. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces, returning an error + * otherwise. + * + * @since: + * 2.3.6 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + + + /************************************************************************** + * + * @function: + * FT_Get_CID_Is_Internally_CID_Keyed + * + * @description: + * Retrieve the type of the input face, CID keyed or not. In contrast + * to the @FT_IS_CID_KEYED macro this function returns successfully also + * for CID-keyed fonts in an SFNT wrapper. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * is_cid :: + * The type of the face as an @FT_Bool. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, returning + * an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ); + + + /************************************************************************** + * + * @function: + * FT_Get_CID_From_Glyph_Index + * + * @description: + * Retrieve the CID of the input glyph index. + * + * @input: + * face :: + * A handle to the input face. + * + * glyph_index :: + * The input glyph index. + * + * @output: + * cid :: + * The CID as an @FT_UInt. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, returning + * an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftcolor.h b/Dependencies/freetype/freetype/include/freetype/ftcolor.h new file mode 100644 index 00000000..420720dd --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftcolor.h @@ -0,0 +1,1667 @@ +/**************************************************************************** + * + * ftcolor.h + * + * FreeType's glyph color management (specification). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCOLOR_H_ +#define FTCOLOR_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * color_management + * + * @title: + * Glyph Color Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'CPAL' table data. + * + * @description: + * The functions described here allow access and manipulation of color + * palette entries in OpenType's 'CPAL' tables. + */ + + + /************************************************************************** + * + * @struct: + * FT_Color + * + * @description: + * This structure models a BGRA color value of a 'CPAL' palette entry. + * + * The used color space is sRGB; the colors are not pre-multiplied, and + * alpha values must be explicitly set. + * + * @fields: + * blue :: + * Blue value. + * + * green :: + * Green value. + * + * red :: + * Red value. + * + * alpha :: + * Alpha value, giving the red, green, and blue color's opacity. + * + * @since: + * 2.10 + */ + typedef struct FT_Color_ + { + FT_Byte blue; + FT_Byte green; + FT_Byte red; + FT_Byte alpha; + + } FT_Color; + + + /************************************************************************** + * + * @enum: + * FT_PALETTE_XXX + * + * @description: + * A list of bit field constants used in the `palette_flags` array of the + * @FT_Palette_Data structure to indicate for which background a palette + * with a given index is usable. + * + * @values: + * FT_PALETTE_FOR_LIGHT_BACKGROUND :: + * The palette is appropriate to use when displaying the font on a + * light background such as white. + * + * FT_PALETTE_FOR_DARK_BACKGROUND :: + * The palette is appropriate to use when displaying the font on a dark + * background such as black. + * + * @since: + * 2.10 + */ +#define FT_PALETTE_FOR_LIGHT_BACKGROUND 0x01 +#define FT_PALETTE_FOR_DARK_BACKGROUND 0x02 + + + /************************************************************************** + * + * @struct: + * FT_Palette_Data + * + * @description: + * This structure holds the data of the 'CPAL' table. + * + * @fields: + * num_palettes :: + * The number of palettes. + * + * palette_name_ids :: + * An optional read-only array of palette name IDs with `num_palettes` + * elements, corresponding to entries like 'dark' or 'light' in the + * font's 'name' table. + * + * An empty name ID in the 'CPAL' table gets represented as value + * 0xFFFF. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * palette_flags :: + * An optional read-only array of palette flags with `num_palettes` + * elements. Possible values are an ORed combination of + * @FT_PALETTE_FOR_LIGHT_BACKGROUND and + * @FT_PALETTE_FOR_DARK_BACKGROUND. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * num_palette_entries :: + * The number of entries in a single palette. All palettes have the + * same size. + * + * palette_entry_name_ids :: + * An optional read-only array of palette entry name IDs with + * `num_palette_entries`. In each palette, entries with the same index + * have the same function. For example, index~0 might correspond to + * string 'outline' in the font's 'name' table to indicate that this + * palette entry is used for outlines, index~1 might correspond to + * 'fill' to indicate the filling color palette entry, etc. + * + * An empty entry name ID in the 'CPAL' table gets represented as value + * 0xFFFF. + * + * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. + * + * @note: + * Use function @FT_Get_Sfnt_Name to map name IDs and entry name IDs to + * name strings. + * + * Use function @FT_Palette_Select to get the colors associated with a + * palette entry. + * + * @since: + * 2.10 + */ + typedef struct FT_Palette_Data_ { + FT_UShort num_palettes; + const FT_UShort* palette_name_ids; + const FT_UShort* palette_flags; + + FT_UShort num_palette_entries; + const FT_UShort* palette_entry_name_ids; + + } FT_Palette_Data; + + + /************************************************************************** + * + * @function: + * FT_Palette_Data_Get + * + * @description: + * Retrieve the face's color palette data. + * + * @input: + * face :: + * The source face handle. + * + * @output: + * apalette :: + * A pointer to an @FT_Palette_Data structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * All arrays in the returned @FT_Palette_Data structure are read-only. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette ); + + + /************************************************************************** + * + * @function: + * FT_Palette_Select + * + * @description: + * This function has two purposes. + * + * (1) It activates a palette for rendering color glyphs, and + * + * (2) it retrieves all (unmodified) color entries of this palette. This + * function returns a read-write array, which means that a calling + * application can modify the palette entries on demand. + * + * A corollary of (2) is that calling the function, then modifying some + * values, then calling the function again with the same arguments resets + * all color entries to the original 'CPAL' values; all user modifications + * are lost. + * + * @input: + * face :: + * The source face handle. + * + * palette_index :: + * The palette index. + * + * @output: + * apalette :: + * An array of color entries for a palette with index `palette_index`, + * having `num_palette_entries` elements (as found in the + * `FT_Palette_Data` structure). If `apalette` is set to `NULL`, no + * array gets returned (and no color entries can be modified). + * + * In case the font doesn't support color palettes, `NULL` is returned. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The array pointed to by `apalette_entries` is owned and managed by + * FreeType. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ); + + + /************************************************************************** + * + * @function: + * FT_Palette_Set_Foreground_Color + * + * @description: + * 'COLR' uses palette index 0xFFFF to indicate a 'text foreground + * color'. This function sets this value. + * + * @input: + * face :: + * The source face handle. + * + * foreground_color :: + * An `FT_Color` structure to define the text foreground color. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function isn't called, the text foreground color is set to + * white opaque (BGRA value 0xFFFFFFFF) if + * @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette, + * and black opaque (BGRA value 0x000000FF) otherwise, including the case + * that no palette types are available in the 'CPAL' table. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ); + + + /************************************************************************** + * + * @section: + * layer_management + * + * @title: + * Glyph Layer Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'COLR' table data. + * + * @description: + * The functions described here allow access of colored glyph layer data + * in OpenType's 'COLR' tables. + */ + + + /************************************************************************** + * + * @struct: + * FT_LayerIterator + * + * @description: + * This iterator object is needed for @FT_Get_Color_Glyph_Layer. + * + * @fields: + * num_layers :: + * The number of glyph layers for the requested glyph index. Will be + * set by @FT_Get_Color_Glyph_Layer. + * + * layer :: + * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. + * + * p :: + * An opaque pointer into 'COLR' table data. The caller must set this + * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. + */ + typedef struct FT_LayerIterator_ + { + FT_UInt num_layers; + FT_UInt layer; + FT_Byte* p; + + } FT_LayerIterator; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Layer + * + * @description: + * This is an interface to the 'COLR' table in OpenType fonts to + * iteratively retrieve the colored glyph layers associated with the + * current glyph slot. + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/colr + * + * The glyph layer data for a given glyph index, if present, provides an + * alternative, multi-color glyph representation: Instead of rendering + * the outline or bitmap with the given glyph index, glyphs with the + * indices and colors returned by this function are rendered layer by + * layer. + * + * The returned elements are ordered in the z~direction from bottom to + * top; the 'n'th element should be rendered with the associated palette + * color and blended on top of the already rendered layers (elements 0, + * 1, ..., n-1). + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * The color palette can be retrieved with @FT_Palette_Select. + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + * + * @note: + * This function is necessary if you want to handle glyph layers by + * yourself. In particular, functions that operate with @FT_GlyphRec + * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access + * to this information. + * + * Note that @FT_Render_Glyph is able to handle colored glyph layers + * automatically if the @FT_LOAD_COLOR flag is passed to a previous call + * to @FT_Load_Glyph. [This is an experimental feature.] + * + * @example: + * ``` + * FT_Color* palette; + * FT_LayerIterator iterator; + * + * FT_Bool have_layers; + * FT_UInt layer_glyph_index; + * FT_UInt layer_color_index; + * + * + * error = FT_Palette_Select( face, palette_index, &palette ); + * if ( error ) + * palette = NULL; + * + * iterator.p = NULL; + * have_layers = FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ); + * + * if ( palette && have_layers ) + * { + * do + * { + * FT_Color layer_color; + * + * + * if ( layer_color_index == 0xFFFF ) + * layer_color = text_foreground_color; + * else + * layer_color = palette[layer_color_index]; + * + * // Load and render glyph `layer_glyph_index', then + * // blend resulting pixmap (using color `layer_color') + * // with previously created pixmaps. + * + * } while ( FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ) ); + * } + * ``` + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @enum: + * FT_PaintFormat + * + * @description: + * Enumeration describing the different paint format types of the v1 + * extensions to the 'COLR' table, see + * 'https://github.com/googlefonts/colr-gradients-spec'. + * + * The enumeration values loosely correspond with the format numbers of + * the specification: FreeType always returns a fully specified 'Paint' + * structure for the 'Transform', 'Translate', 'Scale', 'Rotate', and + * 'Skew' table types even though the specification has different formats + * depending on whether or not a center is specified, whether the scale + * is uniform in x and y~direction or not, etc. Also, only non-variable + * format identifiers are listed in this enumeration; as soon as support + * for variable 'COLR' v1 fonts is implemented, interpolation is + * performed dependent on axis coordinates, which are configured on the + * @FT_Face through @FT_Set_Var_Design_Coordinates. This implies that + * always static, readily interpolated values are returned in the 'Paint' + * structures. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintFormat_ + { + FT_COLR_PAINTFORMAT_COLR_LAYERS = 1, + FT_COLR_PAINTFORMAT_SOLID = 2, + FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 4, + FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 6, + FT_COLR_PAINTFORMAT_SWEEP_GRADIENT = 8, + FT_COLR_PAINTFORMAT_GLYPH = 10, + FT_COLR_PAINTFORMAT_COLR_GLYPH = 11, + FT_COLR_PAINTFORMAT_TRANSFORM = 12, + FT_COLR_PAINTFORMAT_TRANSLATE = 14, + FT_COLR_PAINTFORMAT_SCALE = 16, + FT_COLR_PAINTFORMAT_ROTATE = 24, + FT_COLR_PAINTFORMAT_SKEW = 28, + FT_COLR_PAINTFORMAT_COMPOSITE = 32, + FT_COLR_PAINT_FORMAT_MAX = 33, + FT_COLR_PAINTFORMAT_UNSUPPORTED = 255 + + } FT_PaintFormat; + + + /************************************************************************** + * + * @struct: + * FT_ColorStopIterator + * + * @description: + * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps + * state while iterating over the stops of an @FT_ColorLine, representing + * the `ColorLine` struct of the v1 extensions to 'COLR', see + * 'https://github.com/googlefonts/colr-gradients-spec'. Do not manually + * modify fields of this iterator. + * + * @fields: + * num_color_stops :: + * The number of color stops for the requested glyph index. Set by + * @FT_Get_Paint. + * + * current_color_stop :: + * The current color stop. Set by @FT_Get_Colorline_Stops. + * + * p :: + * An opaque pointer into 'COLR' table data. Set by @FT_Get_Paint. + * Updated by @FT_Get_Colorline_Stops. + * + * read_variable :: + * A boolean keeping track of whether variable color lines are to be + * read. Set by @FT_Get_Paint. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStopIterator_ + { + FT_UInt num_color_stops; + FT_UInt current_color_stop; + + FT_Byte* p; + + FT_Bool read_variable; + + } FT_ColorStopIterator; + + + /************************************************************************** + * + * @struct: + * FT_ColorIndex + * + * @description: + * A structure representing a `ColorIndex` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * palette_index :: + * The palette index into a 'CPAL' palette. + * + * alpha :: + * Alpha transparency value multiplied with the value from 'CPAL'. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorIndex_ + { + FT_UInt16 palette_index; + FT_F2Dot14 alpha; + + } FT_ColorIndex; + + + /************************************************************************** + * + * @struct: + * FT_ColorStop + * + * @description: + * A structure representing a `ColorStop` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * stop_offset :: + * The stop offset along the gradient, expressed as a 16.16 fixed-point + * coordinate. + * + * color :: + * The color information for this stop, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStop_ + { + FT_Fixed stop_offset; + FT_ColorIndex color; + + } FT_ColorStop; + + + /************************************************************************** + * + * @enum: + * FT_PaintExtend + * + * @description: + * An enumeration representing the 'Extend' mode of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes how the gradient fill continues at the other boundaries. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintExtend_ + { + FT_COLR_PAINT_EXTEND_PAD = 0, + FT_COLR_PAINT_EXTEND_REPEAT = 1, + FT_COLR_PAINT_EXTEND_REFLECT = 2 + + } FT_PaintExtend; + + + /************************************************************************** + * + * @struct: + * FT_ColorLine + * + * @description: + * A structure representing a `ColorLine` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes a list of color stops along the defined gradient. + * + * @fields: + * extend :: + * The extend mode at the outer boundaries, see @FT_PaintExtend. + * + * color_stop_iterator :: + * The @FT_ColorStopIterator used to enumerate and retrieve the + * actual @FT_ColorStop's. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorLine_ + { + FT_PaintExtend extend; + FT_ColorStopIterator color_stop_iterator; + + } FT_ColorLine; + + + /************************************************************************** + * + * @struct: + * FT_Affine23 + * + * @description: + * A structure used to store a 2x3 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is + * + * ``` + * x' = x*xx + y*xy + dx + * y' = x*yx + y*yy + dy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * dx :: + * x translation. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + * + * dy :: + * y translation. + * + * @since: + * 2.13 + */ + typedef struct FT_Affine_23_ + { + FT_Fixed xx, xy, dx; + FT_Fixed yx, yy, dy; + + } FT_Affine23; + + + /************************************************************************** + * + * @enum: + * FT_Composite_Mode + * + * @description: + * An enumeration listing the 'COLR' v1 composite modes used in + * @FT_PaintComposite. For more details on each paint mode, see + * 'https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators'. + * + * @since: + * 2.13 + */ + typedef enum FT_Composite_Mode_ + { + FT_COLR_COMPOSITE_CLEAR = 0, + FT_COLR_COMPOSITE_SRC = 1, + FT_COLR_COMPOSITE_DEST = 2, + FT_COLR_COMPOSITE_SRC_OVER = 3, + FT_COLR_COMPOSITE_DEST_OVER = 4, + FT_COLR_COMPOSITE_SRC_IN = 5, + FT_COLR_COMPOSITE_DEST_IN = 6, + FT_COLR_COMPOSITE_SRC_OUT = 7, + FT_COLR_COMPOSITE_DEST_OUT = 8, + FT_COLR_COMPOSITE_SRC_ATOP = 9, + FT_COLR_COMPOSITE_DEST_ATOP = 10, + FT_COLR_COMPOSITE_XOR = 11, + FT_COLR_COMPOSITE_PLUS = 12, + FT_COLR_COMPOSITE_SCREEN = 13, + FT_COLR_COMPOSITE_OVERLAY = 14, + FT_COLR_COMPOSITE_DARKEN = 15, + FT_COLR_COMPOSITE_LIGHTEN = 16, + FT_COLR_COMPOSITE_COLOR_DODGE = 17, + FT_COLR_COMPOSITE_COLOR_BURN = 18, + FT_COLR_COMPOSITE_HARD_LIGHT = 19, + FT_COLR_COMPOSITE_SOFT_LIGHT = 20, + FT_COLR_COMPOSITE_DIFFERENCE = 21, + FT_COLR_COMPOSITE_EXCLUSION = 22, + FT_COLR_COMPOSITE_MULTIPLY = 23, + FT_COLR_COMPOSITE_HSL_HUE = 24, + FT_COLR_COMPOSITE_HSL_SATURATION = 25, + FT_COLR_COMPOSITE_HSL_COLOR = 26, + FT_COLR_COMPOSITE_HSL_LUMINOSITY = 27, + FT_COLR_COMPOSITE_MAX = 28 + + } FT_Composite_Mode; + + + /************************************************************************** + * + * @struct: + * FT_OpaquePaint + * + * @description: + * A structure representing an offset to a `Paint` value stored in any + * of the paint tables of a 'COLR' v1 font. Compare Offset<24> there. + * When 'COLR' v1 paint tables represented by FreeType objects such as + * @FT_PaintColrLayers, @FT_PaintComposite, or @FT_PaintTransform + * reference downstream nested paint tables, we do not immediately + * retrieve them but encapsulate their location in this type. Use + * @FT_Get_Paint to retrieve the actual @FT_COLR_Paint object that + * describes the details of the respective paint table. + * + * @fields: + * p :: + * An internal offset to a Paint table, needs to be set to NULL before + * passing this struct as an argument to @FT_Get_Paint. + * + * insert_root_transform :: + * An internal boolean to track whether an initial root transform is + * to be provided. Do not set this value. + * + * @since: + * 2.13 + */ + typedef struct FT_Opaque_Paint_ + { + FT_Byte* p; + FT_Bool insert_root_transform; + } FT_OpaquePaint; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrLayers + * + * @description: + * A structure representing a `PaintColrLayers` table of a 'COLR' v1 + * font. This table describes a set of layers that are to be composited + * with composite mode `FT_COLR_COMPOSITE_SRC_OVER`. The return value + * of this function is an @FT_LayerIterator initialized so that it can + * be used with @FT_Get_Paint_Layers to retrieve the @FT_OpaquePaint + * objects as references to each layer. + * + * @fields: + * layer_iterator :: + * The layer iterator that describes the layers of this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrLayers_ + { + FT_LayerIterator layer_iterator; + + } FT_PaintColrLayers; + + + /************************************************************************** + * + * @struct: + * FT_PaintSolid + * + * @description: + * A structure representing a `PaintSolid` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * Using a `PaintSolid` value means that the glyph layer filled with + * this paint is solid-colored and does not contain a gradient. + * + * @fields: + * color :: + * The color information for this solid paint, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSolid_ + { + FT_ColorIndex color; + + } FT_PaintSolid; + + + /************************************************************************** + * + * @struct: + * FT_PaintLinearGradient + * + * @description: + * A structure representing a `PaintLinearGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a linear gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * p0 :: + * The starting point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p1 :: + * The end point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p2 :: + * Optional point~p2 to rotate the gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * Otherwise equal to~p0. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintLinearGradient_ + { + FT_ColorLine colorline; + + /* TODO: Potentially expose those as x0, y0 etc. */ + FT_Vector p0; + FT_Vector p1; + FT_Vector p2; + + } FT_PaintLinearGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintRadialGradient + * + * @description: + * A structure representing a `PaintRadialGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a radial gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * c0 :: + * The center of the starting point of the radial gradient in font + * units represented as a 16.16 fixed-point `FT_Vector`. + * + * r0 :: + * The radius of the starting circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * c1 :: + * The center of the end point of the radial gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * r1 :: + * The radius of the end circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintRadialGradient_ + { + FT_ColorLine colorline; + + FT_Vector c0; + FT_Pos r0; + FT_Vector c1; + FT_Pos r1; + + } FT_PaintRadialGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintSweepGradient + * + * @description: + * A structure representing a `PaintSweepGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a sweep gradient + * from `start_angle` to `end_angle`. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * center :: + * The center of the sweep gradient in font units represented as a + * vector of 16.16 fixed-point values. + * + * start_angle :: + * The start angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * end_angle :: + * The end angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSweepGradient_ + { + FT_ColorLine colorline; + + FT_Vector center; + FT_Fixed start_angle; + FT_Fixed end_angle; + + } FT_PaintSweepGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintGlyph` paint table. + * + * @fields: + * paint :: + * An opaque paint object pointing to a `Paint` table that serves as + * the fill for the glyph ID. + * + * glyphID :: + * The glyph ID from the 'glyf' table, which serves as the contour + * information that is filled with paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintGlyph_ + { + FT_OpaquePaint paint; + FT_UInt glyphID; + + } FT_PaintGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintColorGlyph` paint table. + * + * @fields: + * glyphID :: + * The glyph ID from the `BaseGlyphV1List` table that is drawn for + * this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrGlyph_ + { + FT_UInt glyphID; + + } FT_PaintColrGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintTransform + * + * @description: + * A structure representing a 'COLR' v1 `PaintTransform` paint table. + * + * @fields: + * paint :: + * An opaque paint that is subject to being transformed. + * + * affine :: + * A 2x3 transformation matrix in @FT_Affine23 format containing + * 16.16 fixed-point values. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTransform_ + { + FT_OpaquePaint paint; + FT_Affine23 affine; + + } FT_PaintTransform; + + + /************************************************************************** + * + * @struct: + * FT_PaintTranslate + * + * @description: + * A structure representing a 'COLR' v1 `PaintTranslate` paint table. + * Used for translating downstream paints by a given x and y~delta. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * dx :: + * Translation in x~direction in font units represented as a + * 16.16 fixed-point value. + * + * dy :: + * Translation in y~direction in font units represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTranslate_ + { + FT_OpaquePaint paint; + + FT_Fixed dx; + FT_Fixed dy; + + } FT_PaintTranslate; + + + /************************************************************************** + * + * @struct: + * FT_PaintScale + * + * @description: + * A structure representing all of the 'COLR' v1 'PaintScale*' paint + * tables. Used for scaling downstream paints by a given x and y~scale, + * with a given center. This structure is used for all 'PaintScale*' + * types that are part of specification; fields of this structure are + * filled accordingly. If there is a center, the center values are set, + * otherwise they are set to the zero coordinate. If the source font + * file has 'PaintScaleUniform*' set, the scale values are set + * accordingly to the same value. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * scaled. + * + * scale_x :: + * Scale factor in x~direction represented as a + * 16.16 fixed-point value. + * + * scale_y :: + * Scale factor in y~direction represented as a + * 16.16 fixed-point value. + * + * center_x :: + * x~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * center_y :: + * y~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintScale_ + { + FT_OpaquePaint paint; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintScale; + + + /************************************************************************** + * + * @struct: + * FT_PaintRotate + * + * @description: + * A structure representing a 'COLR' v1 `PaintRotate` paint table. Used + * for rotating downstream paints with a given center and angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * angle :: + * The rotation angle that is to be applied in degrees divided by + * 180.0 (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees value. + * + * center_x :: + * The x~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + + typedef struct FT_PaintRotate_ + { + FT_OpaquePaint paint; + + FT_Fixed angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintRotate; + + + /************************************************************************** + * + * @struct: + * FT_PaintSkew + * + * @description: + * A structure representing a 'COLR' v1 `PaintSkew` paint table. Used + * for skewing or shearing downstream paints by a given center and + * angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * skewed. + * + * x_skew_angle :: + * The skewing angle in x~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * y_skew_angle :: + * The skewing angle in y~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * center_x :: + * The x~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSkew_ + { + FT_OpaquePaint paint; + + FT_Fixed x_skew_angle; + FT_Fixed y_skew_angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintSkew; + + + /************************************************************************** + * + * @struct: + * FT_PaintComposite + * + * @description: + * A structure representing a 'COLR' v1 `PaintComposite` paint table. + * Used for compositing two paints in a 'COLR' v1 directed acyclic graph. + * + * @fields: + * source_paint :: + * An @FT_OpaquePaint object referencing the source that is to be + * composited. + * + * composite_mode :: + * An @FT_Composite_Mode enum value determining the composition + * operation. + * + * backdrop_paint :: + * An @FT_OpaquePaint object referencing the backdrop paint that + * `source_paint` is composited onto. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintComposite_ + { + FT_OpaquePaint source_paint; + FT_Composite_Mode composite_mode; + FT_OpaquePaint backdrop_paint; + + } FT_PaintComposite; + + + /************************************************************************** + * + * @union: + * FT_COLR_Paint + * + * @description: + * A union object representing format and details of a paint table of a + * 'COLR' v1 font, see + * 'https://github.com/googlefonts/colr-gradients-spec'. Use + * @FT_Get_Paint to retrieve a @FT_COLR_Paint for an @FT_OpaquePaint + * object. + * + * @fields: + * format :: + * The gradient format for this Paint structure. + * + * u :: + * Union of all paint table types: + * + * * @FT_PaintColrLayers + * * @FT_PaintGlyph + * * @FT_PaintSolid + * * @FT_PaintLinearGradient + * * @FT_PaintRadialGradient + * * @FT_PaintSweepGradient + * * @FT_PaintTransform + * * @FT_PaintTranslate + * * @FT_PaintRotate + * * @FT_PaintSkew + * * @FT_PaintComposite + * * @FT_PaintColrGlyph + * + * @since: + * 2.13 + */ + typedef struct FT_COLR_Paint_ + { + FT_PaintFormat format; + + union + { + FT_PaintColrLayers colr_layers; + FT_PaintGlyph glyph; + FT_PaintSolid solid; + FT_PaintLinearGradient linear_gradient; + FT_PaintRadialGradient radial_gradient; + FT_PaintSweepGradient sweep_gradient; + FT_PaintTransform transform; + FT_PaintTranslate translate; + FT_PaintScale scale; + FT_PaintRotate rotate; + FT_PaintSkew skew; + FT_PaintComposite composite; + FT_PaintColrGlyph colr_glyph; + + } u; + + } FT_COLR_Paint; + + + /************************************************************************** + * + * @enum: + * FT_Color_Root_Transform + * + * @description: + * An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to + * return a root transform to configure the client's graphics context + * matrix. + * + * @values: + * FT_COLOR_INCLUDE_ROOT_TRANSFORM :: + * Do include the root transform as the initial @FT_COLR_Paint object. + * + * FT_COLOR_NO_ROOT_TRANSFORM :: + * Do not output an initial root transform. + * + * @since: + * 2.13 + */ + typedef enum FT_Color_Root_Transform_ + { + FT_COLOR_INCLUDE_ROOT_TRANSFORM, + FT_COLOR_NO_ROOT_TRANSFORM, + + FT_COLOR_ROOT_TRANSFORM_MAX + + } FT_Color_Root_Transform; + + + /************************************************************************** + * + * @struct: + * FT_ClipBox + * + * @description: + * A structure representing a 'COLR' v1 'ClipBox' table. 'COLR' v1 + * glyphs may optionally define a clip box for aiding allocation or + * defining a maximum drawable region. Use @FT_Get_Color_Glyph_ClipBox + * to retrieve it. + * + * @fields: + * bottom_left :: + * The bottom left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_left :: + * The top left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_right :: + * The top right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * bottom_right :: + * The bottom right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * @since: + * 2.13 + */ + typedef struct FT_ClipBox_ + { + FT_Vector bottom_left; + FT_Vector top_left; + FT_Vector top_right; + FT_Vector bottom_right; + + } FT_ClipBox; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Paint + * + * @description: + * This is the starting point and interface to color gradient + * information in a 'COLR' v1 table in OpenType fonts to recursively + * retrieve the paint tables for the directed acyclic graph of a colored + * glyph, given a glyph ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * In a 'COLR' v1 font, each color glyph defines a directed acyclic + * graph of nested paint tables, such as `PaintGlyph`, `PaintSolid`, + * `PaintLinearGradient`, `PaintRadialGradient`, and so on. Using this + * function and specifying a glyph ID, one retrieves the root paint + * table for this glyph ID. + * + * This function allows control whether an initial root transform is + * returned to configure scaling, transform, and translation correctly + * on the client's graphics context. The initial root transform is + * computed and returned according to the values configured for @FT_Size + * and @FT_Set_Transform on the @FT_Face object, see below for details + * of the `root_transform` parameter. This has implications for a + * client 'COLR' v1 implementation: When this function returns an + * initially computed root transform, at the time of executing the + * @FT_PaintGlyph operation, the contours should be retrieved using + * @FT_Load_Glyph at unscaled, untransformed size. This is because the + * root transform applied to the graphics context will take care of + * correct scaling. + * + * Alternatively, to allow hinting of contours, at the time of executing + * @FT_Load_Glyph, the current graphics context transformation matrix + * can be decomposed into a scaling matrix and a remainder, and + * @FT_Load_Glyph can be used to retrieve the contours at scaled size. + * Care must then be taken to blit or clip to the graphics context with + * taking this remainder transformation into account. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the root paint table. + * + * root_transform :: + * Specifies whether an initially computed root is returned by the + * @FT_PaintTransform operation to account for the activated size + * (see @FT_Activate_Size) and the configured transform and translate + * (see @FT_Set_Transform). + * + * This root transform is returned before nodes of the glyph graph of + * the font are returned. Subsequent @FT_COLR_Paint structures + * contain unscaled and untransformed values. The inserted root + * transform enables the client application to apply an initial + * transform to its graphics context. When executing subsequent + * FT_COLR_Paint operations, values from @FT_COLR_Paint operations + * will ultimately be correctly scaled because of the root transform + * applied to the graphics context. Use + * @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use + * @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be + * useful when traversing the 'COLR' v1 glyph graph and reaching a + * @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and + * painting that inline, no additional root transform is needed as it + * has already been applied to the graphics context at the beginning + * of drawing this glyph. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_ClipBox + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @return: + * Value~1 if a clip box is found. If no clip box is found or an error + * occured, value~0 is returned. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint_Layers + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * If the root paint of a color glyph, or a nested paint of a 'COLR' + * glyph is a `PaintColrLayers` table, this function retrieves the + * layers of the `PaintColrLayers` table. + * + * The @FT_PaintColrLayers object contains an @FT_LayerIterator, which + * is used here to iterate over the layers. Each layer is returned as + * an @FT_OpaquePaint object, which then can be used with @FT_Get_Paint + * to retrieve the actual paint object. + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Colorline_Stops + * + * @description: + * This is an interface to color gradient information in a 'COLR' v1 + * table in OpenType fonts to iteratively retrieve the gradient and + * solid fill information for colored glyph layers for a specified glyph + * ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The retrieved @FT_ColorStopIterator, configured on an @FT_ColorLine, + * which in turn got retrieved via paint information in + * @FT_PaintLinearGradient or @FT_PaintRadialGradient. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Colorline_Stops( FT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint + * + * @description: + * Access the details of a paint using an @FT_OpaquePaint opaque paint + * object, which internally stores the offset to the respective `Paint` + * object in the 'COLR' table. + * + * @input: + * face :: + * A handle to the parent face object. + * + * opaque_paint :: + * The opaque paint object for which the underlying @FT_COLR_Paint + * data is to be retrieved. + * + * @output: + * paint :: + * The specific @FT_COLR_Paint object containing information coming + * from one of the font's `Paint*` tables. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + + /* */ + + +FT_END_HEADER + +#endif /* FTCOLOR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftdriver.h b/Dependencies/freetype/freetype/include/freetype/ftdriver.h new file mode 100644 index 00000000..1b7f539f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftdriver.h @@ -0,0 +1,1320 @@ +/**************************************************************************** + * + * ftdriver.h + * + * FreeType API for controlling driver modules (specification only). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTDRIVER_H_ +#define FTDRIVER_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * auto_hinter + * + * @title: + * The auto-hinter + * + * @abstract: + * Controlling the auto-hinting module. + * + * @description: + * While FreeType's auto-hinter doesn't expose API functions by itself, + * it is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. The following lists the available properties + * together with the necessary macros and structures. + * + * Note that the auto-hinter's module name is 'autofitter' for historical + * reasons. + * + * Available properties are @increase-x-height, @no-stem-darkening + * (experimental), @darkening-parameters (experimental), + * @glyph-to-script-map (experimental), @fallback-script (experimental), + * and @default-script (experimental), as documented in the @properties + * section. + * + */ + + + /************************************************************************** + * + * @section: + * cff_driver + * + * @title: + * The CFF driver + * + * @abstract: + * Controlling the CFF driver module. + * + * @description: + * While FreeType's CFF driver doesn't expose API functions by itself, it + * is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. + * + * The CFF driver's module name is 'cff'. + * + * Available properties are @hinting-engine, @no-stem-darkening, + * @darkening-parameters, and @random-seed, as documented in the + * @properties section. + * + * + * **Hinting and anti-aliasing principles of the new engine** + * + * The rasterizer is positioning horizontal features (e.g., ascender + * height & x-height, or crossbars) on the pixel grid and minimizing the + * amount of anti-aliasing applied to them, while placing vertical + * features (vertical stems) on the pixel grid without hinting, thus + * representing the stem position and weight accurately. Sometimes the + * vertical stems may be only partially black. In this context, + * 'anti-aliasing' means that stems are not positioned exactly on pixel + * borders, causing a fuzzy appearance. + * + * There are two principles behind this approach. + * + * 1) No hinting in the horizontal direction: Unlike 'superhinted' + * TrueType, which changes glyph widths to accommodate regular + * inter-glyph spacing, Adobe's approach is 'faithful to the design' in + * representing both the glyph width and the inter-glyph spacing designed + * for the font. This makes the screen display as close as it can be to + * the result one would get with infinite resolution, while preserving + * what is considered the key characteristics of each glyph. Note that + * the distances between unhinted and grid-fitted positions at small + * sizes are comparable to kerning values and thus would be noticeable + * (and distracting) while reading if hinting were applied. + * + * One of the reasons to not hint horizontally is anti-aliasing for LCD + * screens: The pixel geometry of modern displays supplies three vertical + * subpixels as the eye moves horizontally across each visible pixel. On + * devices where we can be certain this characteristic is present a + * rasterizer can take advantage of the subpixels to add increments of + * weight. In Western writing systems this turns out to be the more + * critical direction anyway; the weights and spacing of vertical stems + * (see above) are central to Armenian, Cyrillic, Greek, and Latin type + * designs. Even when the rasterizer uses greyscale anti-aliasing instead + * of color (a necessary compromise when one doesn't know the screen + * characteristics), the unhinted vertical features preserve the design's + * weight and spacing much better than aliased type would. + * + * 2) Alignment in the vertical direction: Weights and spacing along the + * y~axis are less critical; what is much more important is the visual + * alignment of related features (like cap-height and x-height). The + * sense of alignment for these is enhanced by the sharpness of grid-fit + * edges, while the cruder vertical resolution (full pixels instead of + * 1/3 pixels) is less of a problem. + * + * On the technical side, horizontal alignment zones for ascender, + * x-height, and other important height values (traditionally called + * 'blue zones') as defined in the font are positioned independently, + * each being rounded to the nearest pixel edge, taking care of overshoot + * suppression at small sizes, stem darkening, and scaling. + * + * Hstems (that is, hint values defined in the font to help align + * horizontal features) that fall within a blue zone are said to be + * 'captured' and are aligned to that zone. Uncaptured stems are moved + * in one of four ways, top edge up or down, bottom edge up or down. + * Unless there are conflicting hstems, the smallest movement is taken to + * minimize distortion. + * + */ + + + /************************************************************************** + * + * @section: + * pcf_driver + * + * @title: + * The PCF driver + * + * @abstract: + * Controlling the PCF driver module. + * + * @description: + * While FreeType's PCF driver doesn't expose API functions by itself, it + * is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. Right now, there is a single property + * @no-long-family-names available if FreeType is compiled with + * PCF_CONFIG_OPTION_LONG_FAMILY_NAMES. + * + * The PCF driver's module name is 'pcf'. + * + */ + + + /************************************************************************** + * + * @section: + * t1_cid_driver + * + * @title: + * The Type 1 and CID drivers + * + * @abstract: + * Controlling the Type~1 and CID driver modules. + * + * @description: + * It is possible to control the behaviour of FreeType's Type~1 and + * Type~1 CID drivers with @FT_Property_Set and @FT_Property_Get. + * + * Behind the scenes, both drivers use the Adobe CFF engine for hinting; + * however, the used properties must be specified separately. + * + * The Type~1 driver's module name is 'type1'; the CID driver's module + * name is 't1cid'. + * + * Available properties are @hinting-engine, @no-stem-darkening, + * @darkening-parameters, and @random-seed, as documented in the + * @properties section. + * + * Please see the @cff_driver section for more details on the new hinting + * engine. + * + */ + + + /************************************************************************** + * + * @section: + * tt_driver + * + * @title: + * The TrueType driver + * + * @abstract: + * Controlling the TrueType driver module. + * + * @description: + * While FreeType's TrueType driver doesn't expose API functions by + * itself, it is possible to control its behaviour with @FT_Property_Set + * and @FT_Property_Get. + * + * The TrueType driver's module name is 'truetype'; a single property + * @interpreter-version is available, as documented in the @properties + * section. + * + * To help understand the differences between interpreter versions, we + * introduce a list of definitions, kindly provided by Greg Hitchcock. + * + * _Bi-Level Rendering_ + * + * Monochromatic rendering, exclusively used in the early days of + * TrueType by both Apple and Microsoft. Microsoft's GDI interface + * supported hinting of the right-side bearing point, such that the + * advance width could be non-linear. Most often this was done to + * achieve some level of glyph symmetry. To enable reasonable + * performance (e.g., not having to run hinting on all glyphs just to get + * the widths) there was a bit in the head table indicating if the side + * bearing was hinted, and additional tables, 'hdmx' and 'LTSH', to cache + * hinting widths across multiple sizes and device aspect ratios. + * + * _Font Smoothing_ + * + * Microsoft's GDI implementation of anti-aliasing. Not traditional + * anti-aliasing as the outlines were hinted before the sampling. The + * widths matched the bi-level rendering. + * + * _ClearType Rendering_ + * + * Technique that uses physical subpixels to improve rendering on LCD + * (and other) displays. Because of the higher resolution, many methods + * of improving symmetry in glyphs through hinting the right-side bearing + * were no longer necessary. This lead to what GDI calls 'natural + * widths' ClearType, see + * http://rastertragedy.com/RTRCh4.htm#Sec21. Since hinting + * has extra resolution, most non-linearity went away, but it is still + * possible for hints to change the advance widths in this mode. + * + * _ClearType Compatible Widths_ + * + * One of the earliest challenges with ClearType was allowing the + * implementation in GDI to be selected without requiring all UI and + * documents to reflow. To address this, a compatible method of + * rendering ClearType was added where the font hints are executed once + * to determine the width in bi-level rendering, and then re-run in + * ClearType, with the difference in widths being absorbed in the font + * hints for ClearType (mostly in the white space of hints); see + * http://rastertragedy.com/RTRCh4.htm#Sec20. Somewhat by + * definition, compatible width ClearType allows for non-linear widths, + * but only when the bi-level version has non-linear widths. + * + * _ClearType Subpixel Positioning_ + * + * One of the nice benefits of ClearType is the ability to more crisply + * display fractional widths; unfortunately, the GDI model of integer + * bitmaps did not support this. However, the WPF and Direct Write + * frameworks do support fractional widths. DWrite calls this 'natural + * mode', not to be confused with GDI's 'natural widths'. Subpixel + * positioning, in the current implementation of Direct Write, + * unfortunately does not support hinted advance widths, see + * http://rastertragedy.com/RTRCh4.htm#Sec22. Note that the + * TrueType interpreter fully allows the advance width to be adjusted in + * this mode, just the DWrite client will ignore those changes. + * + * _ClearType Backward Compatibility_ + * + * This is a set of exceptions made in the TrueType interpreter to + * minimize hinting techniques that were problematic with the extra + * resolution of ClearType; see + * http://rastertragedy.com/RTRCh4.htm#Sec1 and + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx. + * This technique is not to be confused with ClearType compatible widths. + * ClearType backward compatibility has no direct impact on changing + * advance widths, but there might be an indirect impact on disabling + * some deltas. This could be worked around in backward compatibility + * mode. + * + * _Native ClearType Mode_ + * + * (Not to be confused with 'natural widths'.) This mode removes all the + * exceptions in the TrueType interpreter when running with ClearType. + * Any issues on widths would still apply, though. + * + */ + + + /************************************************************************** + * + * @section: + * ot_svg_driver + * + * @title: + * The SVG driver + * + * @abstract: + * Controlling the external rendering of OT-SVG glyphs. + * + * @description: + * By default, FreeType can only load the 'SVG~' table of OpenType fonts + * if configuration macro `FT_CONFIG_OPTION_SVG` is defined. To make it + * render SVG glyphs, an external SVG rendering library is needed. All + * details on the interface between FreeType and the external library + * via function hooks can be found in section @svg_fonts. + * + * The OT-SVG driver's module name is 'ot-svg'; it supports a single + * property called @svg-hooks, documented below in the @properties + * section. + * + */ + + + /************************************************************************** + * + * @section: + * properties + * + * @title: + * Driver properties + * + * @abstract: + * Controlling driver modules. + * + * @description: + * Driver modules can be controlled by setting and unsetting properties, + * using the functions @FT_Property_Set and @FT_Property_Get. This + * section documents the available properties, together with auxiliary + * macros and structures. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_HINTING_XXX + * + * @description: + * A list of constants used for the @hinting-engine property to select + * the hinting engine for CFF, Type~1, and CID fonts. + * + * @values: + * FT_HINTING_FREETYPE :: + * Use the old FreeType hinting engine. + * + * FT_HINTING_ADOBE :: + * Use the hinting engine contributed by Adobe. + * + * @since: + * 2.9 + * + */ +#define FT_HINTING_FREETYPE 0 +#define FT_HINTING_ADOBE 1 + + /* these constants (introduced in 2.4.12) are deprecated */ +#define FT_CFF_HINTING_FREETYPE FT_HINTING_FREETYPE +#define FT_CFF_HINTING_ADOBE FT_HINTING_ADOBE + + + /************************************************************************** + * + * @property: + * hinting-engine + * + * @description: + * Thanks to Adobe, which contributed a new hinting (and parsing) engine, + * an application can select between 'freetype' and 'adobe' if compiled + * with `CFF_CONFIG_OPTION_OLD_ENGINE`. If this configuration macro + * isn't defined, 'hinting-engine' does nothing. + * + * The same holds for the Type~1 and CID modules if compiled with + * `T1_CONFIG_OPTION_OLD_ENGINE`. + * + * For the 'cff' module, the default engine is 'adobe'. For both the + * 'type1' and 't1cid' modules, the default engine is 'adobe', too. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 'adobe' or 'freetype'). + * + * @example: + * The following example code demonstrates how to select Adobe's hinting + * engine for the 'cff' module (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_UInt hinting_engine = FT_HINTING_ADOBE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "cff", + * "hinting-engine", &hinting_engine ); + * ``` + * + * @since: + * 2.4.12 (for 'cff' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * no-stem-darkening + * + * @description: + * All glyphs that pass through the auto-hinter will be emboldened unless + * this property is set to TRUE. The same is true for the CFF, Type~1, + * and CID font modules if the 'Adobe' engine is selected (which is the + * default). + * + * Stem darkening emboldens glyphs at smaller sizes to make them more + * readable on common low-DPI screens when using linear alpha blending + * and gamma correction, see @FT_Render_Glyph. When not using linear + * alpha blending and gamma correction, glyphs will appear heavy and + * fuzzy! + * + * Gamma correction essentially lightens fonts since shades of grey are + * shifted to higher pixel values (=~higher brightness) to match the + * original intention to the reality of our screens. The side-effect is + * that glyphs 'thin out'. Mac OS~X and Adobe's proprietary font + * rendering library implement a counter-measure: stem darkening at + * smaller sizes where shades of gray dominate. By emboldening a glyph + * slightly in relation to its pixel size, individual pixels get higher + * coverage of filled-in outlines and are therefore 'blacker'. This + * counteracts the 'thinning out' of glyphs, making text remain readable + * at smaller sizes. + * + * For the auto-hinter, stem-darkening is experimental currently and thus + * switched off by default (that is, `no-stem-darkening` is set to TRUE + * by default). Total consistency with the CFF driver is not achieved + * right now because the emboldening method differs and glyphs must be + * scaled down on the Y-axis to keep outline points inside their + * precomputed blue zones. The smaller the size (especially 9ppem and + * down), the higher the loss of emboldening versus the CFF driver. + * + * Note that stem darkening is never applied if @FT_LOAD_NO_SCALE is set. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 1 and 0 for 'on' and 'off', respectively). It + * can also be set per face using @FT_Face_Properties with + * @FT_PARAM_TAG_STEM_DARKENING. + * + * @example: + * ``` + * FT_Library library; + * FT_Bool no_stem_darkening = TRUE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "cff", + * "no-stem-darkening", &no_stem_darkening ); + * ``` + * + * @since: + * 2.4.12 (for 'cff' module) + * + * 2.6.2 (for 'autofitter' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * darkening-parameters + * + * @description: + * By default, the Adobe hinting engine, as used by the CFF, Type~1, and + * CID font drivers, darkens stems as follows (if the `no-stem-darkening` + * property isn't set): + * + * ``` + * stem width <= 0.5px: darkening amount = 0.4px + * stem width = 1px: darkening amount = 0.275px + * stem width = 1.667px: darkening amount = 0.275px + * stem width >= 2.333px: darkening amount = 0px + * ``` + * + * and piecewise linear in-between. At configuration time, these four + * control points can be set with the macro + * `CFF_CONFIG_OPTION_DARKENING_PARAMETERS`; the CFF, Type~1, and CID + * drivers share these values. At runtime, the control points can be + * changed using the `darkening-parameters` property (see the example + * below that demonstrates this for the Type~1 driver). + * + * The x~values give the stem width, and the y~values the darkening + * amount. The unit is 1000th of pixels. All coordinate values must be + * positive; the x~values must be monotonically increasing; the y~values + * must be monotonically decreasing and smaller than or equal to 500 + * (corresponding to half a pixel); the slope of each linear piece must + * be shallower than -1 (e.g., -.4). + * + * The auto-hinter provides this property, too, as an experimental + * feature. See @no-stem-darkening for more. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable, using eight comma-separated integers without spaces. Here + * the above example, using `\` to break the line for readability. + * + * ``` + * FREETYPE_PROPERTIES=\ + * type1:darkening-parameters=500,300,1000,200,1500,100,2000,0 + * ``` + * + * @example: + * ``` + * FT_Library library; + * FT_Int darken_params[8] = { 500, 300, // x1, y1 + * 1000, 200, // x2, y2 + * 1500, 100, // x3, y3 + * 2000, 0 }; // x4, y4 + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "type1", + * "darkening-parameters", darken_params ); + * ``` + * + * @since: + * 2.5.1 (for 'cff' module) + * + * 2.6.2 (for 'autofitter' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * random-seed + * + * @description: + * By default, the seed value for the CFF 'random' operator and the + * similar '0 28 callothersubr pop' command for the Type~1 and CID + * drivers is set to a random value. However, mainly for debugging + * purposes, it is often necessary to use a known value as a seed so that + * the pseudo-random number sequences generated by 'random' are + * repeatable. + * + * The `random-seed` property does that. Its argument is a signed 32bit + * integer; if the value is zero or negative, the seed given by the + * `intitialRandomSeed` private DICT operator in a CFF file gets used (or + * a default value if there is no such operator). If the value is + * positive, use it instead of `initialRandomSeed`, which is consequently + * ignored. + * + * @note: + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable. It can also be set per face using @FT_Face_Properties with + * @FT_PARAM_TAG_RANDOM_SEED. + * + * @since: + * 2.8 (for 'cff' module) + * + * 2.9 (for 'type1' and 't1cid' modules) + * + */ + + + /************************************************************************** + * + * @property: + * no-long-family-names + * + * @description: + * If `PCF_CONFIG_OPTION_LONG_FAMILY_NAMES` is active while compiling + * FreeType, the PCF driver constructs long family names. + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When + * selecting 'Fixed' in KDE or Gnome one gets results that appear rather + * random, the style changes often if one changes the size and one cannot + * select some fonts at all. The improve this situation, the PCF module + * prepends the foundry name (plus a space) to the family name. It also + * checks whether there are 'wide' characters; all put together, family + * names like 'Sony Fixed' or 'Misc Fixed Wide' are constructed. + * + * If `no-long-family-names` is set, this feature gets switched off. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values 1 and 0 for 'on' and 'off', respectively). + * + * @example: + * ``` + * FT_Library library; + * FT_Bool no_long_family_names = TRUE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "pcf", + * "no-long-family-names", + * &no_long_family_names ); + * ``` + * + * @since: + * 2.8 + */ + + + /************************************************************************** + * + * @enum: + * TT_INTERPRETER_VERSION_XXX + * + * @description: + * A list of constants used for the @interpreter-version property to + * select the hinting engine for Truetype fonts. + * + * The numeric value in the constant names represents the version number + * as returned by the 'GETINFO' bytecode instruction. + * + * @values: + * TT_INTERPRETER_VERSION_35 :: + * Version~35 corresponds to MS rasterizer v.1.7 as used e.g. in + * Windows~98; only grayscale and B/W rasterizing is supported. + * + * TT_INTERPRETER_VERSION_38 :: + * Version~38 is the same Version~40. The original 'Infinality' code is + * no longer available. + * + * TT_INTERPRETER_VERSION_40 :: + * Version~40 corresponds to MS rasterizer v.2.1; it is roughly + * equivalent to the hinting provided by DirectWrite ClearType (as can + * be found, for example, in Microsoft's Edge Browser on Windows~10). + * It is used in FreeType to select the 'minimal' subpixel hinting + * code, a stripped-down and higher performance version of the + * 'Infinality' code. + * + * @note: + * This property controls the behaviour of the bytecode interpreter and + * thus how outlines get hinted. It does **not** control how glyph get + * rasterized! In particular, it does not control subpixel color + * filtering. + * + * If FreeType has not been compiled with the configuration option + * `TT_CONFIG_OPTION_SUBPIXEL_HINTING`, selecting version~38 or~40 causes + * an `FT_Err_Unimplemented_Feature` error. + * + * Depending on the graphics framework, Microsoft uses different bytecode + * and rendering engines. As a consequence, the version numbers returned + * by a call to the 'GETINFO' bytecode instruction are more convoluted + * than desired. + * + * Here are two tables that try to shed some light on the possible values + * for the MS rasterizer engine, together with the additional features + * introduced by it. + * + * ``` + * GETINFO framework version feature + * ------------------------------------------------------------------- + * 3 GDI (Win 3.1), v1.0 16-bit, first version + * TrueImage + * 33 GDI (Win NT 3.1), v1.5 32-bit + * HP Laserjet + * 34 GDI (Win 95) v1.6 font smoothing, + * new SCANTYPE opcode + * 35 GDI (Win 98/2000) v1.7 (UN)SCALED_COMPONENT_OFFSET + * bits in composite glyphs + * 36 MGDI (Win CE 2) v1.6+ classic ClearType + * 37 GDI (XP and later), v1.8 ClearType + * GDI+ old (before Vista) + * 38 GDI+ old (Vista, Win 7), v1.9 subpixel ClearType, + * WPF Y-direction ClearType, + * additional error checking + * 39 DWrite (before Win 8) v2.0 subpixel ClearType flags + * in GETINFO opcode, + * bug fixes + * 40 GDI+ (after Win 7), v2.1 Y-direction ClearType flag + * DWrite (Win 8) in GETINFO opcode, + * Gray ClearType + * ``` + * + * The 'version' field gives a rough orientation only, since some + * applications provided certain features much earlier (as an example, + * Microsoft Reader used subpixel and Y-direction ClearType already in + * Windows 2000). Similarly, updates to a given framework might include + * improved hinting support. + * + * ``` + * version sampling rendering comment + * x y x y + * -------------------------------------------------------------- + * v1.0 normal normal B/W B/W bi-level + * v1.6 high high gray gray grayscale + * v1.8 high normal color-filter B/W (GDI) ClearType + * v1.9 high high color-filter gray Color ClearType + * v2.1 high normal gray B/W Gray ClearType + * v2.1 high high gray gray Gray ClearType + * ``` + * + * Color and Gray ClearType are the two available variants of + * 'Y-direction ClearType', meaning grayscale rasterization along the + * Y-direction; the name used in the TrueType specification for this + * feature is 'symmetric smoothing'. 'Classic ClearType' is the original + * algorithm used before introducing a modified version in Win~XP. + * Another name for v1.6's grayscale rendering is 'font smoothing', and + * 'Color ClearType' is sometimes also called 'DWrite ClearType'. To + * differentiate between today's Color ClearType and the earlier + * ClearType variant with B/W rendering along the vertical axis, the + * latter is sometimes called 'GDI ClearType'. + * + * 'Normal' and 'high' sampling describe the (virtual) resolution to + * access the rasterized outline after the hinting process. 'Normal' + * means 1 sample per grid line (i.e., B/W). In the current Microsoft + * implementation, 'high' means an extra virtual resolution of 16x16 (or + * 16x1) grid lines per pixel for bytecode instructions like 'MIRP'. + * After hinting, these 16 grid lines are mapped to 6x5 (or 6x1) grid + * lines for color filtering if Color ClearType is activated. + * + * Note that 'Gray ClearType' is essentially the same as v1.6's grayscale + * rendering. However, the GETINFO instruction handles it differently: + * v1.6 returns bit~12 (hinting for grayscale), while v2.1 returns + * bits~13 (hinting for ClearType), 18 (symmetrical smoothing), and~19 + * (Gray ClearType). Also, this mode respects bits 2 and~3 for the + * version~1 gasp table exclusively (like Color ClearType), while v1.6 + * only respects the values of version~0 (bits 0 and~1). + * + * Keep in mind that the features of the above interpreter versions might + * not map exactly to FreeType features or behavior because it is a + * fundamentally different library with different internals. + * + */ +#define TT_INTERPRETER_VERSION_35 35 +#define TT_INTERPRETER_VERSION_38 38 +#define TT_INTERPRETER_VERSION_40 40 + + + /************************************************************************** + * + * @property: + * interpreter-version + * + * @description: + * Currently, three versions are available, two representing the bytecode + * interpreter with subpixel hinting support (old 'Infinality' code and + * new stripped-down and higher performance 'minimal' code) and one + * without, respectively. The default is subpixel support if + * `TT_CONFIG_OPTION_SUBPIXEL_HINTING` is defined, and no subpixel + * support otherwise (since it isn't available then). + * + * If subpixel hinting is on, many TrueType bytecode instructions behave + * differently compared to B/W or grayscale rendering (except if 'native + * ClearType' is selected by the font). Microsoft's main idea is to + * render at a much increased horizontal resolution, then sampling down + * the created output to subpixel precision. However, many older fonts + * are not suited to this and must be specially taken care of by applying + * (hardcoded) tweaks in Microsoft's interpreter. + * + * Details on subpixel hinting and some of the necessary tweaks can be + * found in Greg Hitchcock's whitepaper at + * 'https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'. + * Note that FreeType currently doesn't really 'subpixel hint' (6x1, 6x2, + * or 6x5 supersampling) like discussed in the paper. Depending on the + * chosen interpreter, it simply ignores instructions on vertical stems + * to arrive at very similar results. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * This property can be set via the `FREETYPE_PROPERTIES` environment + * variable (using values '35', '38', or '40'). + * + * @example: + * The following example code demonstrates how to deactivate subpixel + * hinting (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_Face face; + * FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "truetype", + * "interpreter-version", + * &interpreter_version ); + * ``` + * + * @since: + * 2.5 + */ + + + /************************************************************************** + * + * @property: + * spread + * + * @description: + * This property of the 'sdf' and 'bsdf' renderers defines how the signed + * distance field (SDF) is represented in the output bitmap. The output + * values are calculated as follows, '128 * ( SDF / spread + 1 )', with + * the result clamped to the 8-bit range [0..255]. Therefore, 'spread' + * is also the maximum euclidean distance from the edge after which the + * values are clamped. The spread is specified in pixels with the + * default value of 8. For accurate SDF texture mapping (interpolation), + * the spread should be large enough to accommodate the target grid unit. + * + * @example: + * The following example code demonstrates how to set the SDF spread + * (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_Int spread = 2; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "sdf", "spread", &spread ); + * ``` + * + * @note: + * FreeType has two rasterizers for generating SDF, namely: + * + * 1. `sdf` for generating SDF directly from glyph's outline, and + * + * 2. `bsdf` for generating SDF from rasterized bitmaps. + * + * Depending on the glyph type (i.e., outline or bitmap), one of the two + * rasterizers is chosen at runtime and used for generating SDFs. To + * force the use of `bsdf` you should render the glyph with any of the + * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and + * then re-render with `FT_RENDER_MODE_SDF`. + * + * There are some issues with stability and possible failures of the SDF + * renderers (specifically `sdf`). + * + * 1. The `sdf` rasterizer is sensitive to really small features (e.g., + * sharp turns that are less than 1~pixel) and imperfections in the + * glyph's outline, causing artifacts in the final output. + * + * 2. The `sdf` rasterizer has limited support for handling intersecting + * contours and *cannot* handle self-intersecting contours whatsoever. + * Self-intersection happens when a single connected contour + * intersects itself at some point; having these in your font + * definitely poses a problem to the rasterizer and cause artifacts, + * too. + * + * 3. Generating SDF for really small glyphs may result in undesirable + * output; the pixel grid (which stores distance information) becomes + * too coarse. + * + * 4. Since the output buffer is normalized, precision at smaller spreads + * is greater than precision at larger spread values because the + * output range of [0..255] gets mapped to a smaller SDF range. A + * spread of~2 should be sufficient in most cases. + * + * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, + * which is more stable than the `sdf` rasterizer in general. + * + * @since: + * 2.11 + */ + + + /************************************************************************** + * + * @property: + * svg-hooks + * + * @description: + * Set up the interface between FreeType and an extern SVG rendering + * library like 'librsvg'. All details on the function hooks can be + * found in section @svg_fonts. + * + * @example: + * The following example code expects that the four hook functions + * `svg_*` are defined elsewhere. Error handling is omitted, too. + * + * ``` + * FT_Library library; + * SVG_RendererHooks hooks = { + * (SVG_Lib_Init_Func)svg_init, + * (SVG_Lib_Free_Func)svg_free, + * (SVG_Lib_Render_Func)svg_render, + * (SVG_Lib_Preset_Slot_Func)svg_preset_slot }; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "ot-svg", + * "svg-hooks", &hooks ); + * ``` + * + * @since: + * 2.12 + */ + + + /************************************************************************** + * + * @property: + * glyph-to-script-map + * + * @description: + * **Experimental only** + * + * The auto-hinter provides various script modules to hint glyphs. + * Examples of supported scripts are Latin or CJK. Before a glyph is + * auto-hinted, the Unicode character map of the font gets examined, and + * the script is then determined based on Unicode character ranges, see + * below. + * + * OpenType fonts, however, often provide much more glyphs than character + * codes (small caps, superscripts, ligatures, swashes, etc.), to be + * controlled by so-called 'features'. Handling OpenType features can be + * quite complicated and thus needs a separate library on top of + * FreeType. + * + * The mapping between glyph indices and scripts (in the auto-hinter + * sense, see the @FT_AUTOHINTER_SCRIPT_XXX values) is stored as an array + * with `num_glyphs` elements, as found in the font's @FT_Face structure. + * The `glyph-to-script-map` property returns a pointer to this array, + * which can be modified as needed. Note that the modification should + * happen before the first glyph gets processed by the auto-hinter so + * that the global analysis of the font shapes actually uses the modified + * mapping. + * + * @example: + * The following example code demonstrates how to access it (omitting the + * error handling). + * + * ``` + * FT_Library library; + * FT_Face face; + * FT_Prop_GlyphToScriptMap prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * + * prop.face = face; + * + * FT_Property_Get( library, "autofitter", + * "glyph-to-script-map", &prop ); + * + * // adjust `prop.map' as needed right here + * + * FT_Load_Glyph( face, ..., FT_LOAD_FORCE_AUTOHINT ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @enum: + * FT_AUTOHINTER_SCRIPT_XXX + * + * @description: + * **Experimental only** + * + * A list of constants used for the @glyph-to-script-map property to + * specify the script submodule the auto-hinter should use for hinting a + * particular glyph. + * + * @values: + * FT_AUTOHINTER_SCRIPT_NONE :: + * Don't auto-hint this glyph. + * + * FT_AUTOHINTER_SCRIPT_LATIN :: + * Apply the latin auto-hinter. For the auto-hinter, 'latin' is a very + * broad term, including Cyrillic and Greek also since characters from + * those scripts share the same design constraints. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+0020 - U+007F // Basic Latin (no control characters) + * U+00A0 - U+00FF // Latin-1 Supplement (no control characters) + * U+0100 - U+017F // Latin Extended-A + * U+0180 - U+024F // Latin Extended-B + * U+0250 - U+02AF // IPA Extensions + * U+02B0 - U+02FF // Spacing Modifier Letters + * U+0300 - U+036F // Combining Diacritical Marks + * U+0370 - U+03FF // Greek and Coptic + * U+0400 - U+04FF // Cyrillic + * U+0500 - U+052F // Cyrillic Supplement + * U+1D00 - U+1D7F // Phonetic Extensions + * U+1D80 - U+1DBF // Phonetic Extensions Supplement + * U+1DC0 - U+1DFF // Combining Diacritical Marks Supplement + * U+1E00 - U+1EFF // Latin Extended Additional + * U+1F00 - U+1FFF // Greek Extended + * U+2000 - U+206F // General Punctuation + * U+2070 - U+209F // Superscripts and Subscripts + * U+20A0 - U+20CF // Currency Symbols + * U+2150 - U+218F // Number Forms + * U+2460 - U+24FF // Enclosed Alphanumerics + * U+2C60 - U+2C7F // Latin Extended-C + * U+2DE0 - U+2DFF // Cyrillic Extended-A + * U+2E00 - U+2E7F // Supplemental Punctuation + * U+A640 - U+A69F // Cyrillic Extended-B + * U+A720 - U+A7FF // Latin Extended-D + * U+FB00 - U+FB06 // Alphab. Present. Forms (Latin Ligatures) + * U+1D400 - U+1D7FF // Mathematical Alphanumeric Symbols + * U+1F100 - U+1F1FF // Enclosed Alphanumeric Supplement + * ``` + * + * FT_AUTOHINTER_SCRIPT_CJK :: + * Apply the CJK auto-hinter, covering Chinese, Japanese, Korean, old + * Vietnamese, and some other scripts. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+1100 - U+11FF // Hangul Jamo + * U+2E80 - U+2EFF // CJK Radicals Supplement + * U+2F00 - U+2FDF // Kangxi Radicals + * U+2FF0 - U+2FFF // Ideographic Description Characters + * U+3000 - U+303F // CJK Symbols and Punctuation + * U+3040 - U+309F // Hiragana + * U+30A0 - U+30FF // Katakana + * U+3100 - U+312F // Bopomofo + * U+3130 - U+318F // Hangul Compatibility Jamo + * U+3190 - U+319F // Kanbun + * U+31A0 - U+31BF // Bopomofo Extended + * U+31C0 - U+31EF // CJK Strokes + * U+31F0 - U+31FF // Katakana Phonetic Extensions + * U+3200 - U+32FF // Enclosed CJK Letters and Months + * U+3300 - U+33FF // CJK Compatibility + * U+3400 - U+4DBF // CJK Unified Ideographs Extension A + * U+4DC0 - U+4DFF // Yijing Hexagram Symbols + * U+4E00 - U+9FFF // CJK Unified Ideographs + * U+A960 - U+A97F // Hangul Jamo Extended-A + * U+AC00 - U+D7AF // Hangul Syllables + * U+D7B0 - U+D7FF // Hangul Jamo Extended-B + * U+F900 - U+FAFF // CJK Compatibility Ideographs + * U+FE10 - U+FE1F // Vertical forms + * U+FE30 - U+FE4F // CJK Compatibility Forms + * U+FF00 - U+FFEF // Halfwidth and Fullwidth Forms + * U+1B000 - U+1B0FF // Kana Supplement + * U+1D300 - U+1D35F // Tai Xuan Hing Symbols + * U+1F200 - U+1F2FF // Enclosed Ideographic Supplement + * U+20000 - U+2A6DF // CJK Unified Ideographs Extension B + * U+2A700 - U+2B73F // CJK Unified Ideographs Extension C + * U+2B740 - U+2B81F // CJK Unified Ideographs Extension D + * U+2F800 - U+2FA1F // CJK Compatibility Ideographs Supplement + * ``` + * + * FT_AUTOHINTER_SCRIPT_INDIC :: + * Apply the indic auto-hinter, covering all major scripts from the + * Indian sub-continent and some other related scripts like Thai, Lao, + * or Tibetan. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * ``` + * U+0900 - U+0DFF // Indic Range + * U+0F00 - U+0FFF // Tibetan + * U+1900 - U+194F // Limbu + * U+1B80 - U+1BBF // Sundanese + * U+A800 - U+A82F // Syloti Nagri + * U+ABC0 - U+ABFF // Meetei Mayek + * U+11800 - U+118DF // Sharada + * ``` + * + * Note that currently Indic support is rudimentary only, missing blue + * zone support. + * + * @since: + * 2.4.11 + * + */ +#define FT_AUTOHINTER_SCRIPT_NONE 0 +#define FT_AUTOHINTER_SCRIPT_LATIN 1 +#define FT_AUTOHINTER_SCRIPT_CJK 2 +#define FT_AUTOHINTER_SCRIPT_INDIC 3 + + + /************************************************************************** + * + * @struct: + * FT_Prop_GlyphToScriptMap + * + * @description: + * **Experimental only** + * + * The data exchange structure for the @glyph-to-script-map property. + * + * @since: + * 2.4.11 + * + */ + typedef struct FT_Prop_GlyphToScriptMap_ + { + FT_Face face; + FT_UShort* map; + + } FT_Prop_GlyphToScriptMap; + + + /************************************************************************** + * + * @property: + * fallback-script + * + * @description: + * **Experimental only** + * + * If no auto-hinter script module can be assigned to a glyph, a fallback + * script gets assigned to it (see also the @glyph-to-script-map + * property). By default, this is @FT_AUTOHINTER_SCRIPT_CJK. Using the + * `fallback-script` property, this fallback value can be changed. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * It's important to use the right timing for changing this value: The + * creation of the glyph-to-script map that eventually uses the fallback + * script value gets triggered either by setting or reading a + * face-specific property like @glyph-to-script-map, or by auto-hinting + * any glyph from that face. In particular, if you have already created + * an @FT_Face structure but not loaded any glyph (using the + * auto-hinter), a change of the fallback script will affect this face. + * + * @example: + * ``` + * FT_Library library; + * FT_UInt fallback_script = FT_AUTOHINTER_SCRIPT_NONE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "autofitter", + * "fallback-script", &fallback_script ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @property: + * default-script + * + * @description: + * **Experimental only** + * + * If FreeType gets compiled with `FT_CONFIG_OPTION_USE_HARFBUZZ` to make + * the HarfBuzz library access OpenType features for getting better glyph + * coverages, this property sets the (auto-fitter) script to be used for + * the default (OpenType) script data of a font's GSUB table. Features + * for the default script are intended for all scripts not explicitly + * handled in GSUB; an example is a 'dlig' feature, containing the + * combination of the characters 'T', 'E', and 'L' to form a 'TEL' + * ligature. + * + * By default, this is @FT_AUTOHINTER_SCRIPT_LATIN. Using the + * `default-script` property, this default value can be changed. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * It's important to use the right timing for changing this value: The + * creation of the glyph-to-script map that eventually uses the default + * script value gets triggered either by setting or reading a + * face-specific property like @glyph-to-script-map, or by auto-hinting + * any glyph from that face. In particular, if you have already created + * an @FT_Face structure but not loaded any glyph (using the + * auto-hinter), a change of the default script will affect this face. + * + * @example: + * ``` + * FT_Library library; + * FT_UInt default_script = FT_AUTOHINTER_SCRIPT_NONE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "autofitter", + * "default-script", &default_script ); + * ``` + * + * @since: + * 2.5.3 + * + */ + + + /************************************************************************** + * + * @property: + * increase-x-height + * + * @description: + * For ppem values in the range 6~<= ppem <= `increase-x-height`, round + * up the font's x~height much more often than normally. If the value is + * set to~0, which is the default, this feature is switched off. Use + * this property to improve the legibility of small font sizes if + * necessary. + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * Set this value right after calling @FT_Set_Char_Size, but before + * loading any glyph (using the auto-hinter). + * + * @example: + * ``` + * FT_Library library; + * FT_Face face; + * FT_Prop_IncreaseXHeight prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * FT_Set_Char_Size( face, 10 * 64, 0, 72, 0 ); + * + * prop.face = face; + * prop.limit = 14; + * + * FT_Property_Set( library, "autofitter", + * "increase-x-height", &prop ); + * ``` + * + * @since: + * 2.4.11 + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Prop_IncreaseXHeight + * + * @description: + * The data exchange structure for the @increase-x-height property. + * + */ + typedef struct FT_Prop_IncreaseXHeight_ + { + FT_Face face; + FT_UInt limit; + + } FT_Prop_IncreaseXHeight; + + + /************************************************************************** + * + * @property: + * warping + * + * @description: + * **Obsolete** + * + * This property was always experimental and probably never worked + * correctly. It was entirely removed from the FreeType~2 sources. This + * entry is only here for historical reference. + * + * Warping only worked in 'normal' auto-hinting mode replacing it. The + * idea of the code was to slightly scale and shift a glyph along the + * non-hinted dimension (which is usually the horizontal axis) so that as + * much of its segments were aligned (more or less) to the grid. To find + * out a glyph's optimal scaling and shifting value, various parameter + * combinations were tried and scored. + * + * @since: + * 2.6 + * + */ + + + /* */ + + +FT_END_HEADER + + +#endif /* FTDRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/fterrdef.h b/Dependencies/freetype/freetype/include/freetype/fterrdef.h new file mode 100644 index 00000000..710ca91b --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/fterrdef.h @@ -0,0 +1,283 @@ +/**************************************************************************** + * + * fterrdef.h + * + * FreeType error codes (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * @section: + * error_code_values + * + * @title: + * Error Code Values + * + * @abstract: + * All possible error codes returned by FreeType functions. + * + * @description: + * The list below is taken verbatim from the file `fterrdef.h` (loaded + * automatically by including `FT_FREETYPE_H`). The first argument of the + * `FT_ERROR_DEF_` macro is the error label; by default, the prefix + * `FT_Err_` gets added so that you get error names like + * `FT_Err_Cannot_Open_Resource`. The second argument is the error code, + * and the last argument an error string, which is not used by FreeType. + * + * Within your application you should **only** use error names and + * **never** its numeric values! The latter might (and actually do) + * change in forthcoming FreeType versions. + * + * Macro `FT_NOERRORDEF_` defines `FT_Err_Ok`, which is always zero. See + * the 'Error Enumerations' subsection how to automatically generate a + * list of error strings. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_Err_XXX + * + */ + + /* generic errors */ + + FT_NOERRORDEF_( Ok, 0x00, + "no error" ) + + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, + "missing property" ) + + /* glyph/character errors */ + + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, + "invalid pixel size" ) + FT_ERRORDEF_( Invalid_SVG_Document, 0x18, + "invalid SVG document" ) + + /* handle errors */ + + FT_ERRORDEF_( Invalid_Handle, 0x20, + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, + "invalid stream handle" ) + + /* driver errors */ + + FT_ERRORDEF_( Too_Many_Drivers, 0x30, + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, + "too many extensions" ) + + /* memory errors */ + + FT_ERRORDEF_( Out_Of_Memory, 0x40, + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, + "unlisted object" ) + + /* stream errors */ + + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, + "invalid frame read" ) + + /* raster errors */ + + FT_ERRORDEF_( Raster_Uninitialized, 0x60, + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, + "negative height while rastering" ) + + /* cache errors */ + + FT_ERRORDEF_( Too_Many_Caches, 0x70, + "too many registered caches" ) + + /* TrueType and SFNT errors */ + + FT_ERRORDEF_( Invalid_Opcode, 0x80, + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, + "invalid PostScript (post) table" ) + FT_ERRORDEF_( DEF_In_Glyf_Bytecode, 0x9C, + "found FDEF or IDEF opcode in glyf bytecode" ) + FT_ERRORDEF_( Missing_Bitmap, 0x9D, + "missing bitmap in strike" ) + FT_ERRORDEF_( Missing_SVG_Hooks, 0x9E, + "SVG hooks have not been set" ) + + /* CFF, CID, and Type 1 errors */ + + FT_ERRORDEF_( Syntax_Error, 0xA0, + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, + "no Unicode glyph name found" ) + FT_ERRORDEF_( Glyph_Too_Big, 0xA4, + "glyph too big for hinting" ) + + /* BDF errors */ + + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, + "Font glyphs corrupted or missing fields" ) + + /* */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/fterrors.h b/Dependencies/freetype/freetype/include/freetype/fterrors.h new file mode 100644 index 00000000..27c0ece5 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/fterrors.h @@ -0,0 +1,296 @@ +/**************************************************************************** + * + * fterrors.h + * + * FreeType error code handling (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * @section: + * error_enumerations + * + * @title: + * Error Enumerations + * + * @abstract: + * How to handle errors and error strings. + * + * @description: + * The header file `fterrors.h` (which is automatically included by + * `freetype.h`) defines the handling of FreeType's enumeration + * constants. It can also be used to generate error message strings + * with a small macro trick explained below. + * + * **Error Formats** + * + * The configuration macro `FT_CONFIG_OPTION_USE_MODULE_ERRORS` can be + * defined in `ftoption.h` in order to make the higher byte indicate the + * module where the error has happened (this is not compatible with + * standard builds of FreeType~2, however). See the file `ftmoderr.h` + * for more details. + * + * **Error Message Strings** + * + * Error definitions are set up with special macros that allow client + * applications to build a table of error message strings. The strings + * are not included in a normal build of FreeType~2 to save space (most + * client applications do not use them). + * + * To do so, you have to define the following macros before including + * this file. + * + * ``` + * FT_ERROR_START_LIST + * ``` + * + * This macro is called before anything else to define the start of the + * error list. It is followed by several `FT_ERROR_DEF` calls. + * + * ``` + * FT_ERROR_DEF( e, v, s ) + * ``` + * + * This macro is called to define one single error. 'e' is the error + * code identifier (e.g., `Invalid_Argument`), 'v' is the error's + * numerical value, and 's' is the corresponding error string. + * + * ``` + * FT_ERROR_END_LIST + * ``` + * + * This macro ends the list. + * + * Additionally, you have to undefine `FTERRORS_H_` before #including + * this file. + * + * Here is a simple example. + * + * ``` + * #undef FTERRORS_H_ + * #define FT_ERRORDEF( e, v, s ) { e, s }, + * #define FT_ERROR_START_LIST { + * #define FT_ERROR_END_LIST { 0, NULL } }; + * + * const struct + * { + * int err_code; + * const char* err_msg; + * } ft_errors[] = + * + * #include + * ``` + * + * An alternative to using an array is a switch statement. + * + * ``` + * #undef FTERRORS_H_ + * #define FT_ERROR_START_LIST switch ( error_code ) { + * #define FT_ERRORDEF( e, v, s ) case v: return s; + * #define FT_ERROR_END_LIST } + * ``` + * + * If you use `FT_CONFIG_OPTION_USE_MODULE_ERRORS`, `error_code` should + * be replaced with `FT_ERROR_BASE(error_code)` in the last example. + */ + + /* */ + + /* In previous FreeType versions we used `__FTERRORS_H__`. However, */ + /* using two successive underscores in a non-system symbol name */ + /* violates the C (and C++) standard, so it was changed to the */ + /* current form. In spite of this, we have to make */ + /* */ + /* ``` */ + /* #undefine __FTERRORS_H__ */ + /* ``` */ + /* */ + /* work for backward compatibility. */ + /* */ +#if !( defined( FTERRORS_H_ ) && defined ( __FTERRORS_H__ ) ) +#define FTERRORS_H_ +#define __FTERRORS_H__ + + + /* include module base error codes */ +#include + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + + + /* FT_ERR_PREFIX is used as a prefix for error identifiers. */ + /* By default, we use `FT_Err_`. */ + /* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif + + + /* FT_ERR_BASE is used as the base for module-specific errors. */ + /* */ +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +#ifndef FT_ERR_BASE +#define FT_ERR_BASE FT_Mod_Err_Base +#endif + +#else + +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 + +#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */ + + + /* If FT_ERRORDEF is not defined, we need to define a simple */ + /* enumeration type. */ + /* */ +#ifndef FT_ERRORDEF + +#define FT_INCLUDE_ERR_PROTOS + +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_ERRORDEF */ + + + /* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) + + /* this is only used for _Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) + + +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif + + + /* now include the error codes */ +#include + + +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SIMPLE CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST + +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ + +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE + + /* FT_ERR_PREFIX is needed internally */ +#ifndef FT2_BUILD_LIBRARY +#undef FT_ERR_PREFIX +#endif + + /* FT_INCLUDE_ERR_PROTOS: Control whether function prototypes should be */ + /* included with */ + /* */ + /* #include */ + /* */ + /* This is only true where `FT_ERRORDEF` is */ + /* undefined. */ + /* */ + /* FT_ERR_PROTOS_DEFINED: Actual multiple-inclusion protection of */ + /* `fterrors.h`. */ +#ifdef FT_INCLUDE_ERR_PROTOS +#undef FT_INCLUDE_ERR_PROTOS + +#ifndef FT_ERR_PROTOS_DEFINED +#define FT_ERR_PROTOS_DEFINED + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @function: + * FT_Error_String + * + * @description: + * Retrieve the description of a valid FreeType error code. + * + * @input: + * error_code :: + * A valid FreeType error code. + * + * @return: + * A C~string or `NULL`, if any error occurred. + * + * @note: + * FreeType has to be compiled with `FT_CONFIG_OPTION_ERROR_STRINGS` or + * `FT_DEBUG_LEVEL_ERROR` to get meaningful descriptions. + * 'error_string' will be `NULL` otherwise. + * + * Module identification will be ignored: + * + * ```c + * strcmp( FT_Error_String( FT_Err_Unknown_File_Format ), + * FT_Error_String( BDF_Err_Unknown_File_Format ) ) == 0; + * ``` + */ + FT_EXPORT( const char* ) + FT_Error_String( FT_Error error_code ); + + /* */ + +FT_END_HEADER + + +#endif /* FT_ERR_PROTOS_DEFINED */ + +#endif /* FT_INCLUDE_ERR_PROTOS */ + +#endif /* !(FTERRORS_H_ && __FTERRORS_H__) */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftfntfmt.h b/Dependencies/freetype/freetype/include/freetype/ftfntfmt.h new file mode 100644 index 00000000..7c8b0874 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftfntfmt.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * + * ftfntfmt.h + * + * Support functions for font formats. + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTFNTFMT_H_ +#define FTFNTFMT_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * font_formats + * + * @title: + * Font Formats + * + * @abstract: + * Getting the font format. + * + * @description: + * The single function in this section can be used to get the font format. + * Note that this information is not needed normally; however, there are + * special cases (like in PDF devices) where it is important to + * differentiate, in spite of FreeType's uniform API. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_Font_Format + * + * @description: + * Return a string describing the format of a given face. Possible values + * are 'TrueType', 'Type~1', 'BDF', 'PCF', 'Type~42', 'CID~Type~1', 'CFF', + * 'PFR', and 'Windows~FNT'. + * + * The return value is suitable to be used as an X11 FONT_PROPERTY. + * + * @input: + * face :: + * Input face handle. + * + * @return: + * Font format string. `NULL` in case of error. + * + * @note: + * A deprecated name for the same function is `FT_Get_X11_Font_Format`. + */ + FT_EXPORT( const char* ) + FT_Get_Font_Format( FT_Face face ); + + + /* deprecated */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTFNTFMT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftgasp.h b/Dependencies/freetype/freetype/include/freetype/ftgasp.h new file mode 100644 index 00000000..30e5a9bf --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftgasp.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * ftgasp.h + * + * Access of TrueType's 'gasp' table (specification). + * + * Copyright (C) 2007-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGASP_H_ +#define FTGASP_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType 'gasp' table entries. + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in its 'gasp' table, if any. This is mainly + * useful when implementing native TrueType hinting with the bytecode + * interpreter to duplicate the Windows text rendering results. + */ + + /************************************************************************** + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This **really** means TrueType bytecode interpretation. If this bit + * is not set, no hinting gets applied. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * If not set, do monochrome rendering. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * If set, smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * The bit-flags `FT_GASP_DO_GRIDFIT` and `FT_GASP_DO_GRAY` are to be + * used for standard font rasterization only. Independently of that, + * `FT_GASP_SYMMETRIC_SMOOTHING` and `FT_GASP_SYMMETRIC_GRIDFIT` are to + * be used if ClearType is enabled (and `FT_GASP_DO_GRIDFIT` and + * `FT_GASP_DO_GRAY` are consequently ignored). + * + * 'ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x04 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 + + + /************************************************************************** + * + * @function: + * FT_Get_Gasp + * + * @description: + * For a TrueType or OpenType font file, return the rasterizer behaviour + * flags from the font's 'gasp' table corresponding to a given character + * pixel size. + * + * @input: + * face :: + * The source face handle. + * + * ppem :: + * The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE if there is no + * 'gasp' table in the face. + * + * @note: + * If you want to use the MM functionality of OpenType variation fonts + * (i.e., using @FT_Set_Var_Design_Coordinates and friends), call this + * function **after** setting an instance since the return values can + * change. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGASP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftglyph.h b/Dependencies/freetype/freetype/include/freetype/ftglyph.h new file mode 100644 index 00000000..dc1eb887 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftglyph.h @@ -0,0 +1,750 @@ +/**************************************************************************** + * + * ftglyph.h + * + * FreeType convenience functions to handle glyphs (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file contains the definition of several convenience functions that + * can be used by client applications to easily retrieve glyph bitmaps and + * outlines from a given face. + * + * These functions should be optional if you are writing a font server or + * text layout engine on top of FreeType. However, they are pretty handy + * for many other simple uses of the library. + * + */ + + +#ifndef FTGLYPH_H_ +#define FTGLYPH_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * glyph_management + * + * @title: + * Glyph Management + * + * @abstract: + * Generic interface to manage individual glyph data. + * + * @description: + * This section contains definitions used to manage glyph data through + * generic @FT_Glyph objects. Each of them can contain a bitmap, + * a vector outline, or even images in other formats. These objects are + * detached from @FT_Face, contrary to @FT_GlyphSlot. + * + */ + + + /* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; + + + /************************************************************************** + * + * @type: + * FT_Glyph + * + * @description: + * Handle to an object used to model generic glyph images. It is a + * pointer to the @FT_GlyphRec structure and can contain a glyph bitmap + * or pointer. + * + * @note: + * Glyph objects are not owned by the library. You must thus release + * them manually (through @FT_Done_Glyph) _before_ calling + * @FT_Done_FreeType. + */ + typedef struct FT_GlyphRec_* FT_Glyph; + + + /************************************************************************** + * + * @struct: + * FT_GlyphRec + * + * @description: + * The root glyph structure contains a given glyph image plus its advance + * width in 16.16 fixed-point format. + * + * @fields: + * library :: + * A handle to the FreeType library object. + * + * clazz :: + * A pointer to the glyph's class. Private. + * + * format :: + * The format of the glyph's image. + * + * advance :: + * A 16.16 vector that gives the glyph's advance width. + */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + + } FT_GlyphRec; + + + /************************************************************************** + * + * @type: + * FT_BitmapGlyph + * + * @description: + * A handle to an object used to model a bitmap glyph image. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. + */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; + + + /************************************************************************** + * + * @struct: + * FT_BitmapGlyphRec + * + * @description: + * A structure used for bitmap glyph images. This really is a + * 'sub-class' of @FT_GlyphRec. + * + * @fields: + * root :: + * The root fields of @FT_Glyph. + * + * left :: + * The left-side bearing, i.e., the horizontal distance from the + * current pen position to the left border of the glyph bitmap. + * + * top :: + * The top-side bearing, i.e., the vertical distance from the current + * pen position to the top border of the glyph bitmap. This distance + * is positive for upwards~y! + * + * bitmap :: + * A descriptor for the bitmap. + * + * @note: + * You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have + * `glyph->format == FT_GLYPH_FORMAT_BITMAP`. This lets you access the + * bitmap's contents easily. + * + * The corresponding pixel buffer is always owned by @FT_BitmapGlyph and + * is thus created and destroyed with it. + */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + + } FT_BitmapGlyphRec; + + + /************************************************************************** + * + * @type: + * FT_OutlineGlyph + * + * @description: + * A handle to an object used to model an outline glyph image. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. + */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; + + + /************************************************************************** + * + * @struct: + * FT_OutlineGlyphRec + * + * @description: + * A structure used for outline (vectorial) glyph images. This really is + * a 'sub-class' of @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_Glyph fields. + * + * outline :: + * A descriptor for the outline. + * + * @note: + * You can typecast an @FT_Glyph to @FT_OutlineGlyph if you have + * `glyph->format == FT_GLYPH_FORMAT_OUTLINE`. This lets you access the + * outline's content easily. + * + * As the outline is extracted from a glyph slot, its coordinates are + * expressed normally in 26.6 pixels, unless the flag @FT_LOAD_NO_SCALE + * was used in @FT_Load_Glyph or @FT_Load_Char. + * + * The outline's tables are always owned by the object and are destroyed + * with it. + */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + + } FT_OutlineGlyphRec; + + + /************************************************************************** + * + * @type: + * FT_SvgGlyph + * + * @description: + * A handle to an object used to model an SVG glyph. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_SvgGlyphRec. + * + * @since: + * 2.12 + */ + typedef struct FT_SvgGlyphRec_* FT_SvgGlyph; + + + /************************************************************************** + * + * @struct: + * FT_SvgGlyphRec + * + * @description: + * A structure used for OT-SVG glyphs. This is a 'sub-class' of + * @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_GlyphRec fields. + * + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * glyph_index :: + * The index of the glyph to be rendered. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * Translation to apply to the glyph while rendering. + * + * @note: + * The Glyph Management API requires @FT_Glyph or its 'sub-class' to have + * all the information needed to completely define the glyph's rendering. + * Outline-based glyphs can directly apply transformations to the outline + * but this is not possible for an SVG document that hasn't been parsed. + * Therefore, the transformation is stored along with the document. In + * the absence of a 'ViewBox' or 'Width'/'Height' attribute, the size of + * the ViewPort should be assumed to be 'units_per_EM'. + */ + typedef struct FT_SvgGlyphRec_ + { + FT_GlyphRec root; + + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_UInt glyph_index; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SvgGlyphRec; + + + /************************************************************************** + * + * @function: + * FT_New_Glyph + * + * @description: + * A function used to create a new empty glyph image. Note that the + * created @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * library :: + * A handle to the FreeType library object. + * + * format :: + * The format of the glyph's image. + * + * @output: + * aglyph :: + * A handle to the glyph object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_New_Glyph( FT_Library library, + FT_Glyph_Format format, + FT_Glyph *aglyph ); + + + /************************************************************************** + * + * @function: + * FT_Get_Glyph + * + * @description: + * A function used to extract a glyph image from a slot. Note that the + * created @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * slot :: + * A handle to the source glyph slot. + * + * @output: + * aglyph :: + * A handle to the glyph object. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Because `*aglyph->advance.x` and `*aglyph->advance.y` are 16.16 + * fixed-point numbers, `slot->advance.x` and `slot->advance.y` (which + * are in 26.6 fixed-point format) must be in the range ]-32768;32768[. + */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Copy + * + * @description: + * A function used to copy a glyph image. Note that the created + * @FT_Glyph object must be released with @FT_Done_Glyph. + * + * @input: + * source :: + * A handle to the source glyph object. + * + * @output: + * target :: + * A handle to the target glyph object. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Transform + * + * @description: + * Transform a glyph image if its format is scalable. + * + * @inout: + * glyph :: + * A handle to the target glyph object. + * + * @input: + * matrix :: + * A pointer to a 2x2 matrix to apply. + * + * delta :: + * A pointer to a 2d vector to apply. Coordinates are expressed in + * 1/64 of a pixel. + * + * @return: + * FreeType error code (if not 0, the glyph format is not scalable). + * + * @note: + * The 2x2 transformation matrix is also applied to the glyph's advance + * vector. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + /************************************************************************** + * + * @enum: + * FT_Glyph_BBox_Mode + * + * @description: + * The mode how the values of @FT_Glyph_Get_CBox are returned. + * + * @values: + * FT_GLYPH_BBOX_UNSCALED :: + * Return unscaled font units. + * + * FT_GLYPH_BBOX_SUBPIXELS :: + * Return unfitted 26.6 coordinates. + * + * FT_GLYPH_BBOX_GRIDFIT :: + * Return grid-fitted 26.6 coordinates. + * + * FT_GLYPH_BBOX_TRUNCATE :: + * Return coordinates in integer pixels. + * + * FT_GLYPH_BBOX_PIXELS :: + * Return grid-fitted pixel coordinates. + */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + + } FT_Glyph_BBox_Mode; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_BBox_Mode` values instead */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS + + + /************************************************************************** + * + * @function: + * FT_Glyph_Get_CBox + * + * @description: + * Return a glyph's 'control box'. The control box encloses all the + * outline's points, including Bezier control points. Though it + * coincides with the exact bounding box for most glyphs, it can be + * slightly larger in some situations (like when rotating an outline that + * contains Bezier outside arcs). + * + * Computing the control box is very fast, while getting the bounding box + * can take much more time as it needs to walk over all segments and arcs + * in the outline. To get the latter, you can use the 'ftbbox' + * component, which is dedicated to this single task. + * + * @input: + * glyph :: + * A handle to the source glyph object. + * + * mode :: + * The mode that indicates how to interpret the returned bounding box + * values. + * + * @output: + * acbox :: + * The glyph coordinate bounding box. Coordinates are expressed in + * 1/64 of pixels if it is grid-fitted. + * + * @note: + * Coordinates are relative to the glyph origin, using the y~upwards + * convention. + * + * If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode` must + * be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font units in 26.6 + * pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS is another name for + * this constant. + * + * If the font is tricky and the glyph has been loaded with + * @FT_LOAD_NO_SCALE, the resulting CBox is meaningless. To get + * reasonable values for the CBox it is necessary to load the glyph at a + * large ppem value (so that the hinting instructions can properly shift + * and scale the subglyphs), then extracting the CBox, which can be + * eventually converted back to font units. + * + * Note that the maximum coordinates are exclusive, which means that one + * can compute the width and height of the glyph image (be it in integer + * or 26.6 pixels) as: + * + * ``` + * width = bbox.xMax - bbox.xMin; + * height = bbox.yMax - bbox.yMin; + * ``` + * + * Note also that for 26.6 coordinates, if `bbox_mode` is set to + * @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, + * which corresponds to: + * + * ``` + * bbox.xMin = FLOOR(bbox.xMin); + * bbox.yMin = FLOOR(bbox.yMin); + * bbox.xMax = CEILING(bbox.xMax); + * bbox.yMax = CEILING(bbox.yMax); + * ``` + * + * To get the bbox in pixel coordinates, set `bbox_mode` to + * @FT_GLYPH_BBOX_TRUNCATE. + * + * To get the bbox in grid-fitted pixel coordinates, set `bbox_mode` to + * @FT_GLYPH_BBOX_PIXELS. + */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_To_Bitmap + * + * @description: + * Convert a given glyph object to a bitmap glyph object. + * + * @inout: + * the_glyph :: + * A pointer to a handle to the target glyph. + * + * @input: + * render_mode :: + * An enumeration that describes how the data is rendered. + * + * origin :: + * A pointer to a vector used to translate the glyph image before + * rendering. Can be~0 (if no translation). The origin is expressed + * in 26.6 pixels. + * + * destroy :: + * A boolean that indicates that the original glyph image should be + * destroyed by this function. It is never destroyed in case of error. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does nothing if the glyph format isn't scalable. + * + * The glyph image is translated with the `origin` vector before + * rendering. + * + * The first parameter is a pointer to an @FT_Glyph handle that will be + * _replaced_ by this function (with newly allocated data). Typically, + * you would do something like the following (omitting error handling). + * + * ``` + * FT_Glyph glyph; + * FT_BitmapGlyph glyph_bitmap; + * + * + * // load glyph + * error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAULT ); + * + * // extract glyph image + * error = FT_Get_Glyph( face->glyph, &glyph ); + * + * // convert to a bitmap (default render mode + destroying old) + * if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) + * { + * error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, + * 0, 1 ); + * if ( error ) // `glyph' unchanged + * ... + * } + * + * // access bitmap content by typecasting + * glyph_bitmap = (FT_BitmapGlyph)glyph; + * + * // do funny stuff with it, like blitting/drawing + * ... + * + * // discard glyph image (bitmap or not) + * FT_Done_Glyph( glyph ); + * ``` + * + * Here is another example, again without error handling. + * + * ``` + * FT_Glyph glyphs[MAX_GLYPHS] + * + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT ) || + * FT_Get_Glyph ( face->glyph, &glyphs[idx] ); + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * { + * FT_Glyph bitmap = glyphs[idx]; + * + * + * ... + * + * // after this call, `bitmap' no longer points into + * // the `glyphs' array (and the old value isn't destroyed) + * FT_Glyph_To_Bitmap( &bitmap, FT_RENDER_MODE_MONO, 0, 0 ); + * + * ... + * + * FT_Done_Glyph( bitmap ); + * } + * + * ... + * + * for ( idx = 0; i < MAX_GLYPHS; i++ ) + * FT_Done_Glyph( glyphs[idx] ); + * ``` + */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ); + + + /************************************************************************** + * + * @function: + * FT_Done_Glyph + * + * @description: + * Destroy a given glyph. + * + * @input: + * glyph :: + * A handle to the target glyph object. Can be `NULL`. + */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); + + /* */ + + + /* other helpful functions */ + + /************************************************************************** + * + * @section: + * computations + * + */ + + + /************************************************************************** + * + * @function: + * FT_Matrix_Multiply + * + * @description: + * Perform the matrix operation `b = a*b`. + * + * @input: + * a :: + * A pointer to matrix `a`. + * + * @inout: + * b :: + * A pointer to matrix `b`. + * + * @note: + * The result is undefined if either `a` or `b` is zero. + * + * Since the function uses wrap-around arithmetic, results become + * meaningless if the arguments are very large. + */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); + + + /************************************************************************** + * + * @function: + * FT_Matrix_Invert + * + * @description: + * Invert a 2x2 matrix. Return an error if it can't be inverted. + * + * @inout: + * matrix :: + * A pointer to the target matrix. Remains untouched in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGLYPH_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftgxval.h b/Dependencies/freetype/freetype/include/freetype/ftgxval.h new file mode 100644 index 00000000..065cd53c --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftgxval.h @@ -0,0 +1,354 @@ +/**************************************************************************** + * + * ftgxval.h + * + * FreeType API for validating TrueTypeGX/AAT tables (specification). + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO, Redhat K.K, + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef FTGXVAL_H_ +#define FTGXVAL_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * gx_validation + * + * @title: + * TrueTypeGX/AAT Validation + * + * @abstract: + * An API to validate TrueTypeGX/AAT tables. + * + * @description: + * This section contains the declaration of functions to validate some + * TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, trak, + * prop, lcar). + * + * @order: + * FT_TrueTypeGX_Validate + * FT_TrueTypeGX_Free + * + * FT_ClassicKern_Validate + * FT_ClassicKern_Free + * + * FT_VALIDATE_GX_LENGTH + * FT_VALIDATE_GXXXX + * FT_VALIDATE_CKERNXXX + * + */ + + /************************************************************************** + * + * + * Warning: Use `FT_VALIDATE_XXX` to validate a table. + * Following definitions are for gxvalid developers. + * + * + */ + +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX + + + /************************************************************************** + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length` argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH ( FT_VALIDATE_GX_LAST_INDEX + 1 ) + + /* */ + + /* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate 'feat' table. + * + * FT_VALIDATE_mort :: + * Validate 'mort' table. + * + * FT_VALIDATE_morx :: + * Validate 'morx' table. + * + * FT_VALIDATE_bsln :: + * Validate 'bsln' table. + * + * FT_VALIDATE_just :: + * Validate 'just' table. + * + * FT_VALIDATE_kern :: + * Validate 'kern' table. + * + * FT_VALIDATE_opbd :: + * Validate 'opbd' table. + * + * FT_VALIDATE_trak :: + * Validate 'trak' table. + * + * FT_VALIDATE_prop :: + * Validate 'prop' table. + * + * FT_VALIDATE_lcar :: + * Validate 'lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ + +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) + +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) + + + /************************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library that + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables` array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. The array + * itself must be allocated by a client. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables` element, by calling @FT_TrueTypeGX_Free. A `NULL` value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + /************************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate to + * indicate the classic kern dialect or dialects. If the selected type + * doesn't fit, @FT_ClassicKern_Validate regards the table as invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the 'kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the 'kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the 'kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) + +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) + + + /************************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16-bit format) kern table to assure that the + * offsets and indices are valid. The idea is that a higher-level + * library that actually does the text layout can access those tables + * without error checking (which can be quite time consuming). + * + * The 'kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32-bit format and the classic 16-bit format, while + * FT_ClassicKern_Validate only supports the classic 16-bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table`, by calling @FT_ClassicKern_Free. A `NULL` value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); + + + /************************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGXVAL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftgzip.h b/Dependencies/freetype/freetype/include/freetype/ftgzip.h new file mode 100644 index 00000000..9516dc03 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftgzip.h @@ -0,0 +1,151 @@ +/**************************************************************************** + * + * ftgzip.h + * + * Gzip-compressed stream support. + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGZIP_H_ +#define FTGZIP_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * gzip + * + * @title: + * GZIP Streams + * + * @abstract: + * Using gzip-compressed font files. + * + * @description: + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from it + * and re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of Gzip-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is mainly + * used to support the compressed `*.pcf.gz` fonts that come with + * XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); + + + /************************************************************************** + * + * @function: + * FT_Gzip_Uncompress + * + * @description: + * Decompress a zipped input buffer into an output buffer. This function + * is modeled after zlib's `uncompress` function. + * + * @input: + * memory :: + * A FreeType memory handle. + * + * input :: + * The input buffer. + * + * input_len :: + * The length of the input buffer. + * + * @output: + * output :: + * The output buffer. + * + * @inout: + * output_len :: + * Before calling the function, this is the total size of the output + * buffer, which must be large enough to hold the entire uncompressed + * data (so the size of the uncompressed data must be known in + * advance). After calling the function, `output_len` is the size of + * the used data in `output`. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with zlib support. + * + * @since: + * 2.5.1 + */ + FT_EXPORT( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ); + + /* */ + + +FT_END_HEADER + +#endif /* FTGZIP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftimage.h b/Dependencies/freetype/freetype/include/freetype/ftimage.h new file mode 100644 index 00000000..2b4b4ac6 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftimage.h @@ -0,0 +1,1289 @@ +/**************************************************************************** + * + * ftimage.h + * + * FreeType glyph image formats and default raster interface + * (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Note: A 'raster' is simply a scan-line converter, used to render + * `FT_Outline`s into `FT_Bitmap`s. + * + * Note: This file can be used for `STANDALONE_` compilation of raster + * (B/W) and smooth (anti-aliased) renderers. Therefore, it must + * rely on standard variable types only instead of aliases in + * `fttypes.h`. + * + */ + + +#ifndef FTIMAGE_H_ +#define FTIMAGE_H_ + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @type: + * FT_Pos + * + * @description: + * The type FT_Pos is used to store vectorial coordinates. Depending on + * the context, these can represent distances in integer font units, or + * 16.16, or 26.6 fixed-point pixel coordinates. + */ + typedef signed long FT_Pos; + + + /************************************************************************** + * + * @struct: + * FT_Vector + * + * @description: + * A simple structure used to store a 2D vector; coordinates are of the + * FT_Pos type. + * + * @fields: + * x :: + * The horizontal coordinate. + * y :: + * The vertical coordinate. + */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + + } FT_Vector; + + + /************************************************************************** + * + * @struct: + * FT_BBox + * + * @description: + * A structure used to hold an outline's bounding box, i.e., the + * coordinates of its extrema in the horizontal and vertical directions. + * + * @fields: + * xMin :: + * The horizontal minimum (left-most). + * + * yMin :: + * The vertical minimum (bottom-most). + * + * xMax :: + * The horizontal maximum (right-most). + * + * yMax :: + * The vertical maximum (top-most). + * + * @note: + * The bounding box is specified with the coordinates of the lower left + * and the upper right corner. In PostScript, those values are often + * called (llx,lly) and (urx,ury), respectively. + * + * If `yMin` is negative, this value gives the glyph's descender. + * Otherwise, the glyph doesn't descend below the baseline. Similarly, + * if `ymax` is positive, this value gives the glyph's ascender. + * + * `xMin` gives the horizontal distance from the glyph's origin to the + * left edge of the glyph's bounding box. If `xMin` is negative, the + * glyph extends to the left of the origin. + */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + + } FT_BBox; + + + /************************************************************************** + * + * @enum: + * FT_Pixel_Mode + * + * @description: + * An enumeration type used to describe the format of pixels in a given + * bitmap. Note that additional formats may be added in the future. + * + * @values: + * FT_PIXEL_MODE_NONE :: + * Value~0 is reserved. + * + * FT_PIXEL_MODE_MONO :: + * A monochrome bitmap, using 1~bit per pixel. Note that pixels are + * stored in most-significant order (MSB), which means that the + * left-most pixel in a byte has value 128. + * + * FT_PIXEL_MODE_GRAY :: + * An 8-bit bitmap, generally used to represent anti-aliased glyph + * images. Each pixel is stored in one byte. Note that the number of + * 'gray' levels is stored in the `num_grays` field of the @FT_Bitmap + * structure (it generally is 256). + * + * FT_PIXEL_MODE_GRAY2 :: + * A 2-bit per pixel bitmap, used to represent embedded anti-aliased + * bitmaps in font files according to the OpenType specification. We + * haven't found a single font using this format, however. + * + * FT_PIXEL_MODE_GRAY4 :: + * A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps + * in font files according to the OpenType specification. We haven't + * found a single font using this format, however. + * + * FT_PIXEL_MODE_LCD :: + * An 8-bit bitmap, representing RGB or BGR decimated glyph images used + * for display on LCD displays; the bitmap is three times wider than + * the original glyph image. See also @FT_RENDER_MODE_LCD. + * + * FT_PIXEL_MODE_LCD_V :: + * An 8-bit bitmap, representing RGB or BGR decimated glyph images used + * for display on rotated LCD displays; the bitmap is three times + * taller than the original glyph image. See also + * @FT_RENDER_MODE_LCD_V. + * + * FT_PIXEL_MODE_BGRA :: + * [Since 2.5] An image with four 8-bit channels per pixel, + * representing a color image (such as emoticons) with alpha channel. + * For each pixel, the format is BGRA, which means, the blue channel + * comes first in memory. The color channels are pre-multiplied and in + * the sRGB colorspace. For example, full red at half-translucent + * opacity will be represented as '00,00,80,80', not '00,00,FF,80'. + * See also @FT_LOAD_COLOR. + */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + FT_PIXEL_MODE_BGRA, + + FT_PIXEL_MODE_MAX /* do not remove */ + + } FT_Pixel_Mode; + + + /* these constants are deprecated; use the corresponding `FT_Pixel_Mode` */ + /* values instead. */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + + /* */ + + /* For debugging, the @FT_Pixel_Mode enumeration must stay in sync */ + /* with the `pixel_modes` array in file `ftobjs.c`. */ + + + /************************************************************************** + * + * @struct: + * FT_Bitmap + * + * @description: + * A structure used to describe a bitmap or pixmap to the raster. Note + * that we now manage pixmaps of various depths through the `pixel_mode` + * field. + * + * @fields: + * rows :: + * The number of bitmap rows. + * + * width :: + * The number of pixels in bitmap row. + * + * pitch :: + * The pitch's absolute value is the number of bytes taken by one + * bitmap row, including padding. However, the pitch is positive when + * the bitmap has a 'down' flow, and negative when it has an 'up' flow. + * In all cases, the pitch is an offset to add to a bitmap pointer in + * order to go down one row. + * + * Note that 'padding' means the alignment of a bitmap to a byte + * border, and FreeType functions normally align to the smallest + * possible integer value. + * + * For the B/W rasterizer, `pitch` is always an even number. + * + * To change the pitch of a bitmap (say, to make it a multiple of 4), + * use @FT_Bitmap_Convert. Alternatively, you might use callback + * functions to directly render to the application's surface; see the + * file `example2.cpp` in the tutorial for a demonstration. + * + * buffer :: + * A typeless pointer to the bitmap buffer. This value should be + * aligned on 32-bit boundaries in most cases. + * + * num_grays :: + * This field is only used with @FT_PIXEL_MODE_GRAY; it gives the + * number of gray levels used in the bitmap. + * + * pixel_mode :: + * The pixel mode, i.e., how pixel bits are stored. See @FT_Pixel_Mode + * for possible values. + * + * palette_mode :: + * This field is intended for paletted pixel modes; it indicates how + * the palette is stored. Not used currently. + * + * palette :: + * A typeless pointer to the bitmap palette; this field is intended for + * paletted pixel modes. Not used currently. + * + * @note: + * `width` and `rows` refer to the *physical* size of the bitmap, not the + * *logical* one. For example, if @FT_Pixel_Mode is set to + * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the + * physical one. + */ + typedef struct FT_Bitmap_ + { + unsigned int rows; + unsigned int width; + int pitch; + unsigned char* buffer; + unsigned short num_grays; + unsigned char pixel_mode; + unsigned char palette_mode; + void* palette; + + } FT_Bitmap; + + + /************************************************************************** + * + * @section: + * outline_processing + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Outline + * + * @description: + * This structure is used to describe an outline to the scan-line + * converter. + * + * @fields: + * n_contours :: + * The number of contours in the outline. + * + * n_points :: + * The number of points in the outline. + * + * points :: + * A pointer to an array of `n_points` @FT_Vector elements, giving the + * outline's point coordinates. + * + * tags :: + * A pointer to an array of `n_points` chars, giving each outline + * point's type. + * + * If bit~0 is unset, the point is 'off' the curve, i.e., a Bezier + * control point, while it is 'on' if set. + * + * Bit~1 is meaningful for 'off' points only. If set, it indicates a + * third-order Bezier arc control point; and a second-order control + * point if unset. + * + * If bit~2 is set, bits 5-7 contain the drop-out mode (as defined in + * the OpenType specification; the value is the same as the argument to + * the 'SCANTYPE' instruction). + * + * Bits 3 and~4 are reserved for internal purposes. + * + * contours :: + * An array of `n_contours` shorts, giving the end point of each + * contour within the outline. For example, the first contour is + * defined by the points '0' to `contours[0]`, the second one is + * defined by the points `contours[0]+1` to `contours[1]`, etc. + * + * flags :: + * A set of bit flags used to characterize the outline and give hints + * to the scan-converter and hinter on how to convert/grid-fit it. See + * @FT_OUTLINE_XXX. + * + * @note: + * The B/W rasterizer only checks bit~2 in the `tags` array for the first + * point of each contour. The drop-out mode as given with + * @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and + * @FT_OUTLINE_INCLUDE_STUBS in `flags` is then overridden. + */ + typedef struct FT_Outline_ + { + unsigned short n_contours; /* number of contours in glyph */ + unsigned short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + unsigned char* tags; /* the points flags */ + unsigned short* contours; /* the contour end points */ + + int flags; /* outline masks */ + + } FT_Outline; + + /* */ + + /* Following limits must be consistent with */ + /* FT_Outline.{n_contours,n_points} */ +#define FT_OUTLINE_CONTOURS_MAX USHRT_MAX +#define FT_OUTLINE_POINTS_MAX USHRT_MAX + + + /************************************************************************** + * + * @enum: + * FT_OUTLINE_XXX + * + * @description: + * A list of bit-field constants used for the flags in an outline's + * `flags` field. + * + * @values: + * FT_OUTLINE_NONE :: + * Value~0 is reserved. + * + * FT_OUTLINE_OWNER :: + * If set, this flag indicates that the outline's field arrays (i.e., + * `points`, `flags`, and `contours`) are 'owned' by the outline + * object, and should thus be freed when it is destroyed. + * + * FT_OUTLINE_EVEN_ODD_FILL :: + * By default, outlines are filled using the non-zero winding rule. If + * set to 1, the outline will be filled using the even-odd fill rule + * (only works with the smooth rasterizer). + * + * FT_OUTLINE_REVERSE_FILL :: + * By default, outside contours of an outline are oriented in + * clock-wise direction, as defined in the TrueType specification. + * This flag is set if the outline uses the opposite direction + * (typically for Type~1 fonts). This flag is ignored by the scan + * converter. + * + * FT_OUTLINE_IGNORE_DROPOUTS :: + * By default, the scan converter will try to detect drop-outs in an + * outline and correct the glyph bitmap to ensure consistent shape + * continuity. If set, this flag hints the scan-line converter to + * ignore such cases. See below for more information. + * + * FT_OUTLINE_SMART_DROPOUTS :: + * Select smart dropout control. If unset, use simple dropout control. + * Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more + * information. + * + * FT_OUTLINE_INCLUDE_STUBS :: + * If set, turn pixels on for 'stubs', otherwise exclude them. Ignored + * if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more + * information. + * + * FT_OUTLINE_OVERLAP :: + * [Since 2.10.3] This flag indicates that this outline contains + * overlapping contours and the anti-aliased renderer should perform + * oversampling to mitigate possible artifacts. This flag should _not_ + * be set for well designed glyphs without overlaps because it quadruples + * the rendering time. + * + * FT_OUTLINE_HIGH_PRECISION :: + * This flag indicates that the scan-line converter should try to + * convert this outline to bitmaps with the highest possible quality. + * It is typically set for small character sizes. Note that this is + * only a hint that might be completely ignored by a given + * scan-converter. + * + * FT_OUTLINE_SINGLE_PASS :: + * This flag is set to force a given scan-converter to only use a + * single pass over the outline to render a bitmap glyph image. + * Normally, it is set for very large character sizes. It is only a + * hint that might be completely ignored by a given scan-converter. + * + * @note: + * The flags @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and + * @FT_OUTLINE_INCLUDE_STUBS are ignored by the smooth rasterizer. + * + * There exists a second mechanism to pass the drop-out mode to the B/W + * rasterizer; see the `tags` field in @FT_Outline. + * + * Please refer to the description of the 'SCANTYPE' instruction in the + * [OpenType specification](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#scantype) + * how simple drop-outs, smart drop-outs, and stubs are defined. + */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 +#define FT_OUTLINE_SMART_DROPOUTS 0x10 +#define FT_OUTLINE_INCLUDE_STUBS 0x20 +#define FT_OUTLINE_OVERLAP 0x40 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + + + /* these constants are deprecated; use the corresponding */ + /* `FT_OUTLINE_XXX` values instead */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + + /* */ + +#define FT_CURVE_TAG( flag ) ( flag & 0x03 ) + + /* see the `tags` field in `FT_Outline` for a description of the values */ +#define FT_CURVE_TAG_ON 0x01 +#define FT_CURVE_TAG_CONIC 0x00 +#define FT_CURVE_TAG_CUBIC 0x02 + +#define FT_CURVE_TAG_HAS_SCANMODE 0x04 + +#define FT_CURVE_TAG_TOUCH_X 0x08 /* reserved for TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 0x10 /* reserved for TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + /* values 0x20, 0x40, and 0x80 are reserved */ + + + /* these constants are deprecated; use the corresponding */ + /* `FT_CURVE_TAG_XXX` values instead */ +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + + + /************************************************************************** + * + * @functype: + * FT_Outline_MoveToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'move to' + * function during outline walking/decomposition. + * + * A 'move to' is emitted to start a new contour in an outline. + * + * @input: + * to :: + * A pointer to the target point of the 'move to'. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_LineToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'line to' + * function during outline walking/decomposition. + * + * A 'line to' is emitted to indicate a segment in the outline. + * + * @input: + * to :: + * A pointer to the target point of the 'line to'. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); + +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_ConicToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'conic to' + * function during outline walking or decomposition. + * + * A 'conic to' is emitted to indicate a second-order Bezier arc in the + * outline. + * + * @input: + * control :: + * An intermediate control point between the last position and the new + * target in `to`. + * + * to :: + * A pointer to the target end point of the conic arc. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); + +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + + + /************************************************************************** + * + * @functype: + * FT_Outline_CubicToFunc + * + * @description: + * A function pointer type used to describe the signature of a 'cubic to' + * function during outline walking or decomposition. + * + * A 'cubic to' is emitted to indicate a third-order Bezier arc. + * + * @input: + * control1 :: + * A pointer to the first Bezier control point. + * + * control2 :: + * A pointer to the second Bezier control point. + * + * to :: + * A pointer to the target end point. + * + * user :: + * A typeless pointer, which is passed from the caller of the + * decomposition function. + * + * @return: + * Error code. 0~means success. + */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); + +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + + + /************************************************************************** + * + * @struct: + * FT_Outline_Funcs + * + * @description: + * A structure to hold various function pointers used during outline + * decomposition in order to emit segments, conic, and cubic Beziers. + * + * @fields: + * move_to :: + * The 'move to' emitter. + * + * line_to :: + * The segment emitter. + * + * conic_to :: + * The second-order Bezier arc emitter. + * + * cubic_to :: + * The third-order Bezier arc emitter. + * + * shift :: + * The shift that is applied to coordinates before they are sent to the + * emitter. + * + * delta :: + * The delta that is applied to coordinates before they are sent to the + * emitter, but after the shift. + * + * @note: + * The point coordinates sent to the emitters are the transformed version + * of the original coordinates (this is important for high accuracy + * during scan-conversion). The transformation is simple: + * + * ``` + * x' = (x << shift) - delta + * y' = (y << shift) - delta + * ``` + * + * Set the values of `shift` and `delta` to~0 to get the original point + * coordinates. + */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; + + } FT_Outline_Funcs; + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @macro: + * FT_IMAGE_TAG + * + * @description: + * This macro converts four-letter tags to an unsigned long type. + * + * @note: + * Since many 16-bit compilers don't like 32-bit enumerations, you should + * redefine this macro in case of problems to something like this: + * + * ``` + * #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value + * ``` + * + * to get a simple enumeration without assigning special numbers. + */ +#ifndef FT_IMAGE_TAG + +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( FT_STATIC_BYTE_CAST( unsigned long, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( unsigned long, _x4 ) ) + +#endif /* FT_IMAGE_TAG */ + + + /************************************************************************** + * + * @enum: + * FT_Glyph_Format + * + * @description: + * An enumeration type used to describe the format of a given glyph + * image. Note that this version of FreeType only supports two image + * formats, even though future font drivers will be able to register + * their own format. + * + * @values: + * FT_GLYPH_FORMAT_NONE :: + * The value~0 is reserved. + * + * FT_GLYPH_FORMAT_COMPOSITE :: + * The glyph image is a composite of several other images. This format + * is _only_ used with @FT_LOAD_NO_RECURSE, and is used to report + * compound glyphs (like accented characters). + * + * FT_GLYPH_FORMAT_BITMAP :: + * The glyph image is a bitmap, and can be described as an @FT_Bitmap. + * You generally need to access the `bitmap` field of the + * @FT_GlyphSlotRec structure to read it. + * + * FT_GLYPH_FORMAT_OUTLINE :: + * The glyph image is a vectorial outline made of line segments and + * Bezier arcs; it can be described as an @FT_Outline; you generally + * want to access the `outline` field of the @FT_GlyphSlotRec structure + * to read it. + * + * FT_GLYPH_FORMAT_PLOTTER :: + * The glyph image is a vectorial path with no inside and outside + * contours. Some Type~1 fonts, like those in the Hershey family, + * contain glyphs in this format. These are described as @FT_Outline, + * but FreeType isn't currently capable of rendering them correctly. + * + * FT_GLYPH_FORMAT_SVG :: + * [Since 2.12] The glyph is represented by an SVG document in the + * 'SVG~' table. + */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_SVG, 'S', 'V', 'G', ' ' ) + + } FT_Glyph_Format; + + + /* these constants are deprecated; use the corresponding */ + /* `FT_Glyph_Format` values instead. */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** R A S T E R D E F I N I T I O N S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + + /************************************************************************** + * + * @section: + * raster + * + * @title: + * Scanline Converter + * + * @abstract: + * How vectorial outlines are converted into bitmaps and pixmaps. + * + * @description: + * A raster or a rasterizer is a scan converter in charge of producing a + * pixel coverage bitmap that can be used as an alpha channel when + * compositing a glyph with a background. FreeType comes with two + * rasterizers: bilevel `raster1` and anti-aliased `smooth` are two + * separate modules. They are usually called from the high-level + * @FT_Load_Glyph or @FT_Render_Glyph functions and produce the entire + * coverage bitmap at once, while staying largely invisible to users. + * + * Instead of working with complete coverage bitmaps, it is also possible + * to intercept consecutive pixel runs on the same scanline with the same + * coverage, called _spans_, and process them individually. Only the + * `smooth` rasterizer permits this when calling @FT_Outline_Render with + * @FT_Raster_Params as described below. + * + * Working with either complete bitmaps or spans it is important to think + * of them as colorless coverage objects suitable as alpha channels to + * blend arbitrary colors with a background. For best results, it is + * recommended to use gamma correction, too. + * + * This section also describes the public API needed to set up alternative + * @FT_Renderer modules. + * + * @order: + * FT_Span + * FT_SpanFunc + * FT_Raster_Params + * FT_RASTER_FLAG_XXX + * + * FT_Raster + * FT_Raster_NewFunc + * FT_Raster_DoneFunc + * FT_Raster_ResetFunc + * FT_Raster_SetModeFunc + * FT_Raster_RenderFunc + * FT_Raster_Funcs + * + */ + + + /************************************************************************** + * + * @struct: + * FT_Span + * + * @description: + * A structure to model a single span of consecutive pixels when + * rendering an anti-aliased bitmap. + * + * @fields: + * x :: + * The span's horizontal start position. + * + * len :: + * The span's length in pixels. + * + * coverage :: + * The span color/coverage, ranging from 0 (background) to 255 + * (foreground). + * + * @note: + * This structure is used by the span drawing callback type named + * @FT_SpanFunc that takes the y~coordinate of the span as a parameter. + * + * The anti-aliased rasterizer produces coverage values from 0 to 255, + * that is, from completely transparent to completely opaque. + */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + + } FT_Span; + + + /************************************************************************** + * + * @functype: + * FT_SpanFunc + * + * @description: + * A function used as a call-back by the anti-aliased renderer in order + * to let client applications draw themselves the pixel spans on each + * scan line. + * + * @input: + * y :: + * The scanline's upward y~coordinate. + * + * count :: + * The number of spans to draw on this scanline. + * + * spans :: + * A table of `count` spans to draw on the scanline. + * + * user :: + * User-supplied data that is passed to the callback. + * + * @note: + * This callback allows client applications to directly render the spans + * of the anti-aliased bitmap to any kind of surfaces. + * + * This can be used to write anti-aliased outlines directly to a given + * background bitmap using alpha compositing. It can also be used for + * oversampling and averaging. + */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); + +#define FT_Raster_Span_Func FT_SpanFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_BitTest_Func + * + * @description: + * Deprecated, unimplemented. + */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); + + + /************************************************************************** + * + * @functype: + * FT_Raster_BitSet_Func + * + * @description: + * Deprecated, unimplemented. + */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); + + + /************************************************************************** + * + * @enum: + * FT_RASTER_FLAG_XXX + * + * @description: + * A list of bit flag constants as used in the `flags` field of a + * @FT_Raster_Params structure. + * + * @values: + * FT_RASTER_FLAG_DEFAULT :: + * This value is 0. + * + * FT_RASTER_FLAG_AA :: + * This flag is set to indicate that an anti-aliased glyph image should + * be generated. Otherwise, it will be monochrome (1-bit). + * + * FT_RASTER_FLAG_DIRECT :: + * This flag is set to indicate direct rendering. In this mode, client + * applications must provide their own span callback. This lets them + * directly draw or compose over an existing bitmap. If this bit is + * _not_ set, the target pixmap's buffer _must_ be zeroed before + * rendering and the output will be clipped to its size. + * + * Direct rendering is only possible with anti-aliased glyphs. + * + * FT_RASTER_FLAG_CLIP :: + * This flag is only used in direct rendering mode. If set, the output + * will be clipped to a box specified in the `clip_box` field of the + * @FT_Raster_Params structure. Otherwise, the `clip_box` is + * effectively set to the bounding box and all spans are generated. + * + * FT_RASTER_FLAG_SDF :: + * This flag is set to indicate that a signed distance field glyph + * image should be generated. This is only used while rendering with + * the @FT_RENDER_MODE_SDF render mode. + */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 +#define FT_RASTER_FLAG_SDF 0x8 + + /* these constants are deprecated; use the corresponding */ + /* `FT_RASTER_FLAG_XXX` values instead */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP + + + /************************************************************************** + * + * @struct: + * FT_Raster_Params + * + * @description: + * A structure to hold the parameters used by a raster's render function, + * passed as an argument to @FT_Outline_Render. + * + * @fields: + * target :: + * The target bitmap. + * + * source :: + * A pointer to the source glyph image (e.g., an @FT_Outline). + * + * flags :: + * The rendering flags. + * + * gray_spans :: + * The gray span drawing callback. + * + * black_spans :: + * Unused. + * + * bit_test :: + * Unused. + * + * bit_set :: + * Unused. + * + * user :: + * User-supplied data that is passed to each drawing callback. + * + * clip_box :: + * An optional span clipping box expressed in _integer_ pixels + * (not in 26.6 fixed-point units). + * + * @note: + * The @FT_RASTER_FLAG_AA bit flag must be set in the `flags` to + * generate an anti-aliased glyph bitmap, otherwise a monochrome bitmap + * is generated. The `target` should have appropriate pixel mode and its + * dimensions define the clipping region. + * + * If both @FT_RASTER_FLAG_AA and @FT_RASTER_FLAG_DIRECT bit flags + * are set in `flags`, the raster calls an @FT_SpanFunc callback + * `gray_spans` with `user` data as an argument ignoring `target`. This + * allows direct composition over a pre-existing user surface to perform + * the span drawing and composition. To optionally clip the spans, set + * the @FT_RASTER_FLAG_CLIP flag and `clip_box`. The monochrome raster + * does not support the direct mode. + * + * The gray-level rasterizer always uses 256 gray levels. If you want + * fewer gray levels, you have to use @FT_RASTER_FLAG_DIRECT and reduce + * the levels in the callback function. + */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; + FT_SpanFunc black_spans; /* unused */ + FT_Raster_BitTest_Func bit_test; /* unused */ + FT_Raster_BitSet_Func bit_set; /* unused */ + void* user; + FT_BBox clip_box; + + } FT_Raster_Params; + + + /************************************************************************** + * + * @type: + * FT_Raster + * + * @description: + * An opaque handle (pointer) to a raster object. Each object can be + * used independently to convert an outline into a bitmap or pixmap. + * + * @note: + * In FreeType 2, all rasters are now encapsulated within specific + * @FT_Renderer modules and only used in their context. + * + */ + typedef struct FT_RasterRec_* FT_Raster; + + + /************************************************************************** + * + * @functype: + * FT_Raster_NewFunc + * + * @description: + * A function used to create a new raster object. + * + * @input: + * memory :: + * A handle to the memory allocator. + * + * @output: + * raster :: + * A handle to the new raster object. + * + * @return: + * Error code. 0~means success. + * + * @note: + * The `memory` parameter is a typeless pointer in order to avoid + * un-wanted dependencies on the rest of the FreeType code. In practice, + * it is an @FT_Memory object, i.e., a handle to the standard FreeType + * memory allocator. However, this field can be completely ignored by a + * given raster implementation. + */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); + +#define FT_Raster_New_Func FT_Raster_NewFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_DoneFunc + * + * @description: + * A function used to destroy a given raster object. + * + * @input: + * raster :: + * A handle to the raster object. + */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); + +#define FT_Raster_Done_Func FT_Raster_DoneFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_ResetFunc + * + * @description: + * FreeType used to provide an area of memory called the 'render pool' + * available to all registered rasterizers. This was not thread safe, + * however, and now FreeType never allocates this pool. + * + * This function is called after a new raster object is created. + * + * @input: + * raster :: + * A handle to the new raster object. + * + * pool_base :: + * Previously, the address in memory of the render pool. Set this to + * `NULL`. + * + * pool_size :: + * Previously, the size in bytes of the render pool. Set this to 0. + * + * @note: + * Rasterizers should rely on dynamic or stack allocation if they want to + * (a handle to the memory allocator is passed to the rasterizer + * constructor). + */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); + +#define FT_Raster_Reset_Func FT_Raster_ResetFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_SetModeFunc + * + * @description: + * This function is a generic facility to change modes or attributes in a + * given raster. This can be used for debugging purposes, or simply to + * allow implementation-specific 'features' in a given raster module. + * + * @input: + * raster :: + * A handle to the new raster object. + * + * mode :: + * A 4-byte tag used to name the mode or property. + * + * args :: + * A pointer to the new mode/property to use. + */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); + +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc + + + /************************************************************************** + * + * @functype: + * FT_Raster_RenderFunc + * + * @description: + * Invoke a given raster to scan-convert a given glyph image into a + * target bitmap. + * + * @input: + * raster :: + * A handle to the raster object. + * + * params :: + * A pointer to an @FT_Raster_Params structure used to store the + * rendering parameters. + * + * @return: + * Error code. 0~means success. + * + * @note: + * The exact format of the source image depends on the raster's glyph + * format defined in its @FT_Raster_Funcs structure. It can be an + * @FT_Outline or anything else in order to support a large array of + * glyph formats. + * + * Note also that the render function can fail and return a + * `FT_Err_Unimplemented_Feature` error code if the raster used does not + * support direct composition. + */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); + +#define FT_Raster_Render_Func FT_Raster_RenderFunc + + + /************************************************************************** + * + * @struct: + * FT_Raster_Funcs + * + * @description: + * A structure used to describe a given raster class to the library. + * + * @fields: + * glyph_format :: + * The supported glyph format for this raster. + * + * raster_new :: + * The raster constructor. + * + * raster_reset :: + * Used to reset the render pool within the raster. + * + * raster_render :: + * A function to render a glyph into a given bitmap. + * + * raster_done :: + * The raster destructor. + */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + + } FT_Raster_Funcs; + + /* */ + + +FT_END_HEADER + +#endif /* FTIMAGE_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftincrem.h b/Dependencies/freetype/freetype/include/freetype/ftincrem.h new file mode 100644 index 00000000..816581b7 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftincrem.h @@ -0,0 +1,348 @@ +/**************************************************************************** + * + * ftincrem.h + * + * FreeType incremental loading (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTINCREM_H_ +#define FTINCREM_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * 'incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application. + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a PostScript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ + + + /************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * 'incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., PostScript + * interpreters), where the glyph data isn't in the font file, or must be + * overridden by different values. + * + * @note: + * It is up to client applications to create and implement + * @FT_Incremental objects, as long as they provide implementations for + * the methods @FT_Incremental_GetGlyphDataFunc, + * @FT_Incremental_FreeGlyphDataFunc and + * @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + * + */ + typedef struct FT_IncrementalRec_* FT_Incremental; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_MetricsRec + * + * @description: + * A small structure used to contain the basic glyph metrics returned by + * the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Horizontal component of glyph advance, in font units. + * + * advance_v :: + * Vertical component of glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical` argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + * + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; + FT_Long advance_v; /* since 2.3.12 */ + + } FT_Incremental_MetricsRec; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A handle to an @FT_Incremental_MetricsRec structure. + * + */ + typedef struct FT_Incremental_MetricsRec_* FT_Incremental_Metrics; + + + /************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the 'glyf' table. For PostScript formats, it must correspond to the + * **unencrypted** charstring bytes, without any `lenIV` header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release the + * data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); + + + /************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + * + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); + + + /************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This allows for handling font types such + * as PCL~XL Format~1, Class~2 downloaded TrueType fonts, where the glyph + * metrics (`hmtx` and `vmtx` tables) are permitted to be omitted from + * the font, and the relevant metrics included in the header of the glyph + * outline data. Importantly, this is not intended to allow custom glyph + * metrics (for example, Postscript Metrics dictionaries), because that + * conflicts with the requirements of outline hinting. Such custom + * metrics must be handled separately, by the calling application. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. The original + * glyph metrics, if any, in font units. If metrics are not available + * all the values must be set to zero. + * + * @output: + * ametrics :: + * The glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data incrementally. + * Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does not + * require it. + * + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + + } FT_Incremental_FuncsRec; + + + /************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * ``` + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * ``` + * + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + + } FT_Incremental_InterfaceRec; + + + /************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; + + + /* */ + + +FT_END_HEADER + +#endif /* FTINCREM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftlcdfil.h b/Dependencies/freetype/freetype/include/freetype/ftlcdfil.h new file mode 100644 index 00000000..25274dc4 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftlcdfil.h @@ -0,0 +1,323 @@ +/**************************************************************************** + * + * ftlcdfil.h + * + * FreeType API for color filtering of subpixel bitmap glyphs + * (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLCDFIL_H_ +#define FTLCDFIL_H_ + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * lcd_rendering + * + * @title: + * Subpixel Rendering + * + * @abstract: + * API to control subpixel rendering. + * + * @description: + * FreeType provides two alternative subpixel rendering technologies. + * Should you define `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` in your + * `ftoption.h` file, this enables ClearType-style rendering. + * Otherwise, Harmony LCD rendering is enabled. These technologies are + * controlled differently and API described below, although always + * available, performs its function when appropriate method is enabled + * and does nothing otherwise. + * + * ClearType-style LCD rendering exploits the color-striped structure of + * LCD pixels, increasing the available resolution in the direction of + * the stripe (usually horizontal RGB) by a factor of~3. Using the + * subpixel coverages unfiltered can create severe color fringes + * especially when rendering thin features. Indeed, to produce + * black-on-white text, the nearby color subpixels must be dimmed + * evenly. Therefore, an equalizing 5-tap FIR filter should be applied + * to subpixel coverages regardless of pixel boundaries and should have + * these properties: + * + * 1. It should be symmetrical, like {~a, b, c, b, a~}, to avoid + * any shifts in appearance. + * + * 2. It should be color-balanced, meaning a~+ b~=~c, to reduce color + * fringes by distributing the computed coverage for one subpixel to + * all subpixels equally. + * + * 3. It should be normalized, meaning 2a~+ 2b~+ c~=~1.0 to maintain + * overall brightness. + * + * Boxy 3-tap filter {0, 1/3, 1/3, 1/3, 0} is sharper but is less + * forgiving of non-ideal gamma curves of a screen (and viewing angles), + * beveled filters are fuzzier but more tolerant. + * + * Use the @FT_Library_SetLcdFilter or @FT_Library_SetLcdFilterWeights + * API to specify a low-pass filter, which is then applied to + * subpixel-rendered bitmaps generated through @FT_Render_Glyph. + * + * Harmony LCD rendering is suitable to panels with any regular subpixel + * structure, not just monitors with 3 color striped subpixels, as long + * as the color subpixels have fixed positions relative to the pixel + * center. In this case, each color channel can be rendered separately + * after shifting the outline opposite to the subpixel shift so that the + * coverage maps are aligned. This method is immune to color fringes + * because the shifts do not change integral coverage. + * + * The subpixel geometry must be specified by xy-coordinates for each + * subpixel. By convention they may come in the RGB order: {{-1/3, 0}, + * {0, 0}, {1/3, 0}} for standard RGB striped panel or {{-1/6, 1/4}, + * {-1/6, -1/4}, {1/3, 0}} for a certain PenTile panel. + * + * Use the @FT_Library_SetLcdGeometry API to specify subpixel positions. + * If one follows the RGB order convention, the same order applies to the + * resulting @FT_PIXEL_MODE_LCD and @FT_PIXEL_MODE_LCD_V bitmaps. Note, + * however, that the coordinate frame for the latter must be rotated + * clockwise. Harmony with default LCD geometry is equivalent to + * ClearType with light filter. + * + * As a result of ClearType filtering or Harmony shifts, the resulting + * dimensions of LCD bitmaps can be slightly wider or taller than the + * dimensions the original outline with regard to the pixel grid. + * For example, for @FT_RENDER_MODE_LCD, the filter adds 2~subpixels to + * the left, and 2~subpixels to the right. The bitmap offset values are + * adjusted accordingly, so clients shouldn't need to modify their layout + * and glyph positioning code when enabling the filter. + * + * The ClearType and Harmony rendering is applicable to glyph bitmaps + * rendered through @FT_Render_Glyph, @FT_Load_Glyph, @FT_Load_Char, and + * @FT_Glyph_To_Bitmap, when @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V + * is specified. This API does not control @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * The described algorithms can completely remove color artefacts when + * combined with gamma-corrected alpha blending in linear space. Each of + * the 3~alpha values (subpixels) must by independently used to blend one + * color channel. That is, red alpha blends the red channel of the text + * color with the red channel of the background pixel. + */ + + + /************************************************************************** + * + * @enum: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * This is a beveled, normalized, and color-balanced five-tap filter + * with weights of [0x08 0x4D 0x56 0x4D 0x08] in 1/256 units. + * + * FT_LCD_FILTER_LIGHT :: + * this is a boxy, normalized, and color-balanced three-tap filter with + * weights of [0x00 0x55 0x56 0x55 0x00] in 1/256 units. + * + * FT_LCD_FILTER_LEGACY :: + * FT_LCD_FILTER_LEGACY1 :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. The second value is + * provided for compatibility with FontConfig, which historically used + * different enumeration, sometimes incorrectly forwarded to FreeType. + * + * @since: + * 2.3.0 (`FT_LCD_FILTER_LEGACY1` since 2.6.2) + */ + typedef enum FT_LcdFilter_ + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY1 = 3, + FT_LCD_FILTER_LEGACY = 16, + + FT_LCD_FILTER_MAX /* do not remove */ + + } FT_LcdFilter; + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to change filter applied to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work well + * on most LCD screens. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Since 2.10.3 the LCD filtering is enabled with @FT_LCD_FILTER_DEFAULT. + * It is no longer necessary to call this function explicitly except + * to choose a different filter or disable filtering altogether with + * @FT_LCD_FILTER_NONE. + * + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdFilterWeights + * + * @description: + * This function can be used to enable LCD filter with custom weights, + * instead of using presets in @FT_Library_SetLcdFilter. + * + * @input: + * library :: + * A handle to the target library instance. + * + * weights :: + * A pointer to an array; the function copies the first five bytes and + * uses them to specify the filter weights in 1/256 units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. + * + * LCD filter weights can also be set per face using @FT_Face_Properties + * with @FT_PARAM_TAG_LCD_FILTER_WEIGHTS. + * + * @since: + * 2.4.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ); + + + /************************************************************************** + * + * @type: + * FT_LcdFiveTapFilter + * + * @description: + * A typedef for passing the five LCD filter weights to + * @FT_Face_Properties within an @FT_Parameter structure. + * + * @since: + * 2.8 + * + */ +#define FT_LCD_FILTER_FIVE_TAPS 5 + + typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS]; + + + /************************************************************************** + * + * @function: + * FT_Library_SetLcdGeometry + * + * @description: + * This function can be used to modify default positions of color + * subpixels, which controls Harmony LCD rendering. + * + * @input: + * library :: + * A handle to the target library instance. + * + * sub :: + * A pointer to an array of 3 vectors in 26.6 fractional pixel format; + * the function modifies the default values, see the note below. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Subpixel geometry examples: + * + * - {{-21, 0}, {0, 0}, {21, 0}} is the default, corresponding to 3 color + * stripes shifted by a third of a pixel. This could be an RGB panel. + * + * - {{21, 0}, {0, 0}, {-21, 0}} looks the same as the default but can + * specify a BGR panel instead, while keeping the bitmap in the same + * RGB888 format. + * + * - {{0, 21}, {0, 0}, {0, -21}} is the vertical RGB, but the bitmap + * stays RGB888 as a result. + * + * - {{-11, 16}, {-11, -16}, {22, 0}} is a certain PenTile arrangement. + * + * This function does nothing and returns `FT_Err_Unimplemented_Feature` + * in the context of ClearType-style subpixel rendering when + * `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is defined in your build of the + * library. + * + * @since: + * 2.10.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLCDFIL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftlist.h b/Dependencies/freetype/freetype/include/freetype/ftlist.h new file mode 100644 index 00000000..972fbfa2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftlist.h @@ -0,0 +1,296 @@ +/**************************************************************************** + * + * ftlist.h + * + * Generic list support for FreeType (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file implements functions relative to list processing. Its data + * structures are defined in `freetype.h`. + * + */ + + +#ifndef FTLIST_H_ +#define FTLIST_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * list_processing + * + * @title: + * List Processing + * + * @abstract: + * Simple management of lists. + * + * @description: + * This section contains various definitions related to list processing + * using doubly-linked nodes. + * + * @order: + * FT_List + * FT_ListNode + * FT_ListRec + * FT_ListNodeRec + * + * FT_List_Add + * FT_List_Insert + * FT_List_Find + * FT_List_Remove + * FT_List_Up + * FT_List_Iterate + * FT_List_Iterator + * FT_List_Finalize + * FT_List_Destructor + * + */ + + + /************************************************************************** + * + * @function: + * FT_List_Find + * + * @description: + * Find the list node for a given listed object. + * + * @input: + * list :: + * A pointer to the parent list. + * data :: + * The address of the listed object. + * + * @return: + * List node. `NULL` if it wasn't found. + */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); + + + /************************************************************************** + * + * @function: + * FT_List_Add + * + * @description: + * Append an element to the end of a list. + * + * @inout: + * list :: + * A pointer to the parent list. + * node :: + * The node to append. + */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Insert + * + * @description: + * Insert an element at the head of a list. + * + * @inout: + * list :: + * A pointer to parent list. + * node :: + * The node to insert. + */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Remove + * + * @description: + * Remove a node from a list. This function doesn't check whether the + * node is in the list! + * + * @input: + * node :: + * The node to remove. + * + * @inout: + * list :: + * A pointer to the parent list. + */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @function: + * FT_List_Up + * + * @description: + * Move a node to the head/top of a list. Used to maintain LRU lists. + * + * @inout: + * list :: + * A pointer to the parent list. + * node :: + * The node to move. + */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); + + + /************************************************************************** + * + * @functype: + * FT_List_Iterator + * + * @description: + * An FT_List iterator function that is called during a list parse by + * @FT_List_Iterate. + * + * @input: + * node :: + * The current iteration list node. + * + * user :: + * A typeless pointer passed to @FT_List_Iterate. Can be used to point + * to the iteration's state. + */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_List_Iterate + * + * @description: + * Parse a list and calls a given iterator function on each element. + * Note that parsing is stopped as soon as one of the iterator calls + * returns a non-zero value. + * + * @input: + * list :: + * A handle to the list. + * iterator :: + * An iterator function, called on each node of the list. + * user :: + * A user-supplied field that is passed as the second argument to the + * iterator. + * + * @return: + * The result (a FreeType error code) of the last iterator call. + */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); + + + /************************************************************************** + * + * @functype: + * FT_List_Destructor + * + * @description: + * An @FT_List iterator function that is called during a list + * finalization by @FT_List_Finalize to destroy all elements in a given + * list. + * + * @input: + * system :: + * The current system object. + * + * data :: + * The current object to destroy. + * + * user :: + * A typeless pointer passed to @FT_List_Iterate. It can be used to + * point to the iteration's state. + */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_List_Finalize + * + * @description: + * Destroy all elements in the list as well as the list itself. + * + * @input: + * list :: + * A handle to the list. + * + * destroy :: + * A list destructor that will be applied to each element of the list. + * Set this to `NULL` if not needed. + * + * memory :: + * The current memory object that handles deallocation. + * + * user :: + * A user-supplied field that is passed as the last argument to the + * destructor. + * + * @note: + * This function expects that all nodes added by @FT_List_Add or + * @FT_List_Insert have been dynamically allocated. + */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLIST_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftlogging.h b/Dependencies/freetype/freetype/include/freetype/ftlogging.h new file mode 100644 index 00000000..1813cfc2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftlogging.h @@ -0,0 +1,184 @@ +/**************************************************************************** + * + * ftlogging.h + * + * Additional debugging APIs. + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLOGGING_H_ +#define FTLOGGING_H_ + + +#include +#include FT_CONFIG_CONFIG_H + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * debugging_apis + * + * @title: + * External Debugging APIs + * + * @abstract: + * Public APIs to control the `FT_DEBUG_LOGGING` macro. + * + * @description: + * This section contains the declarations of public functions that + * enables fine control of what the `FT_DEBUG_LOGGING` macro outputs. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Level + * + * @description: + * Change the levels of tracing components of FreeType at run time. + * + * @input: + * tracing_level :: + * New tracing value. + * + * @example: + * The following call makes FreeType trace everything but the 'memory' + * component. + * + * ``` + * FT_Trace_Set_Level( "any:7 memory:0" ); + * ``` + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Level( const char* tracing_level ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Default_Level + * + * @description: + * Reset tracing value of FreeType's components to the default value + * (i.e., to the value of the `FT2_DEBUG` environment value or to NULL + * if `FT2_DEBUG` is not set). + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Default_Level( void ); + + + /************************************************************************** + * + * @functype: + * FT_Custom_Log_Handler + * + * @description: + * A function typedef that is used to handle the logging of tracing and + * debug messages on a file system. + * + * @input: + * ft_component :: + * The name of `FT_COMPONENT` from which the current debug or error + * message is produced. + * + * fmt :: + * Actual debug or tracing message. + * + * args:: + * Arguments of debug or tracing messages. + * + * @since: + * 2.11 + * + */ + typedef void + (*FT_Custom_Log_Handler)( const char* ft_component, + const char* fmt, + va_list args ); + + + /************************************************************************** + * + * @function: + * FT_Set_Log_Handler + * + * @description: + * A function to set a custom log handler. + * + * @input: + * handler :: + * New logging function. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Log_Handler + * + * @description: + * A function to undo the effect of @FT_Set_Log_Handler, resetting the + * log handler to FreeType's built-in version. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Default_Log_Handler( void ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLOGGING_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftlzw.h b/Dependencies/freetype/freetype/include/freetype/ftlzw.h new file mode 100644 index 00000000..bcf59ba7 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftlzw.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * + * ftlzw.h + * + * LZW-compressed stream support. + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLZW_H_ +#define FTLZW_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * lzw + * + * @title: + * LZW Streams + * + * @abstract: + * Using LZW-compressed font files. + * + * @description: + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it and + * re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * + * This section contains the declaration of LZW-specific functions. + * + */ + + /************************************************************************** + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is mainly + * used to support the compressed `*.pcf.Z` fonts that come with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close` on the new stream will + * **not** call `FT_Stream_Close` on the source stream. None of the + * stream objects will be released to the heap. + * + * This function may return `FT_Err_Unimplemented_Feature` if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLZW_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftmac.h b/Dependencies/freetype/freetype/include/freetype/ftmac.h new file mode 100644 index 00000000..e4efde33 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftmac.h @@ -0,0 +1,289 @@ +/**************************************************************************** + * + * ftmac.h + * + * Additional Mac-specific API. + * + * Copyright (C) 1996-2024 by + * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/**************************************************************************** + * + * NOTE: Include this file after `FT_FREETYPE_H` and after any + * Mac-specific headers (because this header uses Mac types such as + * 'Handle', 'FSSpec', 'FSRef', etc.) + * + */ + + +#ifndef FTMAC_H_ +#define FTMAC_H_ + + + + +FT_BEGIN_HEADER + + + /* gcc-3.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined( __GNUC__ ) && \ + ( ( __GNUC__ >= 4 ) || \ + ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 1 ) ) ) +#define FT_DEPRECATED_ATTRIBUTE __attribute__(( deprecated )) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif + + + /************************************************************************** + * + * @section: + * mac_specific + * + * @title: + * Mac Specific Interface + * + * @abstract: + * Only available on the Macintosh. + * + * @description: + * The following definitions are only available if FreeType is compiled + * on a Macintosh. + * + */ + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FOND + * + * @description: + * Create a new face object from a FOND resource. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * fond :: + * A FOND resource. + * + * face_index :: + * Only supported for the -1 'sanity check' special case. + * + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @example: + * This function can be used to create @FT_Face objects from fonts that + * are installed in the system as follows. + * + * ``` + * fond = GetResource( 'FOND', fontName ); + * error = FT_New_Face_From_FOND( library, fond, 0, &face ); + * ``` + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFile_From_Mac_Name + * + * @description: + * Return an FSSpec for the disk file containing the named font. + * + * @input: + * fontName :: + * Mac OS name of the font (e.g., Times New Roman Bold). + * + * @output: + * pathSpec :: + * FSSpec to the file. For passing to @FT_New_Face_From_FSSpec. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face_From_FSSpec. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFile_From_Mac_ATS_Name + * + * @description: + * Return an FSSpec for the disk file containing the named font. + * + * @input: + * fontName :: + * Mac OS name of the font in ATS framework. + * + * @output: + * pathSpec :: + * FSSpec to the file. For passing to @FT_New_Face_From_FSSpec. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face_From_FSSpec. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_GetFilePath_From_Mac_ATS_Name + * + * @description: + * Return a pathname of the disk file and face index for given font name + * that is handled by ATS framework. + * + * @input: + * fontName :: + * Mac OS name of the font in ATS framework. + * + * @output: + * path :: + * Buffer to store pathname of the file. For passing to @FT_New_Face. + * The client must allocate this buffer before calling this function. + * + * maxPathSize :: + * Lengths of the buffer `path` that client allocated. + * + * face_index :: + * Index of the face. For passing to @FT_New_Face. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FSSpec + * + * @description: + * Create a new face object from a given resource and typeface index + * using an FSSpec to the font file. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * spec :: + * FSSpec to the font file. + * + * face_index :: + * The index of the face within the resource. The first face has + * index~0. + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * @FT_New_Face_From_FSSpec is identical to @FT_New_Face except it + * accepts an FSSpec instead of a path. + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + + /************************************************************************** + * + * @function: + * FT_New_Face_From_FSRef + * + * @description: + * Create a new face object from a given resource and typeface index + * using an FSRef to the font file. + * + * @inout: + * library :: + * A handle to the library resource. + * + * @input: + * spec :: + * FSRef to the font file. + * + * face_index :: + * The index of the face within the resource. The first face has + * index~0. + * @output: + * aface :: + * A handle to a new face object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * @FT_New_Face_From_FSRef is identical to @FT_New_Face except it accepts + * an FSRef instead of a path. + */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; + + /* */ + + +FT_END_HEADER + + +#endif /* FTMAC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftmm.h b/Dependencies/freetype/freetype/include/freetype/ftmm.h new file mode 100644 index 00000000..35ed039c --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftmm.h @@ -0,0 +1,834 @@ +/**************************************************************************** + * + * ftmm.h + * + * FreeType Multiple Master font interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMM_H_ +#define FTMM_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * multiple_masters + * + * @title: + * Multiple Masters + * + * @abstract: + * How to manage Multiple Masters fonts. + * + * @description: + * The following types and functions are used to manage Multiple Master + * fonts, i.e., the selection of specific design instances by setting + * design axis coordinates. + * + * Besides Adobe MM fonts, the interface supports Apple's TrueType GX and + * OpenType variation fonts. Some of the routines only work with Adobe + * MM fonts, others will work with all three types. They are similar + * enough that a consistent interface makes sense. + * + * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For GX and + * OpenType variation fonts, it returns true. + * + */ + + + /************************************************************************** + * + * @enum: + * T1_MAX_MM_XXX + * + * @description: + * Multiple Masters limits as defined in their specifications. + * + * @values: + * T1_MAX_MM_AXIS :: + * The maximum number of Multiple Masters axes. + * + * T1_MAX_MM_DESIGNS :: + * The maximum number of Multiple Masters designs. + * + * T1_MAX_MM_MAP_POINTS :: + * The maximum number of elements in a design map. + * + */ +#define T1_MAX_MM_AXIS 4 +#define T1_MAX_MM_DESIGNS 16 +#define T1_MAX_MM_MAP_POINTS 20 + + + /************************************************************************** + * + * @struct: + * FT_MM_Axis + * + * @description: + * A structure to model a given axis in design space for Multiple Masters + * fonts. + * + * This structure can't be used for TrueType GX or OpenType variation + * fonts. + * + * @fields: + * name :: + * The axis's name. + * + * minimum :: + * The axis's minimum design coordinate. + * + * maximum :: + * The axis's maximum design coordinate. + */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + + } FT_MM_Axis; + + + /************************************************************************** + * + * @struct: + * FT_Multi_Master + * + * @description: + * A structure to model the axes and space of a Multiple Masters font. + * + * This structure can't be used for TrueType GX or OpenType variation + * fonts. + * + * @fields: + * num_axis :: + * Number of axes. Cannot exceed~4. + * + * num_designs :: + * Number of designs; should be normally 2^num_axis even though the + * Type~1 specification strangely allows for intermediate designs to be + * present. This number cannot exceed~16. + * + * axis :: + * A table of axis descriptors. + */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + + } FT_Multi_Master; + + + /************************************************************************** + * + * @struct: + * FT_Var_Axis + * + * @description: + * A structure to model a given axis in design space for Multiple + * Masters, TrueType GX, and OpenType variation fonts. + * + * @fields: + * name :: + * The axis's name. Not always meaningful for TrueType GX or OpenType + * variation fonts. + * + * minimum :: + * The axis's minimum design coordinate. + * + * def :: + * The axis's default design coordinate. FreeType computes meaningful + * default values for Adobe MM fonts. + * + * maximum :: + * The axis's maximum design coordinate. + * + * tag :: + * The axis's tag (the equivalent to 'name' for TrueType GX and + * OpenType variation fonts). FreeType provides default values for + * Adobe MM fonts if possible. + * + * strid :: + * The axis name entry in the font's 'name' table. This is another + * (and often better) version of the 'name' field for TrueType GX or + * OpenType variation fonts. Not meaningful for Adobe MM fonts. + * + * @note: + * The fields `minimum`, `def`, and `maximum` are 16.16 fractional values + * for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the + * values are whole numbers (i.e., the fractional part is zero). + */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + + FT_ULong tag; + FT_UInt strid; + + } FT_Var_Axis; + + + /************************************************************************** + * + * @struct: + * FT_Var_Named_Style + * + * @description: + * A structure to model a named instance in a TrueType GX or OpenType + * variation font. + * + * This structure can't be used for Adobe MM fonts. + * + * @fields: + * coords :: + * The design coordinates for this instance. This is an array with one + * entry for each axis. + * + * strid :: + * The entry in 'name' table identifying this instance. + * + * psid :: + * The entry in 'name' table identifying a PostScript name for this + * instance. Value 0xFFFF indicates a missing entry. + */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + FT_UInt psid; /* since 2.7.1 */ + + } FT_Var_Named_Style; + + + /************************************************************************** + * + * @struct: + * FT_MM_Var + * + * @description: + * A structure to model the axes and space of an Adobe MM, TrueType GX, + * or OpenType variation font. + * + * Some fields are specific to one format and not to the others. + * + * @fields: + * num_axis :: + * The number of axes. The maximum value is~4 for Adobe MM fonts; no + * limit in TrueType GX or OpenType variation fonts. + * + * num_designs :: + * The number of designs; should be normally 2^num_axis for Adobe MM + * fonts. Not meaningful for TrueType GX or OpenType variation fonts + * (where every glyph could have a different number of designs). + * + * num_namedstyles :: + * The number of named styles; a 'named style' is a tuple of design + * coordinates that has a string ID (in the 'name' table) associated + * with it. The font can tell the user that, for example, + * [Weight=1.5,Width=1.1] is 'Bold'. Another name for 'named style' is + * 'named instance'. + * + * For Adobe Multiple Masters fonts, this value is always zero because + * the format does not support named styles. + * + * axis :: + * An axis descriptor table. TrueType GX and OpenType variation fonts + * contain slightly more data than Adobe MM fonts. Memory management + * of this pointer is done internally by FreeType. + * + * namedstyle :: + * A named style (instance) table. Only meaningful for TrueType GX and + * OpenType variation fonts. Memory management of this pointer is done + * internally by FreeType. + */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + + } FT_MM_Var; + + + /************************************************************************** + * + * @function: + * FT_Get_Multi_Master + * + * @description: + * Retrieve a variation descriptor of a given Adobe MM font. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * amaster :: + * The Multiple Masters descriptor. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_Var + * + * @description: + * Retrieve a variation descriptor for a given font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * amaster :: + * The variation descriptor. Allocates a data structure, which the + * user must deallocate with a call to @FT_Done_MM_Var after use. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Done_MM_Var + * + * @description: + * Free the memory allocated by @FT_Get_MM_Var. + * + * @input: + * library :: + * A handle of the face's parent library object that was used in the + * call to @FT_Get_MM_Var to create `amaster`. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_MM_Var( FT_Library library, + FT_MM_Var *amaster ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_Design_Coordinates + * + * @description: + * For Adobe MM fonts, choose an interpolated font design through design + * coordinates. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * An array of design coordinates. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_Var_Design_Coordinates + * + * @description: + * Choose an interpolated font design through design coordinates. + * + * This function works with all supported variation formats. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * An array of design coordinates. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType variation fonts. For Adobe MM fonts, the values are supposed + * to be whole numbers (i.e., the fractional part is zero). + * + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * [Since 2.9] 'Default values' means the currently selected named + * instance (or the base font if no named instance is selected). + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Design_Coordinates + * + * @description: + * Get the design coordinates of the currently selected interpolated + * font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of design coordinates to retrieve. If it is larger than + * the number of axes, set the excess values to~0. + * + * @output: + * coords :: + * The design coordinates array. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType variation fonts. For Adobe MM fonts, the values are whole + * numbers (i.e., the fractional part is zero). + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_Blend_Coordinates + * + * @description: + * Choose an interpolated font design through normalized blend + * coordinates. + * + * This function works with all supported variation formats. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * num_coords :: + * The number of available design coordinates. If it is larger than + * the number of axes, ignore the excess values. If it is smaller than + * the number of axes, use default values for the remaining axes. + * + * coords :: + * The design coordinates array. Each element is a 16.16 fractional + * value and must be between 0 and 1.0 for Adobe MM fonts, and between + * -1.0 and 1.0 for TrueType GX and OpenType variation fonts. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * [Since 2.8.1] To reset all axes to the default values, call the + * function with `num_coords` set to zero and `coords` set to `NULL`. + * [Since 2.9] 'Default values' means the currently selected named + * instance (or the base font if no named instance is selected). + * + * [Since 2.9] If `num_coords` is larger than zero, this function sets + * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field + * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, + * this bit flag gets unset. + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_Blend_Coordinates + * + * @description: + * Get the normalized blend coordinates of the currently selected + * interpolated font. + * + * This function works with all supported variation formats. + * + * @input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of normalized blend coordinates to retrieve. If it is + * larger than the number of axes, set the excess values to~0.5 for + * Adobe MM fonts, and to~0 for TrueType GX and OpenType variation + * fonts. + * + * @output: + * coords :: + * The normalized blend coordinates array (as 16.16 fractional values). + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_Var_Blend_Coordinates + * + * @description: + * This is another name of @FT_Set_MM_Blend_Coordinates. + */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Blend_Coordinates + * + * @description: + * This is another name of @FT_Get_MM_Blend_Coordinates. + * + * @since: + * 2.7.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @function: + * FT_Set_MM_WeightVector + * + * @description: + * For Adobe MM fonts, choose an interpolated font design by directly + * setting the weight vector. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * len :: + * The length of the weight vector array. If it is larger than the + * number of designs, the extra values are ignored. If it is less than + * the number of designs, the remaining values are set to zero. + * + * weightvector :: + * An array representing the weight vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the weight vector to 16~elements. + * + * If `len` is larger than zero, this function sets the + * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e., + * @FT_IS_VARIATION will return true). If `len` is zero, this bit flag + * is unset and the weight vector array is reset to the default values. + * + * The Adobe documentation also states that the values in the + * WeightVector array must total 1.0 +/-~0.001. In practice this does + * not seem to be enforced, so is not enforced here, either. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_WeightVector + * + * @description: + * For Adobe MM fonts, retrieve the current weight vector of the font. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * len :: + * A pointer to the size of the array to be filled. If the size of the + * array is less than the number of designs, `FT_Err_Invalid_Argument` + * is returned, and `len` is set to the required size (the number of + * designs). If the size of the array is greater than the number of + * designs, the remaining entries are set to~0. On successful + * completion, `len` is set to the number of designs (i.e., the number + * of values written to the array). + * + * @output: + * weightvector :: + * An array to be filled. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the WeightVector to~16. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + + + /************************************************************************** + * + * @enum: + * FT_VAR_AXIS_FLAG_XXX + * + * @description: + * A list of bit flags used in the return value of + * @FT_Get_Var_Axis_Flags. + * + * @values: + * FT_VAR_AXIS_FLAG_HIDDEN :: + * The variation axis should not be exposed to user interfaces. + * + * @since: + * 2.8.1 + */ +#define FT_VAR_AXIS_FLAG_HIDDEN 1 + + + /************************************************************************** + * + * @function: + * FT_Get_Var_Axis_Flags + * + * @description: + * Get the 'flags' field of an OpenType Variation Axis Record. + * + * Not meaningful for Adobe MM fonts (`*flags` is always zero). + * + * @input: + * master :: + * The variation descriptor. + * + * axis_index :: + * The index of the requested variation axis. + * + * @output: + * flags :: + * The 'flags' field. See @FT_VAR_AXIS_FLAG_XXX for possible values. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.8.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Var_Axis_Flags( FT_MM_Var* master, + FT_UInt axis_index, + FT_UInt* flags ); + + + /************************************************************************** + * + * @function: + * FT_Set_Named_Instance + * + * @description: + * Set or change the current named instance. + * + * @input: + * face :: + * A handle to the source face. + * + * instance_index :: + * The index of the requested instance, starting with value 1. If set + * to value 0, FreeType switches to font access without a named + * instance. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The function uses the value of `instance_index` to set bits 16-30 of + * the face's `face_index` field. It also resets any variation applied + * to the font, and the @FT_FACE_FLAG_VARIATION bit of the face's + * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION will + * return false). + * + * For Adobe MM fonts (which don't have named instances) this function + * simply resets the current face to the default instance. + * + * @since: + * 2.9 + */ + FT_EXPORT( FT_Error ) + FT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ); + + + /************************************************************************** + * + * @function: + * FT_Get_Default_Named_Instance + * + * @description: + * Retrieve the index of the default named instance, to be used with + * @FT_Set_Named_Instance. + * + * The default instance of a variation font is that instance for which + * the nth axis coordinate is equal to `axis[n].def` (as specified in the + * @FT_MM_Var structure), with~n covering all axes. + * + * FreeType synthesizes a named instance for the default instance if the + * font does not contain such an entry. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * instance_index :: + * The index of the default named instance. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For Adobe MM fonts (which don't have named instances) this function + * always returns zero for `instance_index`. + * + * @since: + * 2.13.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + + /* */ + + +FT_END_HEADER + +#endif /* FTMM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftmodapi.h b/Dependencies/freetype/freetype/include/freetype/ftmodapi.h new file mode 100644 index 00000000..0ee71589 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftmodapi.h @@ -0,0 +1,807 @@ +/**************************************************************************** + * + * ftmodapi.h + * + * FreeType modules public interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMODAPI_H_ +#define FTMODAPI_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * module_management + * + * @title: + * Module Management + * + * @abstract: + * How to add, upgrade, remove, and control modules from FreeType. + * + * @description: + * The definitions below are used to manage modules within FreeType. + * Internal and external modules can be added, upgraded, and removed at + * runtime. For example, an alternative renderer or proprietary font + * driver can be registered and prioritized. Additionally, some module + * properties can also be controlled. + * + * Here is a list of existing values of the `module_name` field in the + * @FT_Module_Class structure. + * + * ``` + * autofitter + * bdf + * cff + * gxvalid + * otvalid + * pcf + * pfr + * psaux + * pshinter + * psnames + * raster1 + * sfnt + * smooth + * truetype + * type1 + * type42 + * t1cid + * winfonts + * ``` + * + * Note that the FreeType Cache sub-system is not a FreeType module. + * + * @order: + * FT_Module + * FT_Module_Constructor + * FT_Module_Destructor + * FT_Module_Requester + * FT_Module_Class + * + * FT_Add_Module + * FT_Get_Module + * FT_Remove_Module + * FT_Add_Default_Modules + * + * FT_FACE_DRIVER_NAME + * FT_Property_Set + * FT_Property_Get + * FT_Set_Default_Properties + * + * FT_New_Library + * FT_Done_Library + * FT_Reference_Library + * + * FT_Renderer + * FT_Renderer_Class + * + * FT_Get_Renderer + * FT_Set_Renderer + * + * FT_Set_Debug_Hook + * + */ + + + /* module bit flags */ +#define FT_MODULE_FONT_DRIVER 1 /* this module is a font driver */ +#define FT_MODULE_RENDERER 2 /* this module is a renderer */ +#define FT_MODULE_HINTER 4 /* this module is a glyph hinter */ +#define FT_MODULE_STYLER 8 /* this module is a styler */ + +#define FT_MODULE_DRIVER_SCALABLE 0x100 /* the driver supports */ + /* scalable fonts */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 /* the driver does not */ + /* support vector outlines */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 /* the driver provides its */ + /* own hinter */ +#define FT_MODULE_DRIVER_HINTS_LIGHTLY 0x800 /* the driver's hinter */ + /* produces LIGHT hints */ + + + /* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER + +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER +#define ft_module_driver_hints_lightly FT_MODULE_DRIVER_HINTS_LIGHTLY + + + typedef FT_Pointer FT_Module_Interface; + + + /************************************************************************** + * + * @functype: + * FT_Module_Constructor + * + * @description: + * A function used to initialize (not create) a new module object. + * + * @input: + * module :: + * The module to initialize. + */ + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); + + + /************************************************************************** + * + * @functype: + * FT_Module_Destructor + * + * @description: + * A function used to finalize (not destroy) a given module object. + * + * @input: + * module :: + * The module to finalize. + */ + typedef void + (*FT_Module_Destructor)( FT_Module module ); + + + /************************************************************************** + * + * @functype: + * FT_Module_Requester + * + * @description: + * A function used to query a given module for a specific interface. + * + * @input: + * module :: + * The module to be searched. + * + * name :: + * The name of the interface in the module. + */ + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); + + + /************************************************************************** + * + * @struct: + * FT_Module_Class + * + * @description: + * The module class descriptor. While being a public structure necessary + * for FreeType's module bookkeeping, most of the fields are essentially + * internal, not to be used directly by an application. + * + * @fields: + * module_flags :: + * Bit flags describing the module. + * + * module_size :: + * The size of one module object/instance in bytes. + * + * module_name :: + * The name of the module. + * + * module_version :: + * The version, as a 16.16 fixed number (major.minor). + * + * module_requires :: + * The version of FreeType this module requires, as a 16.16 fixed + * number (major.minor). Starts at version 2.0, i.e., 0x20000. + * + * module_interface :: + * A typeless pointer to a structure (which varies between different + * modules) that holds the module's interface functions. This is + * essentially what `get_interface` returns. + * + * module_init :: + * The initializing function. + * + * module_done :: + * The finalizing function. + * + * get_interface :: + * The interface requesting function. + */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + + const void* module_interface; + + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + + } FT_Module_Class; + + + /************************************************************************** + * + * @function: + * FT_Add_Module + * + * @description: + * Add a new module to a given library instance. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * clazz :: + * A pointer to class descriptor for the module. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An error will be returned if a module already exists by that name, or + * if the module requires a version of FreeType that is too great. + */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); + + + /************************************************************************** + * + * @function: + * FT_Get_Module + * + * @description: + * Find a module by its name. + * + * @input: + * library :: + * A handle to the library object. + * + * module_name :: + * The module's name (as an ASCII string). + * + * @return: + * A module handle. 0~if none was found. + * + * @note: + * FreeType's internal modules aren't documented very well, and you + * should look up the source code for details. + */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); + + + /************************************************************************** + * + * @function: + * FT_Remove_Module + * + * @description: + * Remove a given module from a library instance. + * + * @inout: + * library :: + * A handle to a library object. + * + * @input: + * module :: + * A handle to a module object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The module object is destroyed by the function in case of success. + */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); + + + /************************************************************************** + * + * @macro: + * FT_FACE_DRIVER_NAME + * + * @description: + * A macro that retrieves the name of a font driver from a face object. + * + * @note: + * The font driver name is a valid `module_name` for @FT_Property_Set + * and @FT_Property_Get. This is not the same as @FT_Get_Font_Format. + * + * @since: + * 2.11 + * + */ +#define FT_FACE_DRIVER_NAME( face ) \ + ( ( *FT_REINTERPRET_CAST( FT_Module_Class**, \ + ( face )->driver ) )->module_name ) + + + /************************************************************************** + * + * @function: + * FT_Property_Set + * + * @description: + * Set a property for a given module. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in section + * @properties. + * + * Note that only a few modules have properties. + * + * value :: + * A generic pointer to a variable or structure that gives the new + * value of the property. The exact definition of `value` is + * dependent on the property; see section @properties. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name` isn't a valid module name, or `property_name` + * doesn't specify a valid property, or if `value` doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example sets property 'bar' (a simple integer) in + * module 'foo' to value~1. + * + * ``` + * FT_UInt bar; + * + * + * bar = 1; + * FT_Property_Set( library, "foo", "bar", &bar ); + * ``` + * + * Note that the FreeType Cache sub-system doesn't recognize module + * property changes. To avoid glyph lookup confusion within the cache + * you should call @FTC_Manager_Reset to completely flush the cache if a + * module property gets changed after @FTC_Manager_New has been called. + * + * It is not possible to set properties of the FreeType Cache sub-system + * itself with FT_Property_Set; use @FTC_Property_Set instead. + * + * @since: + * 2.4.11 + * + */ + FT_EXPORT( FT_Error ) + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ); + + + /************************************************************************** + * + * @function: + * FT_Property_Get + * + * @description: + * Get a module's property value. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in section + * @properties. + * + * @inout: + * value :: + * A generic pointer to a variable or structure that gives the value + * of the property. The exact definition of `value` is dependent on + * the property; see section @properties. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name` isn't a valid module name, or `property_name` + * doesn't specify a valid property, or if `value` doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example gets property 'baz' (a range) in module 'foo'. + * + * ``` + * typedef range_ + * { + * FT_Int32 min; + * FT_Int32 max; + * + * } range; + * + * range baz; + * + * + * FT_Property_Get( library, "foo", "baz", &baz ); + * ``` + * + * It is not possible to retrieve properties of the FreeType Cache + * sub-system with FT_Property_Get; use @FTC_Property_Get instead. + * + * @since: + * 2.4.11 + * + */ + FT_EXPORT( FT_Error ) + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Properties + * + * @description: + * If compilation option `FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES` is + * set, this function reads the `FREETYPE_PROPERTIES` environment + * variable to control driver properties. See section @properties for + * more. + * + * If the compilation option is not set, this function does nothing. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=0 + * ``` + * + * @inout: + * library :: + * A handle to a new library object. + * + * @since: + * 2.8 + */ + FT_EXPORT( void ) + FT_Set_Default_Properties( FT_Library library ); + + + /************************************************************************** + * + * @function: + * FT_Reference_Library + * + * @description: + * A counter gets initialized to~1 at the time an @FT_Library structure + * is created. This function increments the counter. @FT_Done_Library + * then only destroys a library if the counter is~1, otherwise it simply + * decrements the counter. + * + * This function helps in managing life-cycles of structures that + * reference @FT_Library objects. + * + * @input: + * library :: + * A handle to a target library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @since: + * 2.4.2 + */ + FT_EXPORT( FT_Error ) + FT_Reference_Library( FT_Library library ); + + + /************************************************************************** + * + * @function: + * FT_New_Library + * + * @description: + * This function is used to create a new FreeType library instance from a + * given memory object. It is thus possible to use libraries with + * distinct memory allocators within the same program. Note, however, + * that the used @FT_Memory structure is expected to remain valid for the + * life of the @FT_Library object. + * + * Normally, you would call this function (followed by a call to + * @FT_Add_Default_Modules or a series of calls to @FT_Add_Module, and a + * call to @FT_Set_Default_Properties) instead of @FT_Init_FreeType to + * initialize the FreeType library. + * + * Don't use @FT_Done_FreeType but @FT_Done_Library to destroy a library + * instance. + * + * @input: + * memory :: + * A handle to the original memory object. + * + * @output: + * alibrary :: + * A pointer to handle of a new library object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Library. + */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); + + + /************************************************************************** + * + * @function: + * FT_Done_Library + * + * @description: + * Discard a given library object. This closes all drivers and discards + * all resource objects. + * + * @input: + * library :: + * A handle to the target library. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * See the discussion of reference counters in the description of + * @FT_Reference_Library. + */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); + + + /************************************************************************** + * + * @functype: + * FT_DebugHook_Func + * + * @description: + * A drop-in replacement (or rather a wrapper) for the bytecode or + * charstring interpreter's main loop function. + * + * Its job is essentially + * + * - to activate debug mode to enforce single-stepping, + * + * - to call the main loop function to interpret the next opcode, and + * + * - to show the changed context to the user. + * + * An example for such a main loop function is `TT_RunIns` (declared in + * FreeType's internal header file `src/truetype/ttinterp.h`). + * + * Have a look at the source code of the `ttdebug` FreeType demo program + * for an example of a drop-in replacement. + * + * @inout: + * arg :: + * A typeless pointer, to be cast to the main loop function's data + * structure (which depends on the font module). For TrueType fonts + * it is bytecode interpreter's execution context, `TT_ExecContext`, + * which is declared in FreeType's internal header file `tttypes.h`. + */ + typedef FT_Error + (*FT_DebugHook_Func)( void* arg ); + + + /************************************************************************** + * + * @enum: + * FT_DEBUG_HOOK_XXX + * + * @description: + * A list of named debug hook indices. + * + * @values: + * FT_DEBUG_HOOK_TRUETYPE:: + * This hook index identifies the TrueType bytecode debugger. + */ +#define FT_DEBUG_HOOK_TRUETYPE 0 + + + /************************************************************************** + * + * @function: + * FT_Set_Debug_Hook + * + * @description: + * Set a debug hook function for debugging the interpreter of a font + * format. + * + * While this is a public API function, an application needs access to + * FreeType's internal header files to do something useful. + * + * Have a look at the source code of the `ttdebug` FreeType demo program + * for an example of its usage. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * hook_index :: + * The index of the debug hook. You should use defined enumeration + * macros like @FT_DEBUG_HOOK_TRUETYPE. + * + * debug_hook :: + * The function used to debug the interpreter. + * + * @note: + * Currently, four debug hook slots are available, but only one (for the + * TrueType interpreter) is defined. + */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); + + + /************************************************************************** + * + * @function: + * FT_Add_Default_Modules + * + * @description: + * Add the set of default drivers to a given library object. This is + * only useful when you create a library object with @FT_New_Library + * (usually to plug a custom memory manager). + * + * @inout: + * library :: + * A handle to a new library object. + */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); + + + + /************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode engine is + * implemented in a given FT_Library instance. It is used by the + * @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * Deprecated and removed. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers the full + * instruction set of the TrueType virtual machine (this was governed + * by patents until May 2010, hence the name). + * + * @since: + * 2.2 + * + */ + typedef enum FT_TrueTypeEngineType_ + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + + } FT_TrueTypeEngineType; + + + /************************************************************************** + * + * @function: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return an @FT_TrueTypeEngineType value to indicate which level of the + * TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); + + /* */ + + +FT_END_HEADER + +#endif /* FTMODAPI_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftmoderr.h b/Dependencies/freetype/freetype/include/freetype/ftmoderr.h new file mode 100644 index 00000000..6722fbf8 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftmoderr.h @@ -0,0 +1,204 @@ +/**************************************************************************** + * + * ftmoderr.h + * + * FreeType module error offsets (specification). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the FreeType module error codes. + * + * If the macro `FT_CONFIG_OPTION_USE_MODULE_ERRORS` in `ftoption.h` is + * set, the lower byte of an error value identifies the error code as + * usual. In addition, the higher byte identifies the module. For + * example, the error `FT_Err_Invalid_File_Format` has value 0x0003, the + * error `TT_Err_Invalid_File_Format` has value 0x1303, the error + * `T1_Err_Invalid_File_Format` has value 0x1403, etc. + * + * Note that `FT_Err_Ok`, `TT_Err_Ok`, etc. are always equal to zero, + * including the high byte. + * + * If `FT_CONFIG_OPTION_USE_MODULE_ERRORS` isn't set, the higher byte of an + * error value is set to zero. + * + * To hide the various `XXX_Err_` prefixes in the source code, FreeType + * provides some macros in `fttypes.h`. + * + * FT_ERR( err ) + * + * Add current error module prefix (as defined with the `FT_ERR_PREFIX` + * macro) to `err`. For example, in the BDF module the line + * + * ``` + * error = FT_ERR( Invalid_Outline ); + * ``` + * + * expands to + * + * ``` + * error = BDF_Err_Invalid_Outline; + * ``` + * + * For simplicity, you can always use `FT_Err_Ok` directly instead of + * `FT_ERR( Ok )`. + * + * FT_ERR_EQ( errcode, err ) + * FT_ERR_NEQ( errcode, err ) + * + * Compare error code `errcode` with the error `err` for equality and + * inequality, respectively. Example: + * + * ``` + * if ( FT_ERR_EQ( error, Invalid_Outline ) ) + * ... + * ``` + * + * Using this macro you don't have to think about error prefixes. Of + * course, if module errors are not active, the above example is the + * same as + * + * ``` + * if ( error == FT_Err_Invalid_Outline ) + * ... + * ``` + * + * FT_ERROR_BASE( errcode ) + * FT_ERROR_MODULE( errcode ) + * + * Get base error and module error code, respectively. + * + * It can also be used to create a module error message table easily with + * something like + * + * ``` + * #undef FTMODERR_H_ + * #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, + * #define FT_MODERR_START_LIST { + * #define FT_MODERR_END_LIST { 0, 0 } }; + * + * const struct + * { + * int mod_err_offset; + * const char* mod_err_msg + * } ft_mod_errors[] = + * + * #include + * ``` + * + */ + + +#ifndef FTMODERR_H_ +#define FTMODERR_H_ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** SETUP MACROS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#undef FT_NEED_EXTERN_C + +#ifndef FT_MODERRDEF + +#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v, +#else +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#endif + +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; + +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif + +#endif /* !FT_MODERRDEF */ + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** LIST MODULE ERROR BASES *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + + + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Bzip2, 0x300, "Bzip2 module" ) + FT_MODERRDEF( Cache, 0x400, "cache module" ) + FT_MODERRDEF( CFF, 0x500, "CFF module" ) + FT_MODERRDEF( CID, 0x600, "CID module" ) + FT_MODERRDEF( Gzip, 0x700, "Gzip module" ) + FT_MODERRDEF( LZW, 0x800, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x900, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0xA00, "PCF module" ) + FT_MODERRDEF( PFR, 0xB00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xC00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xD00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xE00, "PS names module" ) + FT_MODERRDEF( Raster, 0xF00, "raster module" ) + FT_MODERRDEF( SFNT, 0x1000, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1100, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1200, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1300, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1400, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) + FT_MODERRDEF( GXvalid, 0x1600, "GX validation module" ) + FT_MODERRDEF( Sdf, 0x1700, "Signed distance field raster module" ) + + +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** CLEANUP *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + +#ifdef FT_NEED_EXTERN_C + } +#endif + +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C + + +#endif /* FTMODERR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftotval.h b/Dependencies/freetype/freetype/include/freetype/ftotval.h new file mode 100644 index 00000000..810200b3 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftotval.h @@ -0,0 +1,206 @@ +/**************************************************************************** + * + * ftotval.h + * + * FreeType API for validating OpenType tables (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/**************************************************************************** + * + * + * Warning: This module might be moved to a different library in the + * future to avoid a tight dependency between FreeType and the + * OpenType specification. + * + * + */ + + +#ifndef FTOTVAL_H_ +#define FTOTVAL_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * ot_validation + * + * @title: + * OpenType Validation + * + * @abstract: + * An API to validate OpenType tables. + * + * @description: + * This section contains the declaration of functions to validate some + * OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + * @order: + * FT_OpenType_Validate + * FT_OpenType_Free + * + * FT_VALIDATE_OTXXX + * + */ + + + /************************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_MATH :: + * Validate MATH table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 +#define FT_VALIDATE_MATH 0x2000 + +#define FT_VALIDATE_OT ( FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF | \ + FT_VALIDATE_MATH ) + + + /************************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library that + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field that specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A `NULL` value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + + /************************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTOTVAL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftoutln.h b/Dependencies/freetype/freetype/include/freetype/ftoutln.h new file mode 100644 index 00000000..44e94b4f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftoutln.h @@ -0,0 +1,588 @@ +/**************************************************************************** + * + * ftoutln.h + * + * Support for the FT_Outline type used to store glyph shapes of + * most scalable font formats (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTOUTLN_H_ +#define FTOUTLN_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * outline_processing + * + * @title: + * Outline Processing + * + * @abstract: + * Functions to create, transform, and render vectorial glyph images. + * + * @description: + * This section contains routines used to create and destroy scalable + * glyph images known as 'outlines'. These can also be measured, + * transformed, and converted into bitmaps and pixmaps. + * + * @order: + * FT_Outline + * FT_Outline_New + * FT_Outline_Done + * FT_Outline_Copy + * FT_Outline_Translate + * FT_Outline_Transform + * FT_Outline_Embolden + * FT_Outline_EmboldenXY + * FT_Outline_Reverse + * FT_Outline_Check + * + * FT_Outline_Get_CBox + * FT_Outline_Get_BBox + * + * FT_Outline_Get_Bitmap + * FT_Outline_Render + * FT_Outline_Decompose + * FT_Outline_Funcs + * FT_Outline_MoveToFunc + * FT_Outline_LineToFunc + * FT_Outline_ConicToFunc + * FT_Outline_CubicToFunc + * + * FT_Orientation + * FT_Outline_Get_Orientation + * + * FT_OUTLINE_XXX + * + */ + + + /************************************************************************** + * + * @function: + * FT_Outline_Decompose + * + * @description: + * Walk over an outline's structure to decompose it into individual + * segments and Bezier arcs. This function also emits 'move to' + * operations to indicate the start of new contours in the outline. + * + * @input: + * outline :: + * A pointer to the source target. + * + * func_interface :: + * A table of 'emitters', i.e., function pointers called during + * decomposition to indicate path operations. + * + * @inout: + * user :: + * A typeless pointer that is passed to each emitter during the + * decomposition. It can be used to store the state during the + * decomposition. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Degenerate contours, segments, and Bezier arcs may be reported. In + * most cases, it is best to filter these out before using the outline + * for stroking or other path modification purposes (which may cause + * degenerate segments to become non-degenerate and visible, like when + * stroke caps are used or the path is otherwise outset). Some glyph + * outlines may contain deliberate degenerate single points for mark + * attachement. + * + * Similarly, the function returns success for an empty outline also + * (doing nothing, that is, not calling any emitter); if necessary, you + * should filter this out, too. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); + + + /************************************************************************** + * + * @function: + * FT_Outline_New + * + * @description: + * Create a new outline of a given size. + * + * @input: + * library :: + * A handle to the library object from where the outline is allocated. + * Note however that the new outline will **not** necessarily be + * **freed**, when destroying the library, by @FT_Done_FreeType. + * + * numPoints :: + * The maximum number of points within the outline. Must be smaller + * than or equal to 0xFFFF (65535). + * + * numContours :: + * The maximum number of contours within the outline. This value must + * be in the range 0 to `numPoints`. + * + * @output: + * anoutline :: + * A handle to the new outline. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The reason why this function takes a `library` parameter is simply to + * use the library's memory allocator. + */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Done + * + * @description: + * Destroy an outline created with @FT_Outline_New. + * + * @input: + * library :: + * A handle of the library object used to allocate the outline. + * + * outline :: + * A pointer to the outline object to be discarded. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the outline's 'owner' field is not set, only the outline descriptor + * will be released. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Check + * + * @description: + * Check the contents of an outline descriptor. + * + * @input: + * outline :: + * A handle to a source outline. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * An empty outline, or an outline with a single point only is also + * valid. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_CBox + * + * @description: + * Return an outline's 'control box'. The control box encloses all the + * outline's points, including Bezier control points. Though it + * coincides with the exact bounding box for most glyphs, it can be + * slightly larger in some situations (like when rotating an outline that + * contains Bezier outside arcs). + * + * Computing the control box is very fast, while getting the bounding box + * can take much more time as it needs to walk over all segments and arcs + * in the outline. To get the latter, you can use the 'ftbbox' + * component, which is dedicated to this single task. + * + * @input: + * outline :: + * A pointer to the source outline descriptor. + * + * @output: + * acbox :: + * The outline's control box. + * + * @note: + * See @FT_Glyph_Get_CBox for a discussion of tricky fonts. + */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Translate + * + * @description: + * Apply a simple translation to the points of an outline. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @input: + * xOffset :: + * The horizontal offset. + * + * yOffset :: + * The vertical offset. + */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Copy + * + * @description: + * Copy an outline into another one. Both objects must have the same + * sizes (number of points & number of contours) when this function is + * called. + * + * @input: + * source :: + * A handle to the source outline. + * + * @output: + * target :: + * A handle to the target outline. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Transform + * + * @description: + * Apply a simple 2x2 matrix to all of an outline's points. Useful for + * applying rotations, slanting, flipping, etc. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @input: + * matrix :: + * A pointer to the transformation matrix. + * + * @note: + * You can use @FT_Outline_Translate if you need to translate the + * outline's points. + */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Embolden + * + * @description: + * Embolden an outline. The new outline will be at most 4~times + * `strength` pixels wider and higher. You may think of the left and + * bottom borders as unchanged. + * + * Negative `strength` values to reduce the outline thickness are + * possible also. + * + * @inout: + * outline :: + * A handle to the target outline. + * + * @input: + * strength :: + * How strong the glyph is emboldened. Expressed in 26.6 pixel format. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The used algorithm to increase or decrease the thickness of the glyph + * doesn't change the number of points; this means that certain + * situations like acute angles or intersections are sometimes handled + * incorrectly. + * + * If you need 'better' metrics values you should call + * @FT_Outline_Get_CBox or @FT_Outline_Get_BBox. + * + * To get meaningful results, font scaling values must be set with + * functions like @FT_Set_Char_Size before calling FT_Render_Glyph. + * + * @example: + * ``` + * FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); + * + * if ( face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) + * FT_Outline_Embolden( &face->glyph->outline, strength ); + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); + + + /************************************************************************** + * + * @function: + * FT_Outline_EmboldenXY + * + * @description: + * Embolden an outline. The new outline will be `xstrength` pixels wider + * and `ystrength` pixels higher. Otherwise, it is similar to + * @FT_Outline_Embolden, which uses the same strength in both directions. + * + * @since: + * 2.4.10 + */ + FT_EXPORT( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Reverse + * + * @description: + * Reverse the drawing direction of an outline. This is used to ensure + * consistent fill conventions for mirrored glyphs. + * + * @inout: + * outline :: + * A pointer to the target outline descriptor. + * + * @note: + * This function toggles the bit flag @FT_OUTLINE_REVERSE_FILL in the + * outline's `flags` field. + * + * It shouldn't be used by a normal client application, unless it knows + * what it is doing. + */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Bitmap + * + * @description: + * Render an outline within a bitmap. The outline's image is simply + * OR-ed to the target bitmap. + * + * @input: + * library :: + * A handle to a FreeType library object. + * + * outline :: + * A pointer to the source outline descriptor. + * + * @inout: + * abitmap :: + * A pointer to the target bitmap descriptor. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function does **not create** the bitmap, it only renders an + * outline image within the one you pass to it! Consequently, the + * various fields in `abitmap` should be set accordingly. + * + * It will use the raster corresponding to the default glyph format. + * + * The value of the `num_grays` field in `abitmap` is ignored. If you + * select the gray-level rasterizer, and you want less than 256 gray + * levels, you have to use @FT_Outline_Render directly. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); + + + /************************************************************************** + * + * @function: + * FT_Outline_Render + * + * @description: + * Render an outline within a bitmap using the current scan-convert. + * + * @input: + * library :: + * A handle to a FreeType library object. + * + * outline :: + * A pointer to the source outline descriptor. + * + * @inout: + * params :: + * A pointer to an @FT_Raster_Params structure used to describe the + * rendering operation. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This advanced function uses @FT_Raster_Params as an argument. + * The field `params.source` will be set to `outline` before the scan + * converter is called, which means that the value you give to it is + * actually ignored. Either `params.target` must point to preallocated + * bitmap, or @FT_RASTER_FLAG_DIRECT must be set in `params.flags` + * allowing FreeType rasterizer to be used for direct composition, + * translucency, etc. See @FT_Raster_Params for more details. + */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); + + + /************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and PostScript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must be + * filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the PostScript specification, counter-clockwise + * contours must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of the + * drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in PostScript, everything that is to the left of the + * drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum FT_Orientation_ + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + + } FT_Orientation; + + + /************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its fill + * orientation (see @FT_Orientation). This is done by integrating the + * total area covered by the outline. The positive integral corresponds + * to the clockwise orientation and @FT_ORIENTATION_POSTSCRIPT is + * returned. The negative integral corresponds to the counter-clockwise + * orientation and @FT_ORIENTATION_TRUETYPE is returned. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTOUTLN_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftparams.h b/Dependencies/freetype/freetype/include/freetype/ftparams.h new file mode 100644 index 00000000..43bf69c2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftparams.h @@ -0,0 +1,218 @@ +/**************************************************************************** + * + * ftparams.h + * + * FreeType API for possible FT_Parameter tags (specification only). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPARAMS_H_ +#define FTPARAMS_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * parameter_tags + * + * @title: + * Parameter Tags + * + * @abstract: + * Macros for driver property and font loading parameter tags. + * + * @description: + * This section contains macros for the @FT_Parameter structure that are + * used with various functions to activate some special functionality or + * different behaviour of various components of FreeType. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore typographic + * family names in the 'name' table (introduced in OpenType version 1.4). + * Use this for backward compatibility with legacy systems that have a + * four-faces-per-family restriction. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY \ + FT_MAKE_TAG( 'i', 'g', 'p', 'f' ) + + + /* this constant is deprecated */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY \ + FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore typographic + * subfamily names in the 'name' table (introduced in OpenType version + * 1.4). Use this for backward compatibility with legacy systems that + * have a four-faces-per-family restriction. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY \ + FT_MAKE_TAG( 'i', 'g', 'p', 's' ) + + + /* this constant is deprecated */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY \ + FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * An @FT_Parameter tag to be used with @FT_Open_Face to indicate + * incremental glyph loading. + * + */ +#define FT_PARAM_TAG_INCREMENTAL \ + FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_SBIX + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore an 'sbix' table + * while loading a font. Use this if @FT_FACE_FLAG_SBIX is set and you + * want to access the outline glyphs in the font. + * + */ +#define FT_PARAM_TAG_IGNORE_SBIX \ + FT_MAKE_TAG( 'i', 's', 'b', 'x' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_LCD_FILTER_WEIGHTS + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding argument specifies the five LCD filter weights for a + * given face (if using @FT_LOAD_TARGET_LCD, for example), overriding the + * global default values or the values set up with + * @FT_Library_SetLcdFilterWeights. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_LCD_FILTER_WEIGHTS \ + FT_MAKE_TAG( 'l', 'c', 'd', 'f' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_RANDOM_SEED + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding 32bit signed integer argument overrides the font + * driver's random seed value with a face-specific one; see @random-seed. + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_RANDOM_SEED \ + FT_MAKE_TAG( 's', 'e', 'e', 'd' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_STEM_DARKENING + * + * @description: + * An @FT_Parameter tag to be used with @FT_Face_Properties. The + * corresponding Boolean argument specifies whether to apply stem + * darkening, overriding the global default values or the values set up + * with @FT_Property_Set (see @no-stem-darkening). + * + * This is a passive setting that only takes effect if the font driver or + * autohinter honors it, which the CFF, Type~1, and CID drivers always + * do, but the autohinter only in 'light' hinting mode (as of version + * 2.9). + * + * @since: + * 2.8 + * + */ +#define FT_PARAM_TAG_STEM_DARKENING \ + FT_MAKE_TAG( 'd', 'a', 'r', 'k' ) + + + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_UNPATENTED_HINTING + * + * @description: + * Deprecated, no effect. + * + * Previously: A constant used as the tag of an @FT_Parameter structure + * to indicate that unpatented methods only should be used by the + * TrueType bytecode interpreter for a typeface opened by @FT_Open_Face. + * + */ +#define FT_PARAM_TAG_UNPATENTED_HINTING \ + FT_MAKE_TAG( 'u', 'n', 'p', 'a' ) + + + /* */ + + +FT_END_HEADER + + +#endif /* FTPARAMS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftpfr.h b/Dependencies/freetype/freetype/include/freetype/ftpfr.h new file mode 100644 index 00000000..1a712b95 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftpfr.h @@ -0,0 +1,179 @@ +/**************************************************************************** + * + * ftpfr.h + * + * FreeType API for accessing PFR-specific data (specification only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPFR_H_ +#define FTPFR_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * pfr_fonts + * + * @title: + * PFR Fonts + * + * @abstract: + * PFR/TrueDoc-specific API. + * + * @description: + * This section contains the declaration of PFR-specific functions. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: + * Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM` for + * non-PFR fonts. Optional (parameter can be `NULL`). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution` for + * non-PFR fonts. Optional (parameter can be `NULL`). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed in + * metrics units to device subpixels. This is equivalent to + * `face->size->x_scale`, but for metrics only. Optional (parameter + * can be `NULL`). + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale` but for the vertical direction. + * optional (parameter can be `NULL`). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: + * A handle to the input face. + * + * left :: + * Index of the left glyph. + * + * right :: + * Index of the right glyph. + * + * @output: + * avector :: + * A kerning vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always return distances in original PFR metrics units. + * This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED mode, + * which always returns distances converted to outline units. + * + * You can use the value of the `x_scale` and `y_scale` parameters + * returned by @FT_Get_PFR_Metrics to scale these to device subpixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + + /************************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: + * A handle to the input face. + * + * gindex :: + * The glyph index. + * + * @output: + * aadvance :: + * The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You can use the `x_scale` or `y_scale` results of @FT_Get_PFR_Metrics + * to convert the advance to device subpixels (i.e., 1/64 of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + /* */ + + +FT_END_HEADER + +#endif /* FTPFR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftrender.h b/Dependencies/freetype/freetype/include/freetype/ftrender.h new file mode 100644 index 00000000..dc5018a1 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftrender.h @@ -0,0 +1,244 @@ +/**************************************************************************** + * + * ftrender.h + * + * FreeType renderer modules public interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTRENDER_H_ +#define FTRENDER_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * module_management + * + */ + + + /* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + + /* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); + +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + + + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + + + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ); + + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + + + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + + + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); + +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc + + + /************************************************************************** + * + * @struct: + * FT_Renderer_Class + * + * @description: + * The renderer module class descriptor. + * + * @fields: + * root :: + * The root @FT_Module_Class fields. + * + * glyph_format :: + * The glyph image format this renderer handles. + * + * render_glyph :: + * A method used to render the image that is in a given glyph slot into + * a bitmap. + * + * transform_glyph :: + * A method used to transform the image that is in a given glyph slot. + * + * get_glyph_cbox :: + * A method used to access the glyph's cbox. + * + * set_mode :: + * A method used to pass additional parameters. + * + * raster_class :: + * For @FT_GLYPH_FORMAT_OUTLINE renderers only. This is a pointer to + * its raster's class. + */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + + FT_Glyph_Format glyph_format; + + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + + const FT_Raster_Funcs* raster_class; + + } FT_Renderer_Class; + + + /************************************************************************** + * + * @function: + * FT_Get_Renderer + * + * @description: + * Retrieve the current renderer for a given glyph format. + * + * @input: + * library :: + * A handle to the library object. + * + * format :: + * The glyph format. + * + * @return: + * A renderer handle. 0~if none found. + * + * @note: + * An error will be returned if a module already exists by that name, or + * if the module requires a version of FreeType that is too great. + * + * To add a new renderer, simply use @FT_Add_Module. To retrieve a + * renderer by its name, use @FT_Get_Module. + */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); + + + /************************************************************************** + * + * @function: + * FT_Set_Renderer + * + * @description: + * Set the current renderer to use, and set additional mode. + * + * @inout: + * library :: + * A handle to the library object. + * + * @input: + * renderer :: + * A handle to the renderer object. + * + * num_params :: + * The number of additional parameters. + * + * parameters :: + * Additional parameters. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * In case of success, the renderer will be used to convert glyph images + * in the renderer's known format into bitmaps. + * + * This doesn't change the current renderer for other formats. + * + * Currently, no FreeType renderer module uses `parameters`; you should + * thus always pass `NULL` as the value. + */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); + + /* */ + + +FT_END_HEADER + +#endif /* FTRENDER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftsizes.h b/Dependencies/freetype/freetype/include/freetype/ftsizes.h new file mode 100644 index 00000000..4ef5c795 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftsizes.h @@ -0,0 +1,159 @@ +/**************************************************************************** + * + * ftsizes.h + * + * FreeType size objects management (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * Typical application would normally not need to use these functions. + * However, they have been placed in a public API for the rare cases where + * they are needed. + * + */ + + +#ifndef FTSIZES_H_ +#define FTSIZES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * sizes_management + * + * @title: + * Size Management + * + * @abstract: + * Managing multiple sizes per face. + * + * @description: + * When creating a new face object (e.g., with @FT_New_Face), an @FT_Size + * object is automatically created and used to store all pixel-size + * dependent information, available in the `face->size` field. + * + * It is however possible to create more sizes for a given face, mostly + * in order to manage several character pixel sizes of the same font + * family and style. See @FT_New_Size and @FT_Done_Size. + * + * Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only modify the + * contents of the current 'active' size; you thus need to use + * @FT_Activate_Size to change it. + * + * 99% of applications won't need the functions provided here, especially + * if they use the caching sub-system, so be cautious when using these. + * + */ + + + /************************************************************************** + * + * @function: + * FT_New_Size + * + * @description: + * Create a new size object from a given face object. + * + * @input: + * face :: + * A handle to a parent face object. + * + * @output: + * asize :: + * A handle to a new size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You need to call @FT_Activate_Size in order to select the new size for + * upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, + * @FT_Load_Glyph, @FT_Load_Char, etc. + */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); + + + /************************************************************************** + * + * @function: + * FT_Done_Size + * + * @description: + * Discard a given size object. Note that @FT_Done_Face automatically + * discards all size objects allocated with @FT_New_Size. + * + * @input: + * size :: + * A handle to a target size object. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); + + + /************************************************************************** + * + * @function: + * FT_Activate_Size + * + * @description: + * Even though it is possible to create several size objects for a given + * face (see @FT_New_Size for details), functions like @FT_Load_Glyph or + * @FT_Load_Char only use the one that has been activated last to + * determine the 'current character pixel size'. + * + * This function can be used to 'activate' a previously created size + * object. + * + * @input: + * size :: + * A handle to a target size object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `face` is the size's parent face object, this function changes the + * value of `face->size` to the input size handle. + */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); + + /* */ + + +FT_END_HEADER + +#endif /* FTSIZES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftsnames.h b/Dependencies/freetype/freetype/include/freetype/ftsnames.h new file mode 100644 index 00000000..d5d5cd93 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftsnames.h @@ -0,0 +1,272 @@ +/**************************************************************************** + * + * ftsnames.h + * + * Simple interface to access SFNT 'name' tables (which are used + * to hold font names, copyright info, notices, etc.) (specification). + * + * This is _not_ used to retrieve glyph names! + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSNAMES_H_ +#define FTSNAMES_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * sfnt_names + * + * @title: + * SFNT Names + * + * @abstract: + * Access the names embedded in TrueType and OpenType files. + * + * @description: + * The TrueType and OpenType specifications allow the inclusion of a + * special names table ('name') in font files. This table contains + * textual (and internationalized) information regarding the font, like + * family name, copyright, version, etc. + * + * The definitions below are used to access them if available. + * + * Note that this has nothing to do with glyph names! + * + */ + + + /************************************************************************** + * + * @struct: + * FT_SfntName + * + * @description: + * A structure used to model an SFNT 'name' table entry. + * + * @fields: + * platform_id :: + * The platform ID for `string`. See @TT_PLATFORM_XXX for possible + * values. + * + * encoding_id :: + * The encoding ID for `string`. See @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, + * @TT_ISO_ID_XXX, @TT_MS_ID_XXX, and @TT_ADOBE_ID_XXX for possible + * values. + * + * language_id :: + * The language ID for `string`. See @TT_MAC_LANGID_XXX and + * @TT_MS_LANGID_XXX for possible values. + * + * Registered OpenType values for `language_id` are always smaller than + * 0x8000; values equal or larger than 0x8000 usually indicate a + * language tag string (introduced in OpenType version 1.6). Use + * function @FT_Get_Sfnt_LangTag with `language_id` as its argument to + * retrieve the associated language tag. + * + * name_id :: + * An identifier for `string`. See @TT_NAME_ID_XXX for possible + * values. + * + * string :: + * The 'name' string. Note that its format differs depending on the + * (platform,encoding) pair, being either a string of bytes (without a + * terminating `NULL` byte) or containing UTF-16BE entities. + * + * string_len :: + * The length of `string` in bytes. + * + * @note: + * Please refer to the TrueType or OpenType specification for more + * details. + */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; + + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntName; + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Name_Count + * + * @description: + * Retrieve the number of name strings in the SFNT 'name' table. + * + * @input: + * face :: + * A handle to the source face. + * + * @return: + * The number of strings in the 'name' table. + * + * @note: + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Name + * + * @description: + * Retrieve a string of the SFNT 'name' table for a given index. + * + * @input: + * face :: + * A handle to the source face. + * + * idx :: + * The index of the 'name' string. + * + * @output: + * aname :: + * The indexed @FT_SfntName structure. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `string` array returned in the `aname` structure is not + * null-terminated. Note that you don't have to deallocate `string` by + * yourself; FreeType takes care of it if you call @FT_Done_Face. + * + * Use @FT_Get_Sfnt_Name_Count to get the total number of available + * 'name' table entries, then do a loop until you get the right platform, + * encoding, and name ID. + * + * 'name' table format~1 entries can use language tags also, see + * @FT_Get_Sfnt_LangTag. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); + + + /************************************************************************** + * + * @struct: + * FT_SfntLangTag + * + * @description: + * A structure to model a language tag entry from an SFNT 'name' table. + * + * @fields: + * string :: + * The language tag string, encoded in UTF-16BE (without trailing + * `NULL` bytes). + * + * string_len :: + * The length of `string` in **bytes**. + * + * @note: + * Please refer to the TrueType or OpenType specification for more + * details. + * + * @since: + * 2.8 + */ + typedef struct FT_SfntLangTag_ + { + FT_Byte* string; /* this string is *not* null-terminated! */ + FT_UInt string_len; /* in bytes */ + + } FT_SfntLangTag; + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_LangTag + * + * @description: + * Retrieve the language tag associated with a language ID of an SFNT + * 'name' table entry. + * + * @input: + * face :: + * A handle to the source face. + * + * langID :: + * The language ID, as returned by @FT_Get_Sfnt_Name. This is always a + * value larger than 0x8000. + * + * @output: + * alangTag :: + * The language tag associated with the 'name' table entry's language + * ID. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The `string` array returned in the `alangTag` structure is not + * null-terminated. Note that you don't have to deallocate `string` by + * yourself; FreeType takes care of it if you call @FT_Done_Face. + * + * Only 'name' table format~1 supports language tags. For format~0 + * tables, this function always returns FT_Err_Invalid_Table. For + * invalid format~1 language ID values, FT_Err_Invalid_Argument is + * returned. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_SFNT_NAMES` is not defined in `ftoption.h`. + * + * @since: + * 2.8 + */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ); + + + /* */ + + +FT_END_HEADER + +#endif /* FTSNAMES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftstroke.h b/Dependencies/freetype/freetype/include/freetype/ftstroke.h new file mode 100644 index 00000000..41626dc9 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftstroke.h @@ -0,0 +1,773 @@ +/**************************************************************************** + * + * ftstroke.h + * + * FreeType path stroker (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSTROKE_H_ +#define FTSTROKE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial glyph. + * It also allows you to retrieve the 'outside' and/or the 'inside' + * borders of the stroke. + * + * This can be useful to generate 'bordered' glyph, i.e., glyphs + * displayed with a colored (and anti-aliased) border around their + * shape. + * + * @order: + * FT_Stroker + * + * FT_Stroker_LineJoin + * FT_Stroker_LineCap + * FT_StrokerBorder + * + * FT_Outline_GetInsideBorder + * FT_Outline_GetOutsideBorder + * + * FT_Glyph_Stroke + * FT_Glyph_StrokeBorder + * + * FT_Stroker_New + * FT_Stroker_Set + * FT_Stroker_Rewind + * FT_Stroker_ParseOutline + * FT_Stroker_Done + * + * FT_Stroker_BeginSubPath + * FT_Stroker_EndSubPath + * + * FT_Stroker_LineTo + * FT_Stroker_ConicTo + * FT_Stroker_CubicTo + * + * FT_Stroker_GetBorderCounts + * FT_Stroker_ExportBorder + * FT_Stroker_GetCounts + * FT_Stroker_Export + * + */ + + + /************************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handle to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; + + + /************************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered in a + * stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used to join + * two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins. The outer corner of the joined + * lines is filled by enclosing the triangular region of the corner + * with a straight line between the outer corners of each stroke. + * + * FT_STROKER_LINEJOIN_MITER_FIXED :: + * Used to render mitered line joins, with fixed bevels if the miter + * limit is exceeded. The outer edges of the strokes for the two + * segments are extended until they meet at an angle. A bevel join + * (see above) is used if the segments meet at too sharp an angle and + * the outer edges meet beyond a distance corresponding to the meter + * limit. This prevents long spikes being created. + * `FT_STROKER_LINEJOIN_MITER_FIXED` generates a miter line join as + * used in PostScript and PDF. + * + * FT_STROKER_LINEJOIN_MITER_VARIABLE :: + * FT_STROKER_LINEJOIN_MITER :: + * Used to render mitered line joins, with variable bevels if the miter + * limit is exceeded. The intersection of the strokes is clipped + * perpendicularly to the bisector, at a distance corresponding to + * the miter limit. This prevents long spikes being created. + * `FT_STROKER_LINEJOIN_MITER_VARIABLE` generates a mitered line join + * as used in XPS. `FT_STROKER_LINEJOIN_MITER` is an alias for + * `FT_STROKER_LINEJOIN_MITER_VARIABLE`, retained for backward + * compatibility. + */ + typedef enum FT_Stroker_LineJoin_ + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL = 1, + FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, + FT_STROKER_LINEJOIN_MITER = FT_STROKER_LINEJOIN_MITER_VARIABLE, + FT_STROKER_LINEJOIN_MITER_FIXED = 3 + + } FT_Stroker_LineJoin; + + + /************************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are rendered in + * a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last point + * itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the last point. + */ + typedef enum FT_Stroker_LineCap_ + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + + } FT_Stroker_LineCap; + + + /************************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border in + * @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the 'inside' and 'outside' + * borders. However, there is no direct mapping between these and the + * 'left' and 'right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum FT_StrokerBorder_ + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + + /************************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the 'inside' + * borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_RIGHT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the 'outside' + * borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. `NULL` in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The maximum reciprocal sine of half-angle at the miter join, + * expressed as 16.16 fixed-point value. + * + * @note: + * The `radius` is expressed in the same units as the outline + * coordinates. + * + * The `miter_limit` multiplied by the `radius` gives the maximum size + * of a miter spike, at which it is clipped for + * @FT_STROKER_LINEJOIN_MITER_VARIABLE or replaced with a bevel join for + * @FT_STROKER_LINEJOIN_MITER_FIXED. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. You should + * call this function before beginning a new series of calls to + * @FT_Stroker_BeginSubPath or @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with the stroker. + * The resulting outline(s) can be retrieved later by functions like + * @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If~1, the outline is treated as an open path instead of + * a closed one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened` is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct 'border' outlines. + * + * If `opened` is~1, the outline is processed as an open path, and the + * stroker generates a single 'stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If~1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is useful when you need to stroke a path that is not + * stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. If the + * subpath was not 'opened', this function 'draws' a single line segment + * to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * 'Draw' a single line segment in the stroker's current sub-path, from + * the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * 'Draw' a single quadratic Bezier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a Bezier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * 'Draw' a single cubic Bezier in the stroker's current sub-path, from + * the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first Bezier control point. + * + * control2 :: + * A pointer to second Bezier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths with the + * stroker. It returns the number of points and contours necessary to + * export one of the 'border' or 'stroke' outlines generated by the + * stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When an outline, or a sub-path, is 'closed', the stroker generates two + * independent 'border' outlines, named 'left' and 'right'. + * + * When the outline, or a sub-path, is 'opened', the stroker merges the + * 'border' outlines with caps. The 'left' border receives all points, + * while the 'right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to retrieve + * the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to export the + * corresponding border to your own @FT_Outline structure. + * + * Note that this function appends the border points and contours to your + * outline, but does not try to resize its arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to get + * sure that there is enough room in your @FT_Outline object to receive + * all new data. + * + * When an outline, or a sub-path, is 'closed', the stroker generates two + * independent 'border' outlines, named 'left' and 'right'. + * + * When the outline, or a sub-path, is 'opened', the stroker merges the + * 'border' outlines with caps. The 'left' border receives all points, + * while the 'right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to retrieve + * all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths with the + * stroker. It returns the number of points and contours necessary to + * export all points/borders from the stroked outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to export all + * borders to your own @FT_Outline structure. + * + * Note that this function appends the border points and contours to your + * outline, but does not try to resize its arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); + + + /************************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be `NULL`. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts to + * account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); + + + /************************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but only + * return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If~1, return the inside border, otherwise the outside + * border. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts to + * account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); + + /* */ + +FT_END_HEADER + +#endif /* FTSTROKE_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftsynth.h b/Dependencies/freetype/freetype/include/freetype/ftsynth.h new file mode 100644 index 00000000..43081b6c --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftsynth.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * ftsynth.h + * + * FreeType synthesizing code for emboldening and slanting + * (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS ALPHA CODE! THIS API *********/ + /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ + /********* FREETYPE DEVELOPMENT TEAM *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Main reason for not lifting the functions in this module to a */ + /* 'standard' API is that the used parameters for emboldening and */ + /* slanting are not configurable. Consider the functions as a */ + /* code resource that should be copied into the application and */ + /* adapted to the particular needs. */ + + +#ifndef FTSYNTH_H_ +#define FTSYNTH_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /* Embolden a glyph by a 'reasonable' value (which is highly a matter of */ + /* taste). This function is actually a convenience function, providing */ + /* a wrapper for @FT_Outline_Embolden and @FT_Bitmap_Embolden. */ + /* */ + /* For emboldened outlines the height, width, and advance metrics are */ + /* increased by the strength of the emboldening -- this even affects */ + /* mono-width fonts! */ + /* */ + /* You can also call @FT_Outline_Get_CBox to get precise values. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); + + /* Precisely adjust the glyph weight either horizontally or vertically. */ + /* The `xdelta` and `ydelta` values are fractions of the face Em size */ + /* (in fixed-point format). Considering that a regular face would have */ + /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should */ + /* be very noticeable. To increase or decrease the weight, use positive */ + /* or negative values, respectively. */ + FT_EXPORT( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ); + + + /* Slant an outline glyph to the right by about 12 degrees. */ + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + + /* Slant an outline glyph by a given sine of an angle. You can apply */ + /* slant along either x- or y-axis by choosing a corresponding non-zero */ + /* argument. If both slants are non-zero, some affine transformation */ + /* will result. */ + FT_EXPORT( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ); + + /* */ + + +FT_END_HEADER + +#endif /* FTSYNTH_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftsystem.h b/Dependencies/freetype/freetype/include/freetype/ftsystem.h new file mode 100644 index 00000000..1eacb3af --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftsystem.h @@ -0,0 +1,350 @@ +/**************************************************************************** + * + * ftsystem.h + * + * FreeType low-level system interface definition (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSYSTEM_H_ +#define FTSYSTEM_H_ + + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * system_interface + * + * @title: + * System Interface + * + * @abstract: + * How FreeType manages memory and i/o. + * + * @description: + * This section contains various definitions related to memory management + * and i/o access. You need to understand this information if you want to + * use a custom memory manager or you own i/o streams. + * + */ + + + /************************************************************************** + * + * M E M O R Y M A N A G E M E N T + * + */ + + + /************************************************************************** + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; + + + /************************************************************************** + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size` bytes from `memory`. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0~in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + + /************************************************************************** + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); + + + /************************************************************************** + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0~in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + + /************************************************************************** + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType~2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; + + + /************************************************************************** + * + * I / O M A N A G E M E N T + * + */ + + + /************************************************************************** + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + * @also: + * See @FT_StreamRec for the publicly accessible fields of a given stream + * object. + * + */ + typedef struct FT_StreamRec_* FT_Stream; + + + /************************************************************************** + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*` in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + + } FT_StreamDesc; + + + /************************************************************************** + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset from the start of the stream to seek to. + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * If count >~0, return the number of bytes effectively read by the + * stream (after seeking to `offset`). If count ==~0, return the status + * of the seek operation (non-zero indicates an error). + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); + + + /************************************************************************** + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); + + + /************************************************************************** + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to `NULL` for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * In case of compressed streams where the size is unknown before + * actually doing the decompression, the value is set to 0x7FFFFFFF. + * (Note that this size value can occur for normal streams also; it is + * thus just a hint.) + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*` + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream's close function. + * + * memory :: + * The memory manager to use to preload frames. This is set internally + * by FreeType and shouldn't be touched by stream implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. In particular, the `FT_GET_XXX` macros use this instead of + * the `pos` field. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + + } FT_StreamRec; + + /* */ + + +FT_END_HEADER + +#endif /* FTSYSTEM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/fttrigon.h b/Dependencies/freetype/freetype/include/freetype/fttrigon.h new file mode 100644 index 00000000..a5299e93 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/fttrigon.h @@ -0,0 +1,350 @@ +/**************************************************************************** + * + * fttrigon.h + * + * FreeType trigonometric functions (specification). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTTRIGON_H_ +#define FTTRIGON_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * computations + * + */ + + + /************************************************************************** + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed-point value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) + + + /************************************************************************** + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) + + + /************************************************************************** + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in the 2d + * plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************** + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `angle2-angle1`. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x` will be `cos(angle)`, and the value of + * `vec.y` will be `sin(angle)`. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); + + + /************************************************************************** + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); + + + /************************************************************************** + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); + + /* */ + + +FT_END_HEADER + +#endif /* FTTRIGON_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/fttypes.h b/Dependencies/freetype/freetype/include/freetype/fttypes.h new file mode 100644 index 00000000..27815143 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/fttypes.h @@ -0,0 +1,617 @@ +/**************************************************************************** + * + * fttypes.h + * + * FreeType simple types definitions (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTTYPES_H_ +#define FTTYPES_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include + +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * basic_types + * + * @title: + * Basic Data Types + * + * @abstract: + * The basic data types defined by the library. + * + * @description: + * This section contains the basic data types defined by FreeType~2, + * ranging from simple scalar types to bitmap descriptors. More + * font-specific structures are defined in a different section. Note + * that FreeType does not use floating-point data types. Fractional + * values are represented by fixed-point integers, with lower bits + * storing the fractional part. + * + * @order: + * FT_Byte + * FT_Bytes + * FT_Char + * FT_Int + * FT_UInt + * FT_Int16 + * FT_UInt16 + * FT_Int32 + * FT_UInt32 + * FT_Int64 + * FT_UInt64 + * FT_Short + * FT_UShort + * FT_Long + * FT_ULong + * FT_Bool + * FT_Offset + * FT_PtrDist + * FT_String + * FT_Tag + * FT_Error + * FT_Fixed + * FT_Pointer + * FT_Pos + * FT_Vector + * FT_BBox + * FT_Matrix + * FT_FWord + * FT_UFWord + * FT_F2Dot14 + * FT_UnitVector + * FT_F26Dot6 + * FT_Data + * + * FT_MAKE_TAG + * + * FT_Generic + * FT_Generic_Finalizer + * + * FT_Bitmap + * FT_Pixel_Mode + * FT_Palette_Mode + * FT_Glyph_Format + * FT_IMAGE_TAG + * + */ + + + /************************************************************************** + * + * @type: + * FT_Bool + * + * @description: + * A typedef of unsigned char, used for simple booleans. As usual, + * values 1 and~0 represent true and false, respectively. + */ + typedef unsigned char FT_Bool; + + + /************************************************************************** + * + * @type: + * FT_FWord + * + * @description: + * A signed 16-bit integer used to store a distance in original font + * units. + */ + typedef signed short FT_FWord; /* distance in FUnits */ + + + /************************************************************************** + * + * @type: + * FT_UFWord + * + * @description: + * An unsigned 16-bit integer used to store a distance in original font + * units. + */ + typedef unsigned short FT_UFWord; /* unsigned distance */ + + + /************************************************************************** + * + * @type: + * FT_Char + * + * @description: + * A simple typedef for the _signed_ char type. + */ + typedef signed char FT_Char; + + + /************************************************************************** + * + * @type: + * FT_Byte + * + * @description: + * A simple typedef for the _unsigned_ char type. + */ + typedef unsigned char FT_Byte; + + + /************************************************************************** + * + * @type: + * FT_Bytes + * + * @description: + * A typedef for constant memory areas. + */ + typedef const FT_Byte* FT_Bytes; + + + /************************************************************************** + * + * @type: + * FT_Tag + * + * @description: + * A typedef for 32-bit tags (as used in the SFNT format). + */ + typedef FT_UInt32 FT_Tag; + + + /************************************************************************** + * + * @type: + * FT_String + * + * @description: + * A simple typedef for the char type, usually used for strings. + */ + typedef char FT_String; + + + /************************************************************************** + * + * @type: + * FT_Short + * + * @description: + * A typedef for signed short. + */ + typedef signed short FT_Short; + + + /************************************************************************** + * + * @type: + * FT_UShort + * + * @description: + * A typedef for unsigned short. + */ + typedef unsigned short FT_UShort; + + + /************************************************************************** + * + * @type: + * FT_Int + * + * @description: + * A typedef for the int type. + */ + typedef signed int FT_Int; + + + /************************************************************************** + * + * @type: + * FT_UInt + * + * @description: + * A typedef for the unsigned int type. + */ + typedef unsigned int FT_UInt; + + + /************************************************************************** + * + * @type: + * FT_Long + * + * @description: + * A typedef for signed long. + */ + typedef signed long FT_Long; + + + /************************************************************************** + * + * @type: + * FT_ULong + * + * @description: + * A typedef for unsigned long. + */ + typedef unsigned long FT_ULong; + + + /************************************************************************** + * + * @type: + * FT_F2Dot14 + * + * @description: + * A signed 2.14 fixed-point type used for unit vectors. + */ + typedef signed short FT_F2Dot14; + + + /************************************************************************** + * + * @type: + * FT_F26Dot6 + * + * @description: + * A signed 26.6 fixed-point type used for vectorial pixel coordinates. + */ + typedef signed long FT_F26Dot6; + + + /************************************************************************** + * + * @type: + * FT_Fixed + * + * @description: + * This type is used to store 16.16 fixed-point values, like scaling + * values or matrix coefficients. + */ + typedef signed long FT_Fixed; + + + /************************************************************************** + * + * @type: + * FT_Error + * + * @description: + * The FreeType error code type. A value of~0 is always interpreted as a + * successful operation. + */ + typedef int FT_Error; + + + /************************************************************************** + * + * @type: + * FT_Pointer + * + * @description: + * A simple typedef for a typeless pointer. + */ + typedef void* FT_Pointer; + + + /************************************************************************** + * + * @type: + * FT_Offset + * + * @description: + * This is equivalent to the ANSI~C `size_t` type, i.e., the largest + * _unsigned_ integer type used to express a file size or position, or a + * memory block size. + */ + typedef size_t FT_Offset; + + + /************************************************************************** + * + * @type: + * FT_PtrDist + * + * @description: + * This is equivalent to the ANSI~C `ptrdiff_t` type, i.e., the largest + * _signed_ integer type used to express the distance between two + * pointers. + */ + typedef ft_ptrdiff_t FT_PtrDist; + + + /************************************************************************** + * + * @struct: + * FT_UnitVector + * + * @description: + * A simple structure used to store a 2D vector unit vector. Uses + * FT_F2Dot14 types. + * + * @fields: + * x :: + * Horizontal coordinate. + * + * y :: + * Vertical coordinate. + */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + + } FT_UnitVector; + + + /************************************************************************** + * + * @struct: + * FT_Matrix + * + * @description: + * A simple structure used to store a 2x2 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is: + * + * ``` + * x' = x*xx + y*xy + * y' = x*yx + y*yy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + + } FT_Matrix; + + + /************************************************************************** + * + * @struct: + * FT_Data + * + * @description: + * Read-only binary data represented as a pointer and a length. + * + * @fields: + * pointer :: + * The data. + * + * length :: + * The length of the data in bytes. + */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_UInt length; + + } FT_Data; + + + /************************************************************************** + * + * @functype: + * FT_Generic_Finalizer + * + * @description: + * Describe a function used to destroy the 'client' data of any FreeType + * object. See the description of the @FT_Generic type for details of + * usage. + * + * @input: + * The address of the FreeType object that is under finalization. Its + * client data is accessed through its `generic` field. + */ + typedef void (*FT_Generic_Finalizer)( void* object ); + + + /************************************************************************** + * + * @struct: + * FT_Generic + * + * @description: + * Client applications often need to associate their own data to a + * variety of FreeType core objects. For example, a text layout API + * might want to associate a glyph cache to a given size object. + * + * Some FreeType object contains a `generic` field, of type `FT_Generic`, + * which usage is left to client applications and font servers. + * + * It can be used to store a pointer to client-specific data, as well as + * the address of a 'finalizer' function, which will be called by + * FreeType when the object is destroyed (for example, the previous + * client example would put the address of the glyph cache destructor in + * the `finalizer` field). + * + * @fields: + * data :: + * A typeless pointer to any client-specified data. This field is + * completely ignored by the FreeType library. + * + * finalizer :: + * A pointer to a 'generic finalizer' function, which will be called + * when the object is destroyed. If this field is set to `NULL`, no + * code will be called. + */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + + } FT_Generic; + + + /************************************************************************** + * + * @macro: + * FT_MAKE_TAG + * + * @description: + * This macro converts four-letter tags that are used to label TrueType + * tables into an `FT_Tag` type, to be used within FreeType. + * + * @note: + * The produced values **must** be 32-bit integers. Don't redefine this + * macro. + */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( FT_STATIC_BYTE_CAST( FT_Tag, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_Tag, _x4 ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /* */ + /* L I S T M A N A G E M E N T */ + /* */ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @section: + * list_processing + * + */ + + + /************************************************************************** + * + * @type: + * FT_ListNode + * + * @description: + * Many elements and objects in FreeType are listed through an @FT_List + * record (see @FT_ListRec). As its name suggests, an FT_ListNode is a + * handle to a single list element. + */ + typedef struct FT_ListNodeRec_* FT_ListNode; + + + /************************************************************************** + * + * @type: + * FT_List + * + * @description: + * A handle to a list record (see @FT_ListRec). + */ + typedef struct FT_ListRec_* FT_List; + + + /************************************************************************** + * + * @struct: + * FT_ListNodeRec + * + * @description: + * A structure used to hold a single list element. + * + * @fields: + * prev :: + * The previous element in the list. `NULL` if first. + * + * next :: + * The next element in the list. `NULL` if last. + * + * data :: + * A typeless pointer to the listed object. + */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + + } FT_ListNodeRec; + + + /************************************************************************** + * + * @struct: + * FT_ListRec + * + * @description: + * A structure used to hold a simple doubly-linked list. These are used + * in many parts of FreeType. + * + * @fields: + * head :: + * The head (first element) of doubly-linked list. + * + * tail :: + * The tail (last element) of doubly-linked list. + */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + + } FT_ListRec; + + /* */ + + +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) +#define FT_BOOL( x ) FT_STATIC_CAST( FT_Bool, (x) != 0 ) + + /* concatenate C tokens */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + /* see `ftmoderr.h` for descriptions of the following macros */ + +#define FT_ERR( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) + +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) + +#define FT_ERR_EQ( x, e ) \ + ( FT_ERROR_BASE( x ) == FT_ERROR_BASE( FT_ERR( e ) ) ) +#define FT_ERR_NEQ( x, e ) \ + ( FT_ERROR_BASE( x ) != FT_ERROR_BASE( FT_ERR( e ) ) ) + + +FT_END_HEADER + +#endif /* FTTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ftwinfnt.h b/Dependencies/freetype/freetype/include/freetype/ftwinfnt.h new file mode 100644 index 00000000..2591e588 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ftwinfnt.h @@ -0,0 +1,276 @@ +/**************************************************************************** + * + * ftwinfnt.h + * + * FreeType API for accessing Windows fnt-specific data. + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTWINFNT_H_ +#define FTWINFNT_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * winfnt_fonts + * + * @title: + * Window FNT Files + * + * @abstract: + * Windows FNT-specific API. + * + * @description: + * This section contains the declaration of Windows FNT-specific + * functions. + * + */ + + + /************************************************************************** + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset` byte in @FT_WinFNT_HeaderRec. + * Exact mapping tables for the various 'cpXXXX' encodings (except for + * 'cp1361') can be found at 'ftp://ftp.unicode.org/Public/' in the + * `MAPPINGS/VENDORS/MICSFT/WINDOWS` subdirectory. 'cp1361' is roughly a + * superset of `MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT`. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a 'don't + * care' value. Valid font files don't contain this value. When + * querying for information about the character set of the font that is + * currently selected into a specified device context, this return + * value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Poettgen : + * + * The 'Windows Font Mapping' article says that `FT_WinFNT_ID_OEM` is + * used for the charset of vector fonts, like `modern.fon`, + * `roman.fon`, and `script.fon` on Windows. + * + * The 'CreateFont' documentation says: The `FT_WinFNT_ID_OEM` value + * specifies a character set that is operating-system dependent. + * + * The 'IFIMETRICS' documentation from the 'Windows Driver Development + * Kit' says: This font supports an OEM-specific character set. The + * OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., 'cp1252'), denotes the + * second default codepage that most international versions of Windows + * have. It is one of the OEM codepages from + * + * https://docs.microsoft.com/en-us/windows/desktop/intl/code-page-identifiers + * , + * + * and is used for the 'DOS boxes', to support legacy applications. A + * German Windows version for example usually uses ANSI codepage 1252 + * and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS~C 5601-1987 (with different ordering + * and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big~5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ + +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 + + + /************************************************************************** + * + * @struct: + * FT_WinFNT_HeaderRec + * + * @description: + * Windows FNT Header info. + */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + + } FT_WinFNT_HeaderRec; + + + /************************************************************************** + * + * @struct: + * FT_WinFNT_Header + * + * @description: + * A handle to an @FT_WinFNT_HeaderRec structure. + */ + typedef struct FT_WinFNT_HeaderRec_* FT_WinFNT_Header; + + + /************************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * aheader :: + * The WinFNT header. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + /* */ + + +FT_END_HEADER + +#endif /* FTWINFNT_H_ */ + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/autohint.h b/Dependencies/freetype/freetype/include/freetype/internal/autohint.h new file mode 100644 index 00000000..8865d53b --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/autohint.h @@ -0,0 +1,234 @@ +/**************************************************************************** + * + * autohint.h + * + * High-level 'autohint' module-specific interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * The auto-hinter is used to load and automatically hint glyphs if a + * format-specific hinter isn't available. + * + */ + + +#ifndef AUTOHINT_H_ +#define AUTOHINT_H_ + + + /************************************************************************** + * + * A small technical note regarding automatic hinting in order to clarify + * this module interface. + * + * An automatic hinter might compute two kinds of data for a given face: + * + * - global hints: Usually some metrics that describe global properties + * of the face. It is computed by scanning more or less + * aggressively the glyphs in the face, and thus can be + * very slow to compute (even if the size of global hints + * is really small). + * + * - glyph hints: These describe some important features of the glyph + * outline, as well as how to align them. They are + * generally much faster to compute than global hints. + * + * The current FreeType auto-hinter does a pretty good job while performing + * fast computations for both global and glyph hints. However, we might be + * interested in introducing more complex and powerful algorithms in the + * future, like the one described in the John D. Hobby paper, which + * unfortunately requires a lot more horsepower. + * + * Because a sufficiently sophisticated font management system would + * typically implement an LRU cache of opened face objects to reduce memory + * usage, it is a good idea to be able to avoid recomputing global hints + * every time the same face is re-opened. + * + * We thus provide the ability to cache global hints outside of the face + * object, in order to speed up font re-opening time. Of course, this + * feature is purely optional, so most client programs won't even notice + * it. + * + * I initially thought that it would be a good idea to cache the glyph + * hints too. However, my general idea now is that if you really need to + * cache these too, you are simply in need of a new font format, where all + * this information could be stored within the font file and decoded on the + * fly. + * + */ + + +#include + + +FT_BEGIN_HEADER + + + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalGetFunc + * + * @description: + * Retrieve the global hints computed for a given face object. The + * resulting data is dissociated from the face and will survive a call to + * FT_Done_Face(). It must be discarded through the API + * FT_AutoHinter_GlobalDoneFunc(). + * + * @input: + * hinter :: + * A handle to the source auto-hinter. + * + * face :: + * A handle to the source face object. + * + * @output: + * global_hints :: + * A typeless pointer to the global hints. + * + * global_len :: + * The size in bytes of the global hints. + */ + typedef void + (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalDoneFunc + * + * @description: + * Discard the global hints retrieved through + * FT_AutoHinter_GlobalGetFunc(). This is the only way these hints are + * freed from memory. + * + * @input: + * hinter :: + * A handle to the auto-hinter module. + * + * global :: + * A pointer to retrieved global hints to discard. + */ + typedef void + (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, + void* global ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlobalResetFunc + * + * @description: + * This function is used to recompute the global metrics in a given font. + * This is useful when global font data changes (e.g. Multiple Masters + * fonts where blend coordinates change). + * + * @input: + * hinter :: + * A handle to the source auto-hinter. + * + * face :: + * A handle to the face. + */ + typedef void + (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, + FT_Face face ); + + + /************************************************************************** + * + * @functype: + * FT_AutoHinter_GlyphLoadFunc + * + * @description: + * This function is used to load, scale, and automatically hint a glyph + * from a given face. + * + * @input: + * face :: + * A handle to the face. + * + * glyph_index :: + * The glyph index. + * + * load_flags :: + * The load flags. + * + * @note: + * This function is capable of loading composite glyphs by hinting each + * sub-glyph independently (which improves quality). + * + * It will call the font driver with @FT_Load_Glyph, with + * @FT_LOAD_NO_SCALE set. + */ + typedef FT_Error + (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + /************************************************************************** + * + * @struct: + * FT_AutoHinter_InterfaceRec + * + * @description: + * The auto-hinter module's interface. + */ + typedef struct FT_AutoHinter_InterfaceRec_ + { + FT_AutoHinter_GlobalResetFunc reset_face; + FT_AutoHinter_GlobalGetFunc get_global_hints; + FT_AutoHinter_GlobalDoneFunc done_global_hints; + FT_AutoHinter_GlyphLoadFunc load_glyph; + + } FT_AutoHinter_InterfaceRec, *FT_AutoHinter_Interface; + + +#define FT_DECLARE_AUTOHINTER_INTERFACE( class_ ) \ + FT_CALLBACK_TABLE const FT_AutoHinter_InterfaceRec class_; + +#define FT_DEFINE_AUTOHINTER_INTERFACE( \ + class_, \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_AutoHinter_InterfaceRec class_ = \ + { \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ \ + }; + + +FT_END_HEADER + +#endif /* AUTOHINT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/cffotypes.h b/Dependencies/freetype/freetype/include/freetype/internal/cffotypes.h new file mode 100644 index 00000000..36b0390a --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/cffotypes.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * cffotypes.h + * + * Basic OpenType/CFF object type definitions (specification). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFOTYPES_H_ +#define CFFOTYPES_H_ + +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + typedef TT_Face CFF_Face; + + + /************************************************************************** + * + * @type: + * CFF_Size + * + * @description: + * A handle to an OpenType size object. + */ + typedef struct CFF_SizeRec_ + { + FT_SizeRec root; + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + + } CFF_SizeRec, *CFF_Size; + + + /************************************************************************** + * + * @type: + * CFF_GlyphSlot + * + * @description: + * A handle to an OpenType glyph slot object. + */ + typedef struct CFF_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CFF_GlyphSlotRec, *CFF_GlyphSlot; + + + /************************************************************************** + * + * @type: + * CFF_Internal + * + * @description: + * The interface to the 'internal' field of `FT_Size`. + */ + typedef struct CFF_InternalRec_ + { + PSH_Globals topfont; + PSH_Globals subfonts[CFF_MAX_CID_FONTS]; + + } CFF_InternalRec, *CFF_Internal; + + + /************************************************************************** + * + * Subglyph transformation record. + */ + typedef struct CFF_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } CFF_Transform; + + +FT_END_HEADER + + +#endif /* CFFOTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/cfftypes.h b/Dependencies/freetype/freetype/include/freetype/internal/cfftypes.h new file mode 100644 index 00000000..ef2e8e75 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/cfftypes.h @@ -0,0 +1,416 @@ +/**************************************************************************** + * + * cfftypes.h + * + * Basic OpenType/CFF type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFTYPES_H_ +#define CFFTYPES_H_ + + +#include +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * CFF_IndexRec + * + * @description: + * A structure used to model a CFF Index table. + * + * @fields: + * stream :: + * The source input stream. + * + * start :: + * The position of the first index byte in the input stream. + * + * count :: + * The number of elements in the index. + * + * off_size :: + * The size in bytes of object offsets in index. + * + * data_offset :: + * The position of first data byte in the index's bytes. + * + * data_size :: + * The size of the data table in this index. + * + * offsets :: + * A table of element offsets in the index. Must be loaded explicitly. + * + * bytes :: + * If the index is loaded in memory, its bytes. + */ + typedef struct CFF_IndexRec_ + { + FT_Stream stream; + FT_ULong start; + FT_UInt hdr_size; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + FT_ULong data_size; + + FT_ULong* offsets; + FT_Byte* bytes; + + } CFF_IndexRec, *CFF_Index; + + + typedef struct CFF_EncodingRec_ + { + FT_UInt format; + FT_ULong offset; + + FT_UInt count; + FT_UShort sids [256]; /* avoid dynamic allocations */ + FT_UShort codes[256]; + + } CFF_EncodingRec, *CFF_Encoding; + + + typedef struct CFF_CharsetRec_ + { + + FT_UInt format; + FT_ULong offset; + + FT_UShort* sids; + FT_UShort* cids; /* the inverse mapping of `sids'; only needed */ + /* for CID-keyed fonts */ + FT_UInt max_cid; + FT_UInt num_glyphs; + + } CFF_CharsetRec, *CFF_Charset; + + + /* cf. similar fields in file `ttgxvar.h' from the `truetype' module */ + + typedef struct CFF_VarData_ + { +#if 0 + FT_UInt itemCount; /* not used; always zero */ + FT_UInt shortDeltaCount; /* not used; always zero */ +#endif + + FT_UInt regionIdxCount; /* number of region indexes */ + FT_UInt* regionIndices; /* array of `regionIdxCount' indices; */ + /* these index `varRegionList' */ + } CFF_VarData; + + + /* contribution of one axis to a region */ + typedef struct CFF_AxisCoords_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero peak means no effect (factor = 1) */ + FT_Fixed endCoord; + + } CFF_AxisCoords; + + + typedef struct CFF_VarRegion_ + { + CFF_AxisCoords* axisList; /* array of axisCount records */ + + } CFF_VarRegion; + + + typedef struct CFF_VStoreRec_ + { + FT_UInt dataCount; + CFF_VarData* varData; /* array of dataCount records */ + /* vsindex indexes this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + CFF_VarRegion* varRegionList; + + } CFF_VStoreRec, *CFF_VStore; + + + /* forward reference */ + typedef struct CFF_FontRec_* CFF_Font; + + + /* This object manages one cached blend vector. */ + /* */ + /* There is a BlendRec for Private DICT parsing in each subfont */ + /* and a BlendRec for charstrings in CF2_Font instance data. */ + /* A cached BV may be used across DICTs or Charstrings if inputs */ + /* have not changed. */ + /* */ + /* `usedBV' is reset at the start of each parse or charstring. */ + /* vsindex cannot be changed after a BV is used. */ + /* */ + /* Note: NDV is long (32/64 bit), while BV is 16.16 (FT_Int32). */ + typedef struct CFF_BlendRec_ + { + FT_Bool builtBV; /* blendV has been built */ + FT_Bool usedBV; /* blendV has been used */ + CFF_Font font; /* top level font struct */ + FT_UInt lastVsindex; /* last vsindex used */ + FT_UInt lenNDV; /* normDV length (aka numAxes) */ + FT_Fixed* lastNDV; /* last NDV used */ + FT_UInt lenBV; /* BlendV length (aka numMasters) */ + FT_Int32* BV; /* current blendV (per DICT/glyph) */ + + } CFF_BlendRec, *CFF_Blend; + + + typedef struct CFF_FontRecDictRec_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Fixed underline_position; + FT_Fixed underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_Bool has_font_matrix; + FT_ULong units_per_em; /* temporarily used as scaling value also */ + FT_Vector font_offset; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; + + /* these should only be used for the top-level font dictionary */ + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_Long cid_supplement; + + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_ULong cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + + /* the next fields come from the data of the deprecated */ + /* `MultipleMaster' operator; they are needed to parse the (also */ + /* deprecated) `blend' operator in Type 2 charstrings */ + FT_UShort num_designs; + FT_UShort num_axes; + + /* fields for CFF2 */ + FT_ULong vstore_offset; + FT_UInt maxstack; + + } CFF_FontRecDictRec, *CFF_FontRecDict; + + + /* forward reference */ + typedef struct CFF_SubFontRec_* CFF_SubFont; + + + typedef struct CFF_PrivateRec_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Fixed blue_values[14]; + FT_Fixed other_blues[10]; + FT_Fixed family_blues[14]; + FT_Fixed family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + + /* fields for CFF2 */ + FT_UInt vsindex; + CFF_SubFont subfont; + + } CFF_PrivateRec, *CFF_Private; + + + typedef struct CFF_FDSelectRec_ + { + FT_Byte format; + FT_UInt range_count; + + /* that's the table, taken from the file `as is' */ + FT_Byte* data; + FT_UInt data_size; + + /* small cache for format 3 only */ + FT_UInt cache_first; + FT_UInt cache_count; + FT_Byte cache_fd; + + } CFF_FDSelectRec, *CFF_FDSelect; + + + /* A SubFont packs a font dict and a private dict together. They are */ + /* needed to support CID-keyed CFF fonts. */ + typedef struct CFF_SubFontRec_ + { + CFF_FontRecDictRec font_dict; + CFF_PrivateRec private_dict; + + /* fields for CFF2 */ + CFF_BlendRec blend; /* current blend vector */ + FT_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + + /* `blend_stack' is a writable buffer to hold blend results. */ + /* This buffer is to the side of the normal cff parser stack; */ + /* `cff_parse_blend' and `cff_blend_doBlend' push blend results here. */ + /* The normal stack then points to these values instead of the DICT */ + /* because all other operators in Private DICT clear the stack. */ + /* `blend_stack' could be cleared at each operator other than blend. */ + /* Blended values are stored as 5-byte fixed-point values. */ + + FT_Byte* blend_stack; /* base of stack allocation */ + FT_Byte* blend_top; /* first empty slot */ + FT_UInt blend_used; /* number of bytes in use */ + FT_UInt blend_alloc; /* number of bytes allocated */ + + CFF_IndexRec local_subrs_index; + FT_Byte** local_subrs; /* array of pointers */ + /* into Local Subrs INDEX data */ + + FT_UInt32 random; + + } CFF_SubFontRec; + + +#define CFF_MAX_CID_FONTS 256 + + + typedef struct CFF_FontRec_ + { + FT_Library library; + FT_Stream stream; + FT_Memory memory; /* TODO: take this from stream->memory? */ + FT_ULong base_offset; /* offset to start of CFF */ + FT_UInt num_faces; + FT_UInt num_glyphs; + + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + + FT_UInt top_dict_length; /* cff2 only */ + + FT_Bool cff2; + + CFF_IndexRec name_index; + CFF_IndexRec top_dict_index; + CFF_IndexRec global_subrs_index; + + CFF_EncodingRec encoding; + CFF_CharsetRec charset; + + CFF_IndexRec charstrings_index; + CFF_IndexRec font_dict_index; + CFF_IndexRec private_index; + CFF_IndexRec local_subrs_index; + + FT_String* font_name; + + /* array of pointers into Global Subrs INDEX data */ + FT_Byte** global_subrs; + + /* array of pointers into String INDEX data stored at string_pool */ + FT_UInt num_strings; + FT_Byte** strings; + FT_Byte* string_pool; + FT_ULong string_pool_size; + + CFF_SubFontRec top_font; + FT_UInt num_subfonts; + CFF_SubFont subfonts[CFF_MAX_CID_FONTS]; + + CFF_FDSelectRec fd_select; + + /* interface to PostScript hinter */ + PSHinter_Service pshinter; + + /* interface to Postscript Names service */ + FT_Service_PsCMaps psnames; + + /* interface to CFFLoad service */ + const void* cffload; + + /* since version 2.3.0 */ + PS_FontInfoRec* font_info; /* font info dictionary */ + + /* since version 2.3.6 */ + FT_String* registry; + FT_String* ordering; + + /* since version 2.4.12 */ + FT_Generic cf2_instance; + + /* since version 2.7.1 */ + CFF_VStoreRec vstore; /* parsed vstore structure */ + + /* since version 2.9 */ + PS_FontExtraRec* font_extra; + + } CFF_FontRec; + + +FT_END_HEADER + +#endif /* CFFTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/compiler-macros.h b/Dependencies/freetype/freetype/include/freetype/internal/compiler-macros.h new file mode 100644 index 00000000..876f66e2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/compiler-macros.h @@ -0,0 +1,343 @@ +/**************************************************************************** + * + * internal/compiler-macros.h + * + * Compiler-specific macro definitions used internally by FreeType. + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef INTERNAL_COMPILER_MACROS_H_ +#define INTERNAL_COMPILER_MACROS_H_ + +#include + +FT_BEGIN_HEADER + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Newer compilers warn for fall-through case statements. */ +#ifndef FALL_THROUGH +# if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \ + ( defined( __cplusplus ) && __cplusplus > 201402L ) +# define FALL_THROUGH [[__fallthrough__]] +# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \ + ( defined( __clang__ ) && \ + ( defined( __apple_build_version__ ) \ + ? __apple_build_version__ >= 12000000 \ + : __clang_major__ >= 10 ) ) +# define FALL_THROUGH __attribute__(( __fallthrough__ )) +# else +# define FALL_THROUGH ( (void)0 ) +# endif +#endif + + /* + * When defining a macro that expands to a non-trivial C statement, use + * FT_BEGIN_STMNT and FT_END_STMNT to enclose the macro's body. This + * ensures there are no surprises when the macro is invoked in conditional + * branches. + * + * Example: + * + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + */ +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + + /* + * FT_DUMMY_STMNT expands to an empty C statement. Useful for + * conditionally defined statement macros. + * + * Example: + * + * #ifdef BUILD_CONFIG_LOGGING + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + * #else + * # define LOG( ... ) FT_DUMMY_STMNT + * #endif + */ +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + +#ifdef __UINTPTR_TYPE__ + /* + * GCC and Clang both provide a `__UINTPTR_TYPE__` that can be used to + * avoid a dependency on `stdint.h`. + */ +# define FT_UINT_TO_POINTER( x ) (void *)(__UINTPTR_TYPE__)(x) +#elif defined( _WIN64 ) + /* only 64bit Windows uses the LLP64 data model, i.e., */ + /* 32-bit integers, 64-bit pointers. */ +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned __int64)(x) +#else +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned long)(x) +#endif + + /* + * Use `FT_TYPEOF( type )` to cast a value to `type`. This is useful to + * suppress signedness compilation warnings in macros. + * + * Example: + * + * #define PAD_( x, n ) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) + * + * (The `typeof` condition is taken from gnulib's `intprops.h` header + * file.) + */ +#if ( ( defined( __GNUC__ ) && __GNUC__ >= 2 ) || \ + ( defined( __IBMC__ ) && __IBMC__ >= 1210 && \ + defined( __IBM__TYPEOF__ ) ) || \ + ( defined( __SUNPRO_C ) && __SUNPRO_C >= 0x5110 && !__STDC__ ) ) +#define FT_TYPEOF( type ) ( __typeof__ ( type ) ) +#else +#define FT_TYPEOF( type ) /* empty */ +#endif + + /* + * Mark a function declaration as internal to the library. This ensures + * that it will not be exposed by default to client code, and helps + * generate smaller and faster code on ELF-based platforms. Place this + * before a function declaration. + */ + + /* Visual C, mingw */ +#if defined( _WIN32 ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "hidden" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_INTERNAL_FUNCTION_ATTRIBUTE __hidden + +#else +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ +#endif + + /* + * FreeType supports compilation of its C sources with a C++ compiler (in + * C++ mode); this introduces a number of subtle issues. + * + * The main one is that a C++ function declaration and its definition must + * have the same 'linkage'. Because all FreeType headers declare their + * functions with C linkage (i.e., within an `extern "C" { ... }` block + * due to the magic of FT_BEGIN_HEADER and FT_END_HEADER), their + * definition in FreeType sources should also be prefixed with `extern + * "C"` when compiled in C++ mode. + * + * The `FT_FUNCTION_DECLARATION` and `FT_FUNCTION_DEFINITION` macros are + * provided to deal with this case, as well as `FT_CALLBACK_DEF` and its + * siblings below. + */ + + /* + * `FT_FUNCTION_DECLARATION( type )` can be used to write a C function + * declaration to ensure it will have C linkage when the library is built + * with a C++ compiler. The parameter is the function's return type, so a + * declaration would look like + * + * FT_FUNCTION_DECLARATION( int ) + * foo( int x ); + * + * NOTE: This requires that all uses are inside of `FT_BEGIN_HEADER ... + * FT_END_HEADER` blocks, which guarantees that the declarations have C + * linkage when the headers are included by C++ sources. + * + * NOTE: Do not use directly. Use `FT_LOCAL`, `FT_BASE`, and `FT_EXPORT` + * instead. + */ +#define FT_FUNCTION_DECLARATION( x ) extern x + + /* + * Same as `FT_FUNCTION_DECLARATION`, but for function definitions instead. + * + * NOTE: Do not use directly. Use `FT_LOCAL_DEF`, `FT_BASE_DEF`, and + * `FT_EXPORT_DEF` instead. + */ +#ifdef __cplusplus +#define FT_FUNCTION_DEFINITION( x ) extern "C" x +#else +#define FT_FUNCTION_DEFINITION( x ) x +#endif + + /* + * Use `FT_LOCAL` and `FT_LOCAL_DEF` to declare and define, respectively, + * an internal FreeType function that is only used by the sources of a + * single `src/module/` directory. This ensures that the functions are + * turned into static ones at build time, resulting in smaller and faster + * code. + */ +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#define FT_LOCAL( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_LOCAL_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + /* + * Use `FT_LOCAL_ARRAY` and `FT_LOCAL_ARRAY_DEF` to declare and define, + * respectively, a constant array that must be accessed from several + * sources in the same `src/module/` sub-directory, and which are internal + * to the library. + */ +#define FT_LOCAL_ARRAY( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + extern const x +#define FT_LOCAL_ARRAY_DEF( x ) FT_FUNCTION_DEFINITION( const x ) + + /* + * `Use FT_BASE` and `FT_BASE_DEF` to declare and define, respectively, an + * internal library function that is used by more than a single module. + */ +#define FT_BASE( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + + /* + * NOTE: Conditionally define `FT_EXPORT_VAR` due to its definition in + * `src/smooth/ftgrays.h` to make the header more portable. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) FT_FUNCTION_DECLARATION( x ) +#endif + + /* + * When compiling FreeType as a DLL or DSO with hidden visibility, + * some systems/compilers need a special attribute in front OR after + * the return type of function declarations. + * + * Two macros are used within the FreeType source code to define + * exported library functions: `FT_EXPORT` and `FT_EXPORT_DEF`. + * + * - `FT_EXPORT( return_type )` + * + * is used in a function declaration, as in + * + * ``` + * FT_EXPORT( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ); + * ``` + * + * - `FT_EXPORT_DEF( return_type )` + * + * is used in a function definition, as in + * + * ``` + * FT_EXPORT_DEF( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ) + * { + * ... some code ... + * return FT_Err_Ok; + * } + * ``` + * + * You can provide your own implementation of `FT_EXPORT` and + * `FT_EXPORT_DEF` here if you want. + * + * To export a variable, use `FT_EXPORT_VAR`. + */ + + /* See `freetype/config/public-macros.h` for the `FT_EXPORT` definition */ +#define FT_EXPORT_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + /* + * The following macros are needed to compile the library with a + * C++ compiler and with 16bit compilers. + */ + + /* + * This is special. Within C++, you must specify `extern "C"` for + * functions which are used via function pointers, and you also + * must do that for structures which contain function pointers to + * assure C linkage -- it's not possible to have (local) anonymous + * functions which are accessed by (global) function pointers. + * + * + * FT_CALLBACK_DEF is used to _define_ a callback function, + * located in the same source code file as the structure that uses + * it. FT_COMPARE_DEF, in addition, ensures the `cdecl` calling + * convention on x86, required by the C library function `qsort`. + * + * FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare + * and define a callback function, respectively, in a similar way + * as FT_BASE and FT_BASE_DEF work. + * + * FT_CALLBACK_TABLE is used to _declare_ a constant variable that + * contains pointers to callback functions. + * + * FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable + * that contains pointers to callback functions. + * + * + * Some 16bit compilers have to redefine these macros to insert + * the infamous `_cdecl` or `__fastcall` declarations. + */ +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif + +#if defined( __GNUC__ ) && defined( __i386__ ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __attribute__(( cdecl )) +#elif defined( _MSC_VER ) && defined( _M_IX86 ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __cdecl +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1240 +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __watcall +#else +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) +#endif + +#define FT_BASE_CALLBACK( x ) FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_CALLBACK_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +#define FT_CALLBACK_TABLE_DEF /* nothing */ +#endif +#endif /* FT_CALLBACK_TABLE */ + +FT_END_HEADER + +#endif /* INTERNAL_COMPILER_MACROS_H_ */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftcalc.h b/Dependencies/freetype/freetype/include/freetype/internal/ftcalc.h new file mode 100644 index 00000000..71128a2d --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftcalc.h @@ -0,0 +1,584 @@ +/**************************************************************************** + * + * ftcalc.h + * + * Arithmetic computations (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCALC_H_ +#define FTCALC_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * FT_MulDiv() and FT_MulFix() are declared in freetype.h. + * + */ + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + /* Provide assembler fragments for performance-critical functions. */ + /* These must be defined `static __inline__' with GCC. */ + +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ + +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 t, t2; + + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x8000 /* a += 0x8000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #16 /* a = t2 >> 16 */ + orr a, a, t, lsl #16 /* a |= t << 16 */ + } + return a; + } + +#endif /* __CC_ARM || __ARMCC__ */ + + +#ifdef __GNUC__ + +#if defined( __arm__ ) && \ + ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ + !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 t, t2; + + + __asm__ __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ +#if defined( __clang__ ) && defined( __thumb2__ ) + "add.w %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#else + "add %0, %0, #0x8000\n\t" /* %0 += 0x8000 */ +#endif + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #16\n\t" /* %0 = %1 >> 16 */ + "orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + return a; + } + +#endif /* __arm__ && */ + /* ( __thumb2__ || !__thumb__ ) && */ + /* !( __CC_ARM || __ARMCC__ ) */ + + +#if defined( __i386__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline__ FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 result; + + + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); + return result; + } + +#endif /* i386 */ + +#endif /* __GNUC__ */ + + +#ifdef _MSC_VER /* Visual C++ */ + +#ifdef _M_IX86 + +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 + + /* documentation is in freetype.h */ + + static __inline FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + FT_Int32 result; + + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 8000h + add eax, ecx + adc edx, 0 + shr eax, 16 + shl edx, 16 + add eax, edx + mov result, eax + } + return result; + } + +#endif /* _M_IX86 */ + +#endif /* _MSC_VER */ + + +#if defined( __GNUC__ ) && defined( __x86_64__ ) + +#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 + + static __inline__ FT_Int32 + FT_MulFix_x86_64( FT_Int32 a, + FT_Int32 b ) + { + /* Temporarily disable the warning that C90 doesn't support */ + /* `long long'. */ +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlong-long" +#endif + +#if 1 + /* Technically not an assembly fragment, but GCC does a really good */ + /* job at inlining it and generating good machine code for it. */ + long long ret, tmp; + + + ret = (long long)a * b; + tmp = ret >> 63; + ret += 0x8000 + tmp; + + return (FT_Int32)( ret >> 16 ); +#else + + /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ + /* code from the lines below. The main issue is that `wide_a' is not */ + /* properly initialized by sign-extending `a'. Instead, the generated */ + /* machine code assumes that the register that contains `a' on input */ + /* can be used directly as a 64-bit value, which is wrong most of the */ + /* time. */ + long long wide_a = (long long)a; + long long wide_b = (long long)b; + long long result; + + + __asm__ __volatile__ ( + "imul %2, %1\n" + "mov %1, %0\n" + "sar $63, %0\n" + "lea 0x8000(%1, %0), %0\n" + "sar $16, %0\n" + : "=&r"(result), "=&r"(wide_a) + : "r"(wide_b) + : "cc" ); + + return (FT_Int32)result; +#endif + +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#pragma GCC diagnostic pop +#endif + } + +#endif /* __GNUC__ && __x86_64__ */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX +#ifdef FT_MULFIX_ASSEMBLER +#define FT_MulFix( a, b ) FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) ) +#endif +#endif + + + /************************************************************************** + * + * @function: + * FT_MulDiv_No_Round + * + * @description: + * A very simple function used to perform the computation '(a*b)/c' + * (without rounding) with maximum accuracy (it uses a 64-bit + * intermediate integer whenever necessary). + * + * This function isn't necessarily as fast as some processor-specific + * operations, but is at least completely portable. + * + * @input: + * a :: + * The first multiplier. + * b :: + * The second multiplier. + * c :: + * The divisor. + * + * @return: + * The result of '(a*b)/c'. This function never traps when trying to + * divide by zero; it simply returns 'MaxInt' or 'MinInt' depending on + * the signs of 'a' and 'b'. + */ + FT_BASE( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ); + + + /************************************************************************** + * + * @function: + * FT_MulAddFix + * + * @description: + * Compute `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`, where `s[n]` is + * usually a 16.16 scalar. + * + * @input: + * s :: + * The array of scalars. + * f :: + * The array of factors. + * count :: + * The number of entries in the array. + * + * @return: + * The result of `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`. + * + * @note: + * This function is currently used for the scaled delta computation of + * variation stores. It internally uses 64-bit data types when + * available, otherwise it emulates 64-bit math by using 32-bit + * operations, which produce a correct result but most likely at a slower + * performance in comparison to the implementation base on `int64_t`. + * + */ + FT_BASE( FT_Int32 ) + FT_MulAddFix( FT_Fixed* s, + FT_Int32* f, + FT_UInt count ); + + + /* + * A variant of FT_Matrix_Multiply which scales its result afterwards. The + * idea is that both `a' and `b' are scaled by factors of 10 so that the + * values are as precise as possible to get a correct result during the + * 64bit multiplication. Let `sa' and `sb' be the scaling factors of `a' + * and `b', respectively, then the scaling factor of the result is `sa*sb'. + */ + FT_BASE( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ); + + + /* + * Check a matrix. If the transformation would lead to extreme shear or + * extreme scaling, for example, return 0. If everything is OK, return 1. + * + * Based on geometric considerations we use the following inequality to + * identify a degenerate matrix. + * + * 32 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2 + * + * Value 32 is heuristic. + */ + FT_BASE( FT_Bool ) + FT_Matrix_Check( const FT_Matrix* matrix ); + + + /* + * A variant of FT_Vector_Transform. See comments for + * FT_Matrix_Multiply_Scaled. + */ + FT_BASE( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ); + + + /* + * This function normalizes a vector and returns its original length. The + * normalized vector is a 16.16 fixed-point unit vector with length close + * to 0x10000. The accuracy of the returned length is limited to 16 bits + * also. The function utilizes quick inverse square root approximation + * without divisions and square roots relying on Newton's iterations + * instead. + */ + FT_BASE( FT_UInt32 ) + FT_Vector_NormLen( FT_Vector* vector ); + + + /* + * Return -1, 0, or +1, depending on the orientation of a given corner. We + * use the Cartesian coordinate system, with positive vertical values going + * upwards. The function returns +1 if the corner turns to the left, -1 to + * the right, and 0 for undecidable cases. + */ + FT_BASE( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + + /* + * Return TRUE if a corner is flat or nearly flat. This is equivalent to + * saying that the corner point is close to its neighbors, or inside an + * ellipse defined by the neighbor focal points to be more precise. + */ + FT_BASE( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); + + + /* + * Return the most significant bit index. + */ + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + +#if defined( __clang__ ) || ( defined( __GNUC__ ) && \ + ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) ) + +#if FT_SIZEOF_INT == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clz( x ) ) + +#elif FT_SIZEOF_LONG == 4 + +#define FT_MSB( x ) ( 31 - __builtin_clzl( x ) ) + +#endif + +#elif defined( _MSC_VER ) && _MSC_VER >= 1400 + +#if defined( _WIN32_WCE ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_ARM64 ) || defined( _M_ARM ) || defined( _M_ARM64EC ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_IX86 ) || defined( _M_AMD64 ) || defined( _M_IA64 ) + +#include +#pragma intrinsic( _BitScanReverse ) + + static __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ) + { + unsigned long where; + + + _BitScanReverse( &where, x ); + + return (FT_Int32)where; + } + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#endif + +#elif defined( __WATCOMC__ ) && defined( __386__ ) + + extern __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ); + +#pragma aux FT_MSB_i386 = \ + "bsr eax, eax" \ + __parm [__eax] __nomemory \ + __value [__eax] \ + __modify __exact [__eax] __nomemory; + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#elif defined( __SunOS_5_11 ) + +#include + +#define FT_MSB( x ) ( fls( x ) - 1 ) + +#elif defined( __DECC ) || defined( __DECCXX ) + +#include + +#define FT_MSB( x ) (FT_Int)( 63 - _leadz( x ) ) + +#elif defined( _CRAYC ) + +#include + +#define FT_MSB( x ) (FT_Int)( 31 - _leadz32( x ) ) + +#endif /* FT_MSB macro definitions */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#ifndef FT_MSB + + FT_BASE( FT_Int ) + FT_MSB( FT_UInt32 z ); + +#endif + + + /* + * Return sqrt(x*x+y*y), which is the same as `FT_Vector_Length' but uses + * two fixed-point arguments instead. + */ + FT_BASE( FT_Fixed ) + FT_Hypot( FT_Fixed x, + FT_Fixed y ); + + + /************************************************************************** + * + * @function: + * FT_SqrtFixed + * + * @description: + * Computes the square root of a 16.16 fixed-point value. + * + * @input: + * x :: + * The value to compute the root for. + * + * @return: + * The result of 'sqrt(x)'. + * + * @note: + * This function is slow and should be avoided. Consider @FT_Hypot or + * @FT_Vector_NormLen instead. + */ + FT_BASE( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 x ); + + +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) * 64 ) /* << 6 */ +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) * 16384 ) /* << 14 */ +#define INT_TO_FIXED( x ) ( (FT_Long)(x) * 65536 ) /* << 16 */ +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) * 4 ) /* << 2 */ +#define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) + +#define ROUND_F26DOT6( x ) ( ( (x) + 32 - ( x < 0 ) ) & -64 ) + + /* + * The following macros have two purposes. + * + * - Tag places where overflow is expected and harmless. + * + * - Avoid run-time sanitizer errors. + * + * Use with care! + */ +#define ADD_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) +#define SUB_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) +#define MUL_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) +#define NEG_INT( a ) \ + (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) + +#define ADD_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) +#define SUB_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) +#define MUL_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) +#define NEG_LONG( a ) \ + (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) + +#define ADD_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) +#define SUB_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) +#define MUL_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) +#define NEG_INT32( a ) \ + (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) + +#ifdef FT_INT64 + +#define ADD_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) +#define SUB_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) +#define MUL_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) +#define NEG_INT64( a ) \ + (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) + +#endif /* FT_INT64 */ + + +FT_END_HEADER + +#endif /* FTCALC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftdebug.h b/Dependencies/freetype/freetype/include/freetype/internal/ftdebug.h new file mode 100644 index 00000000..d7fa8dc9 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftdebug.h @@ -0,0 +1,442 @@ +/**************************************************************************** + * + * ftdebug.h + * + * Debugging and logging component (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + * + * IMPORTANT: A description of FreeType's debugging support can be + * found in 'docs/DEBUG.TXT'. Read it if you need to use or + * understand this code. + * + */ + + +#ifndef FTDEBUG_H_ +#define FTDEBUG_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include "compiler-macros.h" + +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include +#include + +#include +#endif /* FT_DEBUG_LOGGING */ + + +FT_BEGIN_HEADER + + /* force the definition of FT_DEBUG_LEVEL_TRACE if FT_DEBUG_LOGGING is */ + /* already defined. */ + /* */ +#ifdef FT_DEBUG_LOGGING +#undef FT_DEBUG_LEVEL_TRACE +#define FT_DEBUG_LEVEL_TRACE +#endif + + /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ + /* is already defined; this simplifies the following #ifdefs */ + /* */ +#ifdef FT_DEBUG_LEVEL_TRACE +#undef FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_ERROR +#endif + + + /************************************************************************** + * + * Define the trace enums as well as the trace levels array when they are + * needed. + * + */ + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define FT_TRACE_DEF( x ) trace_ ## x , + + /* defining the enumeration */ + typedef enum FT_Trace_ + { +#include + trace_count + + } FT_Trace; + + + /* a pointer to the array of trace levels, */ + /* provided by `src/base/ftdebug.c' */ + extern int* ft_trace_levels; + +#undef FT_TRACE_DEF + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Define the FT_TRACE macro + * + * IMPORTANT! + * + * Each component must define the macro FT_COMPONENT to a valid FT_Trace + * value before using any TRACE macro. + * + * To get consistent logging output, there should be no newline character + * (i.e., '\n') or a single trailing one in the message string of + * `FT_TRACEx` and `FT_ERROR`. + */ + + + /************************************************************************* + * + * If FT_DEBUG_LOGGING is enabled, tracing messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, tracing messages are sent to + * `FT_Message` (defined in ftdebug.c). + */ +#ifdef FT_DEBUG_LOGGING + + /* we need two macros to convert the names of `FT_COMPONENT` to a string */ +#define FT_LOGGING_TAG( x ) FT_LOGGING_TAG_( x ) +#define FT_LOGGING_TAG_( x ) #x + + /* we need two macros to convert the component and the trace level */ + /* to a string that combines them */ +#define FT_LOGGING_TAGX( x, y ) FT_LOGGING_TAGX_( x, y ) +#define FT_LOGGING_TAGX_( x, y ) #x ":" #y + + +#define FT_LOG( level, varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAGX( FT_COMPONENT, level ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + { \ + if ( custom_output_handler != NULL ) \ + FT_Logging_Callback varformat; \ + else \ + dlg_trace varformat; \ + } \ + ft_remove_tag( dlg_tag ); \ + } while( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_LOG( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + FT_Message varformat; \ + } while ( 0 ) + +#endif /* !FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* we need two macros here to make cpp expand `FT_COMPONENT' */ +#define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x ) +#define FT_TRACE_COMP_( x ) trace_ ## x + +#define FT_TRACE( level, varformat ) FT_LOG( level, varformat ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE( level, varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Get_Count + * + * @description: + * Return the number of available trace components. + * + * @return: + * The number of trace components. 0 if FreeType 2 is not built with + * FT_DEBUG_LEVEL_TRACE definition. + * + * @note: + * This function may be useful if you want to access elements of the + * internal trace levels array by an index. + */ + FT_BASE( FT_Int ) + FT_Trace_Get_Count( void ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Get_Name + * + * @description: + * Return the name of a trace component. + * + * @input: + * The index of the trace component. + * + * @return: + * The name of the trace component. This is a statically allocated + * C~string, so do not free it after use. `NULL` if FreeType is not + * built with FT_DEBUG_LEVEL_TRACE definition. + * + * @note: + * Use @FT_Trace_Get_Count to get the number of available trace + * components. + */ + FT_BASE( const char* ) + FT_Trace_Get_Name( FT_Int idx ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Disable + * + * @description: + * Switch off tracing temporarily. It can be activated again with + * @FT_Trace_Enable. + */ + FT_BASE( void ) + FT_Trace_Disable( void ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Enable + * + * @description: + * Activate tracing. Use it after tracing has been switched off with + * @FT_Trace_Disable. + */ + FT_BASE( void ) + FT_Trace_Enable( void ); + + + /************************************************************************** + * + * You need two opening and closing parentheses! + * + * Example: FT_TRACE0(( "Value is %i", foo )) + * + * Output of the FT_TRACEX macros is sent to stderr. + * + */ + +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) + + + /************************************************************************** + * + * Define the FT_ERROR macro. + * + * Output of this macro is sent to stderr. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + + /************************************************************************** + * + * If FT_DEBUG_LOGGING is enabled, error messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, error messages are sent to `FT_Message` + * (defined in ftdebug.c). + * + */ +#ifdef FT_DEBUG_LOGGING + +#define FT_ERROR( varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAG( FT_COMPONENT ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + dlg_trace varformat; \ + ft_remove_tag( dlg_tag ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_ERROR( varformat ) FT_Message varformat + +#endif /* !FT_DEBUG_LOGGING */ + + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ERROR( varformat ) do { } while ( 0 ) /* nothing */ + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /************************************************************************** + * + * Define the FT_ASSERT and FT_THROW macros. The call to `FT_Throw` makes + * it possible to easily set a breakpoint at this function. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#define FT_ASSERT( condition ) \ + do \ + { \ + if ( !( condition ) ) \ + FT_Panic( "assertion failed on line %d of file %s\n", \ + __LINE__, __FILE__ ); \ + } while ( 0 ) + +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( FT_ERR_PREFIX, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( FT_ERR_PREFIX, e ) ) + +#else /* !FT_DEBUG_LEVEL_ERROR */ + +#define FT_ASSERT( condition ) do { } while ( 0 ) + +#define FT_THROW( e ) FT_ERR_CAT( FT_ERR_PREFIX, e ) + +#endif /* !FT_DEBUG_LEVEL_ERROR */ + + + /************************************************************************** + * + * Define `FT_Message` and `FT_Panic` when needed. + * + */ + +#ifdef FT_DEBUG_LEVEL_ERROR + +#include "stdio.h" /* for vfprintf() */ + + /* print a message */ + FT_BASE( void ) + FT_Message( const char* fmt, + ... ); + + /* print a message and exit */ + FT_BASE( void ) + FT_Panic( const char* fmt, + ... ); + + /* report file name and line number of an error */ + FT_BASE( int ) + FT_Throw( FT_Error error, + int line, + const char* file ); + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + + FT_BASE( void ) + ft_debug_init( void ); + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * 'dlg' uses output handlers to control how and where log messages are + * printed. Therefore we need to define a default output handler for + * FreeType. + */ + FT_BASE( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ); + + + /************************************************************************** + * + * 1. `ft_default_log_handler` stores the function pointer that is used + * internally by FreeType to print logs to a file. + * + * 2. `custom_output_handler` stores the function pointer to the callback + * function provided by the user. + * + * It is defined in `ftdebug.c`. + */ + extern dlg_handler ft_default_log_handler; + extern FT_Custom_Log_Handler custom_output_handler; + + + /************************************************************************** + * + * If FT_DEBUG_LOGGING macro is enabled, FreeType needs to initialize and + * un-initialize `FILE*`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_logging_init( void ); + + FT_BASE( void ) + ft_logging_deinit( void ); + + + /************************************************************************** + * + * For printing the name of `FT_COMPONENT` along with the actual log we + * need to add a tag with the name of `FT_COMPONENT`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_add_tag( const char* tag ); + + FT_BASE( void ) + ft_remove_tag( const char* tag ); + + + /************************************************************************** + * + * A function to print log data using a custom callback logging function + * (which is set using `FT_Set_Log_Handler`). + * + * This function is defined in `ftdebug.c`. + */ + FT_BASE( void ) + FT_Logging_Callback( const char* fmt, + ... ); + +#endif /* FT_DEBUG_LOGGING */ + + +FT_END_HEADER + +#endif /* FTDEBUG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftdrv.h b/Dependencies/freetype/freetype/include/freetype/internal/ftdrv.h new file mode 100644 index 00000000..5609b3ef --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftdrv.h @@ -0,0 +1,289 @@ +/**************************************************************************** + * + * ftdrv.h + * + * FreeType internal font driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTDRV_H_ +#define FTDRV_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + typedef FT_Error + (*FT_Face_InitFunc)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + + typedef void + (*FT_Face_DoneFunc)( FT_Face face ); + + + typedef FT_Error + (*FT_Size_InitFunc)( FT_Size size ); + + typedef void + (*FT_Size_DoneFunc)( FT_Size size ); + + + typedef FT_Error + (*FT_Slot_InitFunc)( FT_GlyphSlot slot ); + + typedef void + (*FT_Slot_DoneFunc)( FT_GlyphSlot slot ); + + + typedef FT_Error + (*FT_Size_RequestFunc)( FT_Size size, + FT_Size_Request req ); + + typedef FT_Error + (*FT_Size_SelectFunc)( FT_Size size, + FT_ULong size_index ); + + typedef FT_Error + (*FT_Slot_LoadFunc)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + typedef FT_Error + (*FT_Face_GetKerningFunc)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + + + typedef FT_Error + (*FT_Face_AttachFunc)( FT_Face face, + FT_Stream stream ); + + + typedef FT_Error + (*FT_Face_GetAdvancesFunc)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ); + + + /************************************************************************** + * + * @struct: + * FT_Driver_ClassRec + * + * @description: + * The font driver class. This structure mostly contains pointers to + * driver methods. + * + * @fields: + * root :: + * The parent module. + * + * face_object_size :: + * The size of a face object in bytes. + * + * size_object_size :: + * The size of a size object in bytes. + * + * slot_object_size :: + * The size of a glyph object in bytes. + * + * init_face :: + * The format-specific face constructor. + * + * done_face :: + * The format-specific face destructor. + * + * init_size :: + * The format-specific size constructor. + * + * done_size :: + * The format-specific size destructor. + * + * init_slot :: + * The format-specific slot constructor. + * + * done_slot :: + * The format-specific slot destructor. + * + * + * load_glyph :: + * A function handle to load a glyph to a slot. This field is + * mandatory! + * + * get_kerning :: + * A function handle to return the unscaled kerning for a given pair of + * glyphs. Can be set to 0 if the format doesn't support kerning. + * + * attach_file :: + * This function handle is used to read additional data for a face from + * another file/stream. For example, this can be used to add data from + * AFM or PFM files on a Type 1 face, or a CIDMap on a CID-keyed face. + * + * get_advances :: + * A function handle used to return advance widths of 'count' glyphs + * (in font units), starting at 'first'. The 'vertical' flag must be + * set to get vertical advance heights. The 'advances' buffer is + * caller-allocated. The idea of this function is to be able to + * perform device-independent text layout without loading a single + * glyph image. + * + * request_size :: + * A handle to a function used to request the new character size. Can + * be set to 0 if the scaling done in the base layer suffices. + * + * select_size :: + * A handle to a function used to select a new fixed size. It is used + * only if @FT_FACE_FLAG_FIXED_SIZES is set. Can be set to 0 if the + * scaling done in the base layer suffices. + * + * @note: + * Most function pointers, with the exception of `load_glyph`, can be set + * to 0 to indicate a default behaviour. + */ + typedef struct FT_Driver_ClassRec_ + { + FT_Module_Class root; + + FT_Long face_object_size; + FT_Long size_object_size; + FT_Long slot_object_size; + + FT_Face_InitFunc init_face; + FT_Face_DoneFunc done_face; + + FT_Size_InitFunc init_size; + FT_Size_DoneFunc done_size; + + FT_Slot_InitFunc init_slot; + FT_Slot_DoneFunc done_slot; + + FT_Slot_LoadFunc load_glyph; + + FT_Face_GetKerningFunc get_kerning; + FT_Face_AttachFunc attach_file; + FT_Face_GetAdvancesFunc get_advances; + + /* since version 2.2 */ + FT_Size_RequestFunc request_size; + FT_Size_SelectFunc select_size; + + } FT_Driver_ClassRec, *FT_Driver_Class; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_DRIVER + * + * @description: + * Used to create a forward declaration of an FT_Driver_ClassRec struct + * instance. + * + * @macro: + * FT_DEFINE_DRIVER + * + * @description: + * Used to initialize an instance of FT_Driver_ClassRec struct. + * + * `ftinit.c` (ft_create_default_module_classes) already contains a + * mechanism to call these functions for the default modules described in + * `ftmodule.h`. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_DRIVER( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Driver_ClassRec class_; + +#define FT_DEFINE_DRIVER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + init_face_, \ + done_face_, \ + init_size_, \ + done_size_, \ + init_slot_, \ + done_slot_, \ + load_glyph_, \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + request_size_, \ + select_size_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Driver_ClassRec class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + \ + init_face_, \ + done_face_, \ + \ + init_size_, \ + done_size_, \ + \ + init_slot_, \ + done_slot_, \ + \ + load_glyph_, \ + \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + \ + request_size_, \ + select_size_ \ + }; + + +FT_END_HEADER + +#endif /* FTDRV_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftgloadr.h b/Dependencies/freetype/freetype/include/freetype/internal/ftgloadr.h new file mode 100644 index 00000000..f1c155b1 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftgloadr.h @@ -0,0 +1,147 @@ +/**************************************************************************** + * + * ftgloadr.h + * + * The FreeType glyph loader (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGLOADR_H_ +#define FTGLOADR_H_ + + +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * FT_GlyphLoader + * + * @description: + * The glyph loader is an internal object used to load several glyphs + * together (for example, in the case of composites). + */ + typedef struct FT_SubGlyphRec_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + + } FT_SubGlyphRec; + + + typedef struct FT_GlyphLoadRec_ + { + FT_Outline outline; /* outline */ + FT_Vector* extra_points; /* extra points table */ + FT_Vector* extra_points2; /* second extra points table */ + FT_UInt num_subglyphs; /* number of subglyphs */ + FT_SubGlyph subglyphs; /* subglyphs */ + + } FT_GlyphLoadRec, *FT_GlyphLoad; + + + typedef struct FT_GlyphLoaderRec_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + + FT_GlyphLoadRec base; + FT_GlyphLoadRec current; + + void* other; /* for possible future extension? */ + + } FT_GlyphLoaderRec, *FT_GlyphLoader; + + + /* create new empty glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ); + + /* add an extra points table to a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ); + + /* destroy a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ); + + /* reset a glyph loader (frees everything int it) */ + FT_BASE( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ); + + /* rewind a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ); + + /* check that there is enough space to add `n_points' and `n_contours' */ + /* to the glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ); + + +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || \ + ( (FT_UInt)(_loader)->base.outline.n_points + \ + (FT_UInt)(_loader)->current.outline.n_points + \ + (FT_UInt)(_count) ) <= (_loader)->max_points ) + +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || \ + ( (FT_UInt)(_loader)->base.outline.n_contours + \ + (FT_UInt)(_loader)->current.outline.n_contours + \ + (FT_UInt)(_count) ) <= (_loader)->max_contours ) + +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points, _contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ + : FT_GlyphLoader_CheckPoints( (_loader), \ + (FT_UInt)(_points), \ + (FT_UInt)(_contours) ) ) + + + /* check that there is enough space to add `n_subs' sub-glyphs to */ + /* a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ); + + /* prepare a glyph loader, i.e. empty the current glyph */ + FT_BASE( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ); + + /* add the current glyph to the base glyph */ + FT_BASE( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ); + + +FT_END_HEADER + +#endif /* FTGLOADR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/fthash.h b/Dependencies/freetype/freetype/include/freetype/internal/fthash.h new file mode 100644 index 00000000..622ec76b --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/fthash.h @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * fthash.h + * + * Hashing functions (specification). + * + */ + +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2015 + * Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on code from bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + +#ifndef FTHASH_H_ +#define FTHASH_H_ + + +#include + + +FT_BEGIN_HEADER + + + typedef union FT_Hashkey_ + { + FT_Int num; + const char* str; + + } FT_Hashkey; + + + typedef struct FT_HashnodeRec_ + { + FT_Hashkey key; + size_t data; + + } FT_HashnodeRec; + + typedef struct FT_HashnodeRec_ *FT_Hashnode; + + + typedef FT_ULong + (*FT_Hash_LookupFunc)( FT_Hashkey* key ); + + typedef FT_Bool + (*FT_Hash_CompareFunc)( FT_Hashkey* a, + FT_Hashkey* b ); + + + typedef struct FT_HashRec_ + { + FT_UInt limit; + FT_UInt size; + FT_UInt used; + + FT_Hash_LookupFunc lookup; + FT_Hash_CompareFunc compare; + + FT_Hashnode* table; + + } FT_HashRec; + + typedef struct FT_HashRec_ *FT_Hash; + + + FT_Error + ft_hash_str_init( FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_init( FT_Hash hash, + FT_Memory memory ); + + void + ft_hash_str_free( FT_Hash hash, + FT_Memory memory ); + +#define ft_hash_num_free ft_hash_str_free + + FT_Error + ft_hash_str_insert( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_insert( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + size_t* + ft_hash_str_lookup( const char* key, + FT_Hash hash ); + + size_t* + ft_hash_num_lookup( FT_Int num, + FT_Hash hash ); + + +FT_END_HEADER + + +#endif /* FTHASH_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftmemory.h b/Dependencies/freetype/freetype/include/freetype/internal/ftmemory.h new file mode 100644 index 00000000..4e05a29f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftmemory.h @@ -0,0 +1,401 @@ +/**************************************************************************** + * + * ftmemory.h + * + * The FreeType memory management macros (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMEMORY_H_ +#define FTMEMORY_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @macro: + * FT_SET_ERROR + * + * @description: + * This macro is used to set an implicit 'error' variable to a given + * expression's value (usually a function call), and convert it to a + * boolean which is set whenever the value is != 0. + */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) + + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M E M O R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* The calculation `NULL + n' is undefined in C. Even if the resulting */ + /* pointer doesn't get dereferenced, this causes warnings with */ + /* sanitizers. */ + /* */ + /* We thus provide a macro that should be used if `base' can be NULL. */ +#define FT_OFFSET( base, count ) ( (base) ? (base) + (count) : NULL ) + + + /* + * C++ refuses to handle statements like p = (void*)anything, with `p' a + * typed pointer. Since we don't have a `typeof' operator in standard C++, + * we have to use a template to emulate it. + */ + +#ifdef __cplusplus + +extern "C++" +{ + template inline T* + cplusplus_typeof( T*, + void *v ) + { + return static_cast ( v ); + } +} + +#define FT_ASSIGNP( p, val ) (p) = cplusplus_typeof( (p), (val) ) + +#else + +#define FT_ASSIGNP( p, val ) (p) = (val) + +#endif + + + +#ifdef FT_DEBUG_MEMORY + + FT_BASE( const char* ) ft_debug_file_; + FT_BASE( long ) ft_debug_lineno_; + +#define FT_DEBUG_INNER( exp ) ( ft_debug_file_ = __FILE__, \ + ft_debug_lineno_ = __LINE__, \ + (exp) ) + +#define FT_ASSIGNP_INNER( p, exp ) ( ft_debug_file_ = __FILE__, \ + ft_debug_lineno_ = __LINE__, \ + FT_ASSIGNP( p, exp ) ) + +#else /* !FT_DEBUG_MEMORY */ + +#define FT_DEBUG_INNER( exp ) (exp) +#define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) + +#endif /* !FT_DEBUG_MEMORY */ + + + /* + * The allocation functions return a pointer, and the error code is written + * to through the `p_error' parameter. + */ + + /* The `q' variants of the functions below (`q' for `quick') don't fill */ + /* the allocated or reallocated memory with zero bytes. */ + + FT_BASE( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + + FT_BASE( void ) + ft_mem_free( FT_Memory memory, + const void* P ); + + + /* The `Q' variants of the macros below (`Q' for `quick') don't fill */ + /* the allocated or reallocated memory with zero bytes. */ + +#define FT_MEM_ALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, \ + (FT_Long)(size), \ + &error ) ) + +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + FT_DEBUG_INNER( ft_mem_free( memory, (ptr) ) ); \ + (ptr) = NULL; \ + FT_END_STMNT + +#define FT_MEM_NEW( ptr ) \ + FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_REALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + 1, \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, \ + (FT_Long)(size), \ + &error ) ) + +#define FT_MEM_QNEW( ptr ) \ + FT_MEM_QALLOC( ptr, sizeof ( *(ptr) ) ) + +#define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + 1, \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + (FT_Long)(item_size), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + (FT_Long)(itmsz), \ + (FT_Long)(oldcnt), \ + (FT_Long)(newcnt), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + (FT_Long)(item_size), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + (FT_Long)(itmsz), \ + (FT_Long)(oldcnt), \ + (FT_Long)(newcnt), \ + (ptr), \ + &error ) ) + + +#define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) + + +#define FT_MEM_SET( dest, byte, count ) \ + ft_memset( dest, byte, (FT_Offset)(count) ) + +#define FT_MEM_COPY( dest, source, count ) \ + ft_memcpy( dest, source, (FT_Offset)(count) ) + +#define FT_MEM_MOVE( dest, source, count ) \ + ft_memmove( dest, source, (FT_Offset)(count) ) + + +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) + +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) + + +#define FT_ARRAY_ZERO( dest, count ) \ + FT_MEM_ZERO( dest, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_COPY( dest, source, count ) \ + FT_MEM_COPY( dest, \ + source, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + +#define FT_ARRAY_MOVE( dest, source, count ) \ + FT_MEM_MOVE( dest, \ + source, \ + (FT_Offset)(count) * sizeof ( *(dest) ) ) + + + /* + * Return the maximum number of addressable elements in an array. We limit + * ourselves to INT_MAX, rather than UINT_MAX, to avoid any problems. + */ +#define FT_ARRAY_MAX( ptr ) ( FT_INT_MAX / sizeof ( *(ptr) ) ) + +#define FT_ARRAY_CHECK( ptr, count ) ( (count) <= FT_ARRAY_MAX( ptr ) ) + + + /************************************************************************** + * + * The following functions macros expect that their pointer argument is + * _typed_ in order to automatically compute array element sizes. + */ + +#define FT_MEM_NEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + sizeof ( *(ptr) ), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, \ + sizeof ( *(ptr) ), \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_MEM_QNEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + sizeof ( *(ptr) ), \ + 0, \ + (FT_Long)(count), \ + NULL, \ + &error ) ) + +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, \ + sizeof ( *(ptr) ), \ + (FT_Long)(cursz), \ + (FT_Long)(newsz), \ + (ptr), \ + &error ) ) + +#define FT_ALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) + +#define FT_REALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) + +#define FT_ALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) + +#define FT_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_QALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) + +#define FT_QREALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) + +#define FT_QALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT( ptr, count, item_size ) ) + +#define FT_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) + +#define FT_FREE( ptr ) FT_MEM_FREE( ptr ) + +#define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) + +#define FT_NEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) + +#define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + +#define FT_QNEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) + +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW_ARRAY( ptr, count ) ) + +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_QRENEW_ARRAY( ptr, curcnt, newcnt ) ) + + + FT_BASE( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ); + + FT_BASE( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ); + + +#define FT_MEM_STRDUP( dst, str ) \ + (dst) = (char*)ft_mem_strdup( memory, (const char*)(str), &error ) + +#define FT_STRDUP( dst, str ) \ + FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) + +#define FT_MEM_DUP( dst, address, size ) \ + FT_ASSIGNP_INNER( dst, ft_mem_dup( memory, \ + (address), \ + (FT_ULong)(size), \ + &error ) ) + +#define FT_DUP( dst, address, size ) \ + FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) + + + /* Return >= 1 if a truncation occurs. */ + /* Return 0 if the source string fits the buffer. */ + /* This is *not* the same as strlcpy(). */ + FT_BASE( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ); + +#define FT_STRCPYN( dst, src, size ) \ + ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) + + +FT_END_HEADER + +#endif /* FTMEMORY_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftmmtypes.h b/Dependencies/freetype/freetype/include/freetype/internal/ftmmtypes.h new file mode 100644 index 00000000..8449e7a0 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftmmtypes.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * ftmmtypes.h + * + * OpenType Variations type definitions for internal use + * with the multi-masters service (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and + * Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTMMTYPES_H_ +#define FTMMTYPES_H_ + +FT_BEGIN_HEADER + + + typedef FT_Int32 FT_ItemVarDelta; + + typedef struct GX_ItemVarDataRec_ + { + FT_UInt itemCount; /* Number of delta sets per item. */ + FT_UInt regionIdxCount; /* Number of region indices. */ + FT_UInt* regionIndices; /* Array of `regionCount` indices; */ + /* these index `varRegionList`. */ + FT_Byte* deltaSet; /* Array of `itemCount` deltas; */ + /* use `innerIndex` for this array. */ + FT_UShort wordDeltaCount; /* Number of the first 32-bit ints */ + /* or 16-bit ints of `deltaSet` */ + /* depending on `longWords`. */ + FT_Bool longWords; /* If true, `deltaSet` is a 32-bit */ + /* array followed by a 16-bit */ + /* array, otherwise a 16-bit array */ + /* followed by an 8-bit array. */ + } GX_ItemVarDataRec, *GX_ItemVarData; + + + /* contribution of one axis to a region */ + typedef struct GX_AxisCoordsRec_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero means no effect (factor = 1) */ + FT_Fixed endCoord; + + } GX_AxisCoordsRec, *GX_AxisCoords; + + + typedef struct GX_VarRegionRec_ + { + GX_AxisCoords axisList; /* array of axisCount records */ + + } GX_VarRegionRec, *GX_VarRegion; + + + /* item variation store */ + typedef struct GX_ItemVarStoreRec_ + { + FT_UInt dataCount; + GX_ItemVarData varData; /* array of dataCount records; */ + /* use `outerIndex' for this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + GX_VarRegion varRegionList; + + } GX_ItemVarStoreRec, *GX_ItemVarStore; + + + typedef struct GX_DeltaSetIdxMapRec_ + { + FT_ULong mapCount; + FT_UInt* outerIndex; /* indices to item var data */ + FT_UInt* innerIndex; /* indices to delta set */ + + } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; + + +FT_END_HEADER + +#endif /* FTMMTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftobjs.h b/Dependencies/freetype/freetype/include/freetype/internal/ftobjs.h new file mode 100644 index 00000000..a1e93298 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftobjs.h @@ -0,0 +1,1232 @@ +/**************************************************************************** + * + * ftobjs.h + * + * The FreeType private base classes (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file contains the definition of all internal FreeType classes. + * + */ + + +#ifndef FTOBJS_H_ +#define FTOBJS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#include +#endif + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Some generic definitions. + */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + + + /************************************************************************** + * + * The min and max functions missing in C. As usual, be careful not to + * write things like FT_MIN( a++, b++ ) to avoid side effects. + */ +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + /* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' algorithm. + * We use alpha = 1, beta = 3/8, giving us results with a largest error + * less than 7% compared to the exact value. + */ +#define FT_HYPOT( x, y ) \ + ( x = FT_ABS( x ), \ + y = FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + + /* we use FT_TYPEOF to suppress signedness compilation warnings */ +#define FT_PAD_FLOOR( x, n ) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + (n) / 2, n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + (n) - 1, n ) + +#define FT_PIX_FLOOR( x ) ( (x) & ~FT_TYPEOF( x )63 ) +#define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) +#define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) + + /* specialized versions (for signed values) */ + /* that don't produce run-time errors due to integer overflow */ +#define FT_PAD_ROUND_LONG( x, n ) FT_PAD_FLOOR( ADD_LONG( (x), (n) / 2 ), \ + n ) +#define FT_PAD_CEIL_LONG( x, n ) FT_PAD_FLOOR( ADD_LONG( (x), (n) - 1 ), \ + n ) +#define FT_PIX_ROUND_LONG( x ) FT_PIX_FLOOR( ADD_LONG( (x), 32 ) ) +#define FT_PIX_CEIL_LONG( x ) FT_PIX_FLOOR( ADD_LONG( (x), 63 ) ) + +#define FT_PAD_ROUND_INT32( x, n ) FT_PAD_FLOOR( ADD_INT32( (x), (n) / 2 ), \ + n ) +#define FT_PAD_CEIL_INT32( x, n ) FT_PAD_FLOOR( ADD_INT32( (x), (n) - 1 ), \ + n ) +#define FT_PIX_ROUND_INT32( x ) FT_PIX_FLOOR( ADD_INT32( (x), 32 ) ) +#define FT_PIX_CEIL_INT32( x ) FT_PIX_FLOOR( ADD_INT32( (x), 63 ) ) + + + /* + * character classification functions -- since these are used to parse font + * files, we must not use those in which are locale-dependent + */ +#define ft_isdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U ) + +#define ft_isxdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U || \ + ( (unsigned)(x) - 'a' ) < 6U || \ + ( (unsigned)(x) - 'A' ) < 6U ) + + /* the next two macros assume ASCII representation */ +#define ft_isupper( x ) ( ( (unsigned)(x) - 'A' ) < 26U ) +#define ft_islower( x ) ( ( (unsigned)(x) - 'a' ) < 26U ) + +#define ft_isalpha( x ) ( ft_isupper( x ) || ft_islower( x ) ) +#define ft_isalnum( x ) ( ft_isdigit( x ) || ft_isalpha( x ) ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** C H A R M A P S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to internal charmap object */ + typedef struct FT_CMapRec_* FT_CMap; + + /* handle to charmap class structure */ + typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; + + /* internal charmap object structure */ + typedef struct FT_CMapRec_ + { + FT_CharMapRec charmap; + FT_CMap_Class clazz; + + } FT_CMapRec; + + /* typecast any pointer to a charmap handle */ +#define FT_CMAP( x ) ( (FT_CMap)( x ) ) + + /* obvious macros */ +#define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id +#define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id +#define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding +#define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face + + + /* class method definitions */ + typedef FT_Error + (*FT_CMap_InitFunc)( FT_CMap cmap, + FT_Pointer init_data ); + + typedef void + (*FT_CMap_DoneFunc)( FT_CMap cmap ); + + typedef FT_UInt + (*FT_CMap_CharIndexFunc)( FT_CMap cmap, + FT_UInt32 char_code ); + + typedef FT_UInt + (*FT_CMap_CharNextFunc)( FT_CMap cmap, + FT_UInt32 *achar_code ); + + typedef FT_UInt + (*FT_CMap_CharVarIndexFunc)( FT_CMap cmap, + FT_CMap unicode_cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_Int + (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + + typedef FT_UInt32 * + (*FT_CMap_VariantListFunc)( FT_CMap cmap, + FT_Memory mem ); + + typedef FT_UInt32 * + (*FT_CMap_CharVariantListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 char_code ); + + typedef FT_UInt32 * + (*FT_CMap_VariantCharListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 variant_selector ); + + + typedef struct FT_CMap_ClassRec_ + { + FT_ULong size; + + FT_CMap_InitFunc init; + FT_CMap_DoneFunc done; + FT_CMap_CharIndexFunc char_index; + FT_CMap_CharNextFunc char_next; + + /* Subsequent entries are special ones for format 14 -- the variant */ + /* selector subtable which behaves like no other */ + + FT_CMap_CharVarIndexFunc char_var_index; + FT_CMap_CharVarIsDefaultFunc char_var_default; + FT_CMap_VariantListFunc variant_list; + FT_CMap_CharVariantListFunc charvariant_list; + FT_CMap_VariantCharListFunc variantchar_list; + + } FT_CMap_ClassRec; + + +#define FT_DECLARE_CMAP_CLASS( class_ ) \ + FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; + +#define FT_DEFINE_CMAP_CLASS( \ + class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_CMap_ClassRec class_ = \ + { \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }; + + + /* create a new charmap and add it to charmap->face */ + FT_BASE( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ); + + /* destroy a charmap and remove it from face's list */ + FT_BASE( void ) + FT_CMap_Done( FT_CMap cmap ); + + + /* add LCD padding to CBox */ + FT_BASE( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ); + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, + FT_Byte* weights ); + + + /* This is the default LCD filter, an in-place, 5-tap FIR filter. */ + FT_BASE( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_LcdFiveTapFilter weights ); + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /************************************************************************** + * + * @struct: + * FT_Face_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_Face object. + * These fields may change between different releases of FreeType. + * + * @fields: + * max_points :: + * The maximum number of points used to store the vectorial outline of + * any glyph in this face. If this value cannot be known in advance, + * or if the face isn't scalable, this should be set to 0. Only + * relevant for scalable formats. + * + * max_contours :: + * The maximum number of contours used to store the vectorial outline + * of any glyph in this face. If this value cannot be known in + * advance, or if the face isn't scalable, this should be set to 0. + * Only relevant for scalable formats. + * + * transform_matrix :: + * A 2x2 matrix of 16.16 coefficients used to transform glyph outlines + * after they are loaded from the font. Only used by the convenience + * functions. + * + * transform_delta :: + * A translation vector used to transform glyph outlines after they are + * loaded from the font. Only used by the convenience functions. + * + * transform_flags :: + * Some flags used to classify the transform. Only used by the + * convenience functions. + * + * services :: + * A cache for frequently used services. It should be only accessed + * with the macro `FT_FACE_LOOKUP_SERVICE`. + * + * incremental_interface :: + * If non-null, the interface through which glyph data and metrics are + * loaded incrementally for faces that do not provide all of this data + * when first opened. This field exists only if + * @FT_CONFIG_OPTION_INCREMENTAL is defined. + * + * no_stem_darkening :: + * Overrides the module-level default, see @stem-darkening[cff], for + * example. FALSE and TRUE toggle stem darkening on and off, + * respectively, value~-1 means to use the module/driver default. + * + * random_seed :: + * If positive, override the seed value for the CFF 'random' operator. + * Value~0 means to use the font's value. Value~-1 means to use the + * CFF driver's default. + * + * lcd_weights :: + * lcd_filter_func :: + * These fields specify the LCD filtering weights and callback function + * for ClearType-style subpixel rendering. + * + * refcount :: + * A counter initialized to~1 at the time an @FT_Face structure is + * created. @FT_Reference_Face increments this counter, and + * @FT_Done_Face only destroys a face if the counter is~1, otherwise it + * simply decrements it. + */ + typedef struct FT_Face_InternalRec_ + { + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + + FT_ServiceCacheRec services; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec* incremental_interface; +#endif + + FT_Char no_stem_darkening; + FT_Int32 random_seed; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#endif + + FT_Int refcount; + + } FT_Face_InternalRec; + + + /************************************************************************** + * + * @struct: + * FT_Slot_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_GlyphSlot + * object. These fields may change between different releases of + * FreeType. + * + * @fields: + * loader :: + * The glyph loader object used to load outlines into the glyph slot. + * + * flags :: + * Possible values are zero or FT_GLYPH_OWN_BITMAP. The latter + * indicates that the FT_GlyphSlot structure owns the bitmap buffer. + * + * glyph_transformed :: + * Boolean. Set to TRUE when the loaded glyph must be transformed + * through a specific font transformation. This is _not_ the same as + * the face transform set through FT_Set_Transform(). + * + * glyph_matrix :: + * The 2x2 matrix corresponding to the glyph transformation, if + * necessary. + * + * glyph_delta :: + * The 2d translation vector corresponding to the glyph transformation, + * if necessary. + * + * glyph_hints :: + * Format-specific glyph hints management. + * + * load_flags :: + * The load flags passed as an argument to @FT_Load_Glyph while + * initializing the glyph slot. + */ + +#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_GZIP_SVG 0x2U + + typedef struct FT_Slot_InternalRec_ + { + FT_GlyphLoader loader; + FT_UInt flags; + FT_Bool glyph_transformed; + FT_Matrix glyph_matrix; + FT_Vector glyph_delta; + void* glyph_hints; + + FT_Int32 load_flags; + + } FT_GlyphSlot_InternalRec; + + + /************************************************************************** + * + * @struct: + * FT_Size_InternalRec + * + * @description: + * This structure contains the internal fields of each FT_Size object. + * + * @fields: + * module_data :: + * Data specific to a driver module. + * + * autohint_mode :: + * The used auto-hinting mode. + * + * autohint_metrics :: + * Metrics used by the auto-hinter. + * + */ + + typedef struct FT_Size_InternalRec_ + { + void* module_data; + + FT_Render_Mode autohint_mode; + FT_Size_Metrics autohint_metrics; + + } FT_Size_InternalRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FT_ModuleRec + * + * @description: + * A module object instance. + * + * @fields: + * clazz :: + * A pointer to the module's class. + * + * library :: + * A handle to the parent library object. + * + * memory :: + * A handle to the memory manager. + */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + + } FT_ModuleRec; + + + /* typecast an object to an FT_Module */ +#define FT_MODULE( x ) ( (FT_Module)(x) ) + +#define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library +#define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory + + +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_FONT_DRIVER ) + +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_RENDERER ) + +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_HINTER ) + +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_STYLER ) + +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_SCALABLE ) + +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_NO_OUTLINES ) + +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HAS_HINTER ) + +#define FT_DRIVER_HINTS_LIGHTLY( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HINTS_LIGHTLY ) + + + /************************************************************************** + * + * @function: + * FT_Get_Module_Interface + * + * @description: + * Finds a module and returns its specific interface as a typeless + * pointer. + * + * @input: + * library :: + * A handle to the library object. + * + * module_name :: + * The module's name (as an ASCII string). + * + * @return: + * A module-specific interface if available, 0 otherwise. + * + * @note: + * You should better be familiar with FreeType internals to know which + * module to look for, and what its interface is :-) + */ + FT_BASE( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + + FT_BASE( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id, + FT_Bool global ); + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_BASE( FT_Error ) + ft_property_string_set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + FT_String* value ); +#endif + + /* */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E, S I Z E & G L Y P H S L O T O B J E C T S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* a few macros used to perform easy typecasts with minimal brain damage */ + +#define FT_FACE( x ) ( (FT_Face)(x) ) +#define FT_SIZE( x ) ( (FT_Size)(x) ) +#define FT_SLOT( x ) ( (FT_GlyphSlot)(x) ) + +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory +#define FT_FACE_STREAM( x ) FT_FACE( x )->stream + + + /************************************************************************** + * + * @function: + * FT_New_GlyphSlot + * + * @description: + * It is sometimes useful to have more than one glyph slot for a given + * face object. This function is used to create additional slots. All + * of them are automatically discarded when the face is destroyed. + * + * @input: + * face :: + * A handle to a parent face object. + * + * @output: + * aslot :: + * A handle to a new glyph slot object. + * + * @return: + * FreeType error code. 0 means success. + */ + FT_BASE( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ); + + + /************************************************************************** + * + * @function: + * FT_Done_GlyphSlot + * + * @description: + * Destroys a given glyph slot. Remember however that all slots are + * automatically destroyed with its parent. Using this function is not + * always mandatory. + * + * @input: + * slot :: + * A handle to a target glyph slot. + */ + FT_BASE( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ); + + /* */ + +#define FT_REQUEST_WIDTH( req ) \ + ( (req)->horiResolution \ + ? ( (req)->width * (FT_Pos)(req)->horiResolution + 36 ) / 72 \ + : (req)->width ) + +#define FT_REQUEST_HEIGHT( req ) \ + ( (req)->vertResolution \ + ? ( (req)->height * (FT_Pos)(req)->vertResolution + 36 ) / 72 \ + : (req)->height ) + + + /* Set the metrics according to a bitmap strike. */ + FT_BASE( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ); + + + /* Set the metrics according to a size request. */ + FT_BASE( FT_Error ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ); + + + /* Match a size request against `available_sizes'. */ + FT_BASE( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ); + + + /* Use the horizontal metrics to synthesize the vertical metrics. */ + /* If `advance' is zero, it is also synthesized. */ + FT_BASE( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ); + + + /* Free the bitmap of a given glyphslot when needed (i.e., only when it */ + /* was allocated with ft_glyphslot_alloc_bitmap). */ + FT_BASE( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ); + + + /* Preset bitmap metrics of an outline glyphslot prior to rendering */ + /* and check whether the truncated bbox is too large for rendering. */ + FT_BASE( FT_Bool ) + ft_glyphslot_preset_bitmap( FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ); + + /* Allocate a new bitmap buffer in a glyph slot. */ + FT_BASE( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ); + + + /* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */ + /* will not be freed by a later call to ft_glyphslot_free_bitmap. */ + FT_BASE( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ); + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define FT_RENDERER( x ) ( (FT_Renderer)(x) ) +#define FT_GLYPH( x ) ( (FT_Glyph)(x) ) +#define FT_BITMAP_GLYPH( x ) ( (FT_BitmapGlyph)(x) ) +#define FT_OUTLINE_GLYPH( x ) ( (FT_OutlineGlyph)(x) ) + + + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + FT_Glyph_Class glyph_class; + + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FT_Renderer_RenderFunc render; + + } FT_RendererRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F O N T D R I V E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ( (FT_Driver)(x) ) + + /* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz + + + /************************************************************************** + * + * @struct: + * FT_DriverRec + * + * @description: + * The root font driver class. A font driver is responsible for managing + * and loading font files of a given format. + * + * @fields: + * root :: + * Contains the fields of the root module class. + * + * clazz :: + * A pointer to the font driver's class. Note that this is NOT + * root.clazz. 'class' wasn't used as it is a reserved word in C++. + * + * faces_list :: + * The list of faces currently opened by this driver. + * + * glyph_loader :: + * Unused. Used to be glyph loader for all faces managed by this + * driver. + */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class clazz; + FT_ListRec faces_list; + FT_GlyphLoader glyph_loader; + + } FT_DriverRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R I E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * FT_LibraryRec + * + * @description: + * The FreeType library class. This is the root of all FreeType data. + * Use FT_New_Library() to create a library object, and FT_Done_Library() + * to discard it and all child objects. + * + * @fields: + * memory :: + * The library's memory object. Manages memory allocation. + * + * version_major :: + * The major version number of the library. + * + * version_minor :: + * The minor version number of the library. + * + * version_patch :: + * The current patch level of the library. + * + * num_modules :: + * The number of modules currently registered within this library. + * This is set to 0 for new libraries. New modules are added through + * the FT_Add_Module() API function. + * + * modules :: + * A table used to store handles to the currently registered + * modules. Note that each font driver contains a list of its opened + * faces. + * + * renderers :: + * The list of renderers currently registered within the library. + * + * cur_renderer :: + * The current outline renderer. This is a shortcut used to avoid + * parsing the list on each call to FT_Outline_Render(). It is a + * handle to the current renderer for the FT_GLYPH_FORMAT_OUTLINE + * format. + * + * auto_hinter :: + * The auto-hinter module interface. + * + * debug_hooks :: + * An array of four function pointers that allow debuggers to hook into + * a font format's interpreter. Currently, only the TrueType bytecode + * debugger uses this. + * + * lcd_weights :: + * The LCD filter weights for ClearType-style subpixel rendering. + * + * lcd_filter_func :: + * The LCD filtering callback function for for ClearType-style subpixel + * rendering. + * + * lcd_geometry :: + * This array specifies LCD subpixel geometry and controls Harmony LCD + * rendering technique, alternative to ClearType. + * + * pic_container :: + * Contains global structs and tables, instead of defining them + * globally. + * + * refcount :: + * A counter initialized to~1 at the time an @FT_Library structure is + * created. @FT_Reference_Library increments this counter, and + * @FT_Done_Library only destroys a library if the counter is~1, + * otherwise it simply decrements it. + */ + typedef struct FT_LibraryRec_ + { + FT_Memory memory; /* library's memory manager */ + + FT_Int version_major; + FT_Int version_minor; + FT_Int version_patch; + + FT_UInt num_modules; + FT_Module modules[FT_MAX_MODULES]; /* module objects */ + + FT_ListRec renderers; /* list of renderers */ + FT_Renderer cur_renderer; /* current outline renderer */ + FT_Module auto_hinter; + + FT_DebugHook_Func debug_hooks[4]; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ +#else + FT_Vector lcd_geometry[3]; /* RGB subpixel positions */ +#endif + + FT_Int refcount; + + } FT_LibraryRec; + + + FT_BASE( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + + FT_BASE( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + + typedef const char* + (*FT_Face_GetPostscriptNameFunc)( FT_Face face ); + + typedef FT_Error + (*FT_Face_GetGlyphNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_Face_GetGlyphNameIndexFunc)( FT_Face face, + const FT_String* glyph_name ); + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /************************************************************************** + * + * @function: + * FT_New_Memory + * + * @description: + * Creates a new memory object. + * + * @return: + * A pointer to the new memory object. 0 in case of error. + */ + FT_BASE( FT_Memory ) + FT_New_Memory( void ); + + + /************************************************************************** + * + * @function: + * FT_Done_Memory + * + * @description: + * Discards memory manager. + * + * @input: + * memory :: + * A handle to the memory manager. + */ + FT_BASE( void ) + FT_Done_Memory( FT_Memory memory ); + +#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* Define default raster's interface. The default raster is located in */ + /* `src/base/ftraster.c'. */ + /* */ + /* Client applications can register new rasters through the */ + /* FT_Set_Raster() API. */ + +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_OUTLINE_FUNCS + * + * @description: + * Used to initialize an instance of FT_Outline_Funcs struct. The struct + * will be allocated in the global scope (or the scope where the macro is + * used). + */ +#define FT_DEFINE_OUTLINE_FUNCS( \ + class_, \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_RASTER_FUNCS + * + * @description: + * Used to initialize an instance of FT_Raster_Funcs struct. The struct + * will be allocated in the global scope (or the scope where the macro is + * used). + */ +#define FT_DEFINE_RASTER_FUNCS( \ + class_, \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_GLYPH + * + * @description: + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_GLYPH( class_ ) \ + FT_CALLBACK_TABLE const FT_Glyph_Class class_; + +#define FT_DEFINE_GLYPH( \ + class_, \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Glyph_Class class_ = \ + { \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_RENDERER + * + * @description: + * Used to create a forward declaration of a FT_Renderer_Class struct + * instance. + * + * @macro: + * FT_DEFINE_RENDERER + * + * @description: + * Used to initialize an instance of FT_Renderer_Class struct. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DECLARE_RENDERER( class_ ) \ + FT_EXPORT_VAR( const FT_Renderer_Class ) class_; + +#define FT_DEFINE_RENDERER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + glyph_format_, \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + raster_class_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Renderer_Class class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + glyph_format_, \ + \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + \ + raster_class_ \ + }; + + + /************************************************************************** + * + * @macro: + * FT_DECLARE_MODULE + * + * @description: + * Used to create a forward declaration of a FT_Module_Class struct + * instance. + * + * @macro: + * FT_DEFINE_MODULE + * + * @description: + * Used to initialize an instance of an FT_Module_Class struct. + * + * The struct will be allocated in the global scope (or the scope where + * the macro is used). + * + * @macro: + * FT_DEFINE_ROOT_MODULE + * + * @description: + * Used to initialize an instance of an FT_Module_Class struct inside + * another struct that contains it or in a function that initializes that + * containing struct. + */ +#define FT_DECLARE_MODULE( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Module_Class class_; + +#define FT_DEFINE_ROOT_MODULE( \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }, + +#define FT_DEFINE_MODULE( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Module_Class class_ = \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }; + + +FT_END_HEADER + +#endif /* FTOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftpsprop.h b/Dependencies/freetype/freetype/include/freetype/internal/ftpsprop.h new file mode 100644 index 00000000..4f11aa16 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftpsprop.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * ftpsprop.h + * + * Get and set properties of PostScript drivers (specification). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTPSPROP_H_ +#define FTPSPROP_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_BASE_CALLBACK( FT_Error ) + ps_property_set( FT_Module module, /* PS_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ); + + FT_BASE_CALLBACK( FT_Error ) + ps_property_get( FT_Module module, /* PS_Driver */ + const char* property_name, + void* value ); + + +FT_END_HEADER + + +#endif /* FTPSPROP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftrfork.h b/Dependencies/freetype/freetype/include/freetype/internal/ftrfork.h new file mode 100644 index 00000000..05c1d6c4 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftrfork.h @@ -0,0 +1,245 @@ +/**************************************************************************** + * + * ftrfork.h + * + * Embedded resource forks accessor (specification). + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO and Redhat K.K. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * Development of the code in this file is support of + * Information-technology Promotion Agency, Japan. + */ + + +#ifndef FTRFORK_H_ +#define FTRFORK_H_ + + +#include + + +FT_BEGIN_HEADER + + + /* Number of guessing rules supported in `FT_Raccess_Guess'. */ + /* Don't forget to increment the number if you add a new guessing rule. */ +#define FT_RACCESS_N_RULES 9 + + + /* A structure to describe a reference in a resource by its resource ID */ + /* and internal offset. The `POST' resource expects to be concatenated */ + /* by the order of resource IDs instead of its appearance in the file. */ + + typedef struct FT_RFork_Ref_ + { + FT_Short res_id; + FT_Long offset; + + } FT_RFork_Ref; + + +#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK + typedef FT_Error + (*ft_raccess_guess_func)( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + typedef enum FT_RFork_Rule_ { + FT_RFork_Rule_invalid = -2, + FT_RFork_Rule_uknown, /* -1 */ + FT_RFork_Rule_apple_double, + FT_RFork_Rule_apple_single, + FT_RFork_Rule_darwin_ufs_export, + FT_RFork_Rule_darwin_newvfs, + FT_RFork_Rule_darwin_hfsplus, + FT_RFork_Rule_vfat, + FT_RFork_Rule_linux_cap, + FT_RFork_Rule_linux_double, + FT_RFork_Rule_linux_netatalk + } FT_RFork_Rule; + + /* For fast translation between rule index and rule type, + * the macros FT_RFORK_xxx should be kept consistent with the + * raccess_guess_funcs table + */ + typedef struct ft_raccess_guess_rec_ { + ft_raccess_guess_func func; + FT_RFork_Rule type; + } ft_raccess_guess_rec; + + +#define CONST_FT_RFORK_RULE_ARRAY_BEGIN( name, type ) \ + static const type name[] = { +#define CONST_FT_RFORK_RULE_ARRAY_ENTRY( func_suffix, type_suffix ) \ + { raccess_guess_ ## func_suffix, \ + FT_RFork_Rule_ ## type_suffix }, + /* this array is a storage, thus a final `;' is needed */ +#define CONST_FT_RFORK_RULE_ARRAY_END }; + +#endif /* FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + + /************************************************************************** + * + * @function: + * FT_Raccess_Guess + * + * @description: + * Guess a file name and offset where the actual resource fork is stored. + * The macro FT_RACCESS_N_RULES holds the number of guessing rules; the + * guessed result for the Nth rule is represented as a triplet: a new + * file name (new_names[N]), a file offset (offsets[N]), and an error + * code (errors[N]). + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * base_name :: + * The (base) file name of the resource fork used for some guessing + * rules. + * + * @output: + * new_names :: + * An array of guessed file names in which the resource forks may + * exist. If 'new_names[N]' is `NULL`, the guessed file name is equal + * to `base_name`. + * + * offsets :: + * An array of guessed file offsets. 'offsets[N]' holds the file + * offset of the possible start of the resource fork in file + * 'new_names[N]'. + * + * errors :: + * An array of FreeType error codes. 'errors[N]' is the error code of + * Nth guessing rule function. If 'errors[N]' is not FT_Err_Ok, + * 'new_names[N]' and 'offsets[N]' are meaningless. + */ + FT_BASE( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char** new_names, + FT_Long* offsets, + FT_Error* errors ); + + + /************************************************************************** + * + * @function: + * FT_Raccess_Get_HeaderInfo + * + * @description: + * Get the information from the header of resource fork. The information + * includes the file offset where the resource map starts, and the file + * offset where the resource data starts. `FT_Raccess_Get_DataOffsets` + * requires these two data. + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * rfork_offset :: + * The file offset where the resource fork starts. + * + * @output: + * map_offset :: + * The file offset where the resource map starts. + * + * rdata_pos :: + * The file offset where the resource data starts. + * + * @return: + * FreeType error code. FT_Err_Ok means success. + */ + FT_BASE( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ); + + + /************************************************************************** + * + * @function: + * FT_Raccess_Get_DataOffsets + * + * @description: + * Get the data offsets for a tag in a resource fork. Offsets are stored + * in an array because, in some cases, resources in a resource fork have + * the same tag. + * + * @input: + * library :: + * A FreeType library instance. + * + * stream :: + * A file stream containing the resource fork. + * + * map_offset :: + * The file offset where the resource map starts. + * + * rdata_pos :: + * The file offset where the resource data starts. + * + * tag :: + * The resource tag. + * + * sort_by_res_id :: + * A Boolean to sort the fragmented resource by their ids. The + * fragmented resources for 'POST' resource should be sorted to restore + * Type1 font properly. For 'sfnt' resources, sorting may induce a + * different order of the faces in comparison to that by QuickDraw API. + * + * @output: + * offsets :: + * The stream offsets for the resource data specified by 'tag'. This + * array is allocated by the function, so you have to call @ft_mem_free + * after use. + * + * count :: + * The length of offsets array. + * + * @return: + * FreeType error code. FT_Err_Ok means success. + * + * @note: + * Normally you should use `FT_Raccess_Get_HeaderInfo` to get the value + * for `map_offset` and `rdata_pos`. + */ + FT_BASE( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Bool sort_by_res_id, + FT_Long **offsets, + FT_Long *count ); + + +FT_END_HEADER + +#endif /* FTRFORK_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftserv.h b/Dependencies/freetype/freetype/include/freetype/internal/ftserv.h new file mode 100644 index 00000000..8c35dbd7 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftserv.h @@ -0,0 +1,495 @@ +/**************************************************************************** + * + * ftserv.h + * + * The FreeType services (specification only). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Each module can export one or more 'services'. Each service is + * identified by a constant string and modeled by a pointer; the latter + * generally corresponds to a structure containing function pointers. + * + * Note that a service's data cannot be a mere function pointer because in + * C it is possible that function pointers might be implemented differently + * than data pointers (e.g. 48 bits instead of 32). + * + */ + + +#ifndef FTSERV_H_ +#define FTSERV_H_ + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @macro: + * FT_FACE_FIND_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's header + * files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * 'multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_`. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be `NULL` if not + * found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /************************************************************************** + * + * @macro: + * FT_FACE_FIND_GLOBAL_SERVICE + * + * @description: + * This macro is used to look up a service from all modules. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's header + * files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * 'multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_`. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be `NULL` if not + * found. + */ +#ifdef __cplusplus + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id, 1 ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id, 1 ); \ + ptr = _tmp_; \ + FT_END_STMNT + +#endif /* !C++ */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E D E S C R I P T O R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The following structure is used to _describe_ a given service to the + * library. This is useful to build simple static service lists. + */ + typedef struct FT_ServiceDescRec_ + { + const char* serv_id; /* service name */ + const void* serv_data; /* service pointer/data */ + + } FT_ServiceDescRec; + + typedef const FT_ServiceDescRec* FT_ServiceDesc; + + + /************************************************************************** + * + * @macro: + * FT_DEFINE_SERVICEDESCREC1 + * FT_DEFINE_SERVICEDESCREC2 + * FT_DEFINE_SERVICEDESCREC3 + * FT_DEFINE_SERVICEDESCREC4 + * FT_DEFINE_SERVICEDESCREC5 + * FT_DEFINE_SERVICEDESCREC6 + * FT_DEFINE_SERVICEDESCREC7 + * FT_DEFINE_SERVICEDESCREC8 + * FT_DEFINE_SERVICEDESCREC9 + * FT_DEFINE_SERVICEDESCREC10 + * + * @description: + * Used to initialize an array of FT_ServiceDescRec structures. + * + * The array will be allocated in the global scope (or the scope where + * the macro is used). + */ +#define FT_DEFINE_SERVICEDESCREC1( class_, \ + serv_id_1, serv_data_1 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC2( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC3( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC4( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC5( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC6( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC7( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC8( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC9( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8, \ + serv_id_9, serv_data_9 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { serv_id_9, serv_data_9 }, \ + { NULL, NULL } \ + }; + +#define FT_DEFINE_SERVICEDESCREC10( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8, \ + serv_id_9, serv_data_9, \ + serv_id_10, serv_data_10 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { serv_id_9, serv_data_9 }, \ + { serv_id_10, serv_data_10 }, \ + { NULL, NULL } \ + }; + + + /* + * Parse a list of FT_ServiceDescRec descriptors and look for a specific + * service by ID. Note that the last element in the array must be { NULL, + * NULL }, and that the function should return NULL if the service isn't + * available. + * + * This function can be used by modules to implement their `get_service' + * method. + */ + FT_BASE( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S E R V I C E S C A C H E *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * This structure is used to store a cache for several frequently used + * services. It is the type of `face->internal->services'. You should + * only use FT_FACE_LOOKUP_SERVICE to access it. + * + * All fields should have the type FT_Pointer to relax compilation + * dependencies. We assume the developer isn't completely stupid. + * + * Each field must be named `service_XXXX' where `XXX' corresponds to the + * correct FT_SERVICE_ID_XXXX macro. See the definition of + * FT_FACE_LOOKUP_SERVICE below how this is implemented. + * + */ + typedef struct FT_ServiceCacheRec_ + { + FT_Pointer service_POSTSCRIPT_FONT_NAME; + FT_Pointer service_MULTI_MASTERS; + FT_Pointer service_METRICS_VARIATIONS; + FT_Pointer service_GLYPH_DICT; + FT_Pointer service_PFR_METRICS; + FT_Pointer service_WINFNT; + + } FT_ServiceCacheRec, *FT_ServiceCache; + + + /* + * A magic number used within the services cache. + */ + + /* ensure that value `1' has the same width as a pointer */ +#define FT_SERVICE_UNAVAILABLE ((FT_Pointer)~(FT_PtrDist)1) + + + /************************************************************************** + * + * @macro: + * FT_FACE_LOOKUP_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module + * using its cache. + * + * @input: + * face :: + * The source face handle containing the cache. + * + * field :: + * The field name in the cache. + * + * id :: + * The service ID. + * + * @output: + * ptr :: + * A variable receiving the service data. `NULL` if not available. + */ +#ifdef __cplusplus + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + *Pptr = svc; \ + FT_END_STMNT + +#else /* !C++ */ + +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + ptr = svc; \ + FT_END_STMNT + +#endif /* !C++ */ + + /* + * A macro used to define new service structure types. + */ + +#define FT_DEFINE_SERVICE( name ) \ + typedef struct FT_Service_ ## name ## Rec_ \ + FT_Service_ ## name ## Rec ; \ + typedef struct FT_Service_ ## name ## Rec_ \ + const * FT_Service_ ## name ; \ + struct FT_Service_ ## name ## Rec_ + + /* */ + +FT_END_HEADER + +#endif /* FTSERV_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftstream.h b/Dependencies/freetype/freetype/include/freetype/internal/ftstream.h new file mode 100644 index 00000000..fd52f767 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftstream.h @@ -0,0 +1,570 @@ +/**************************************************************************** + * + * ftstream.h + * + * Stream handling (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSTREAM_H_ +#define FTSTREAM_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* format of an 8-bit frame_op value: */ + /* */ + /* bit 76543210 */ + /* xxxxxxes */ + /* */ + /* s is set to 1 if the value is signed. */ + /* e is set to 1 if the value is little-endian. */ + /* xxx is a command. */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ +#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */ + + + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + + } FT_Frame_Op; + + + typedef struct FT_Frame_Field_ + { + FT_Byte value; + FT_Byte size; + FT_UShort offset; + + } FT_Frame_Field; + + + /* Construct an FT_Frame_Field out of a structure type and a field name. */ + /* The structure type must be set in the FT_STRUCTURE macro before */ + /* calling the FT_FRAME_START() macro. */ + /* */ +#define FT_FIELD_SIZE( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) + +#define FT_FIELD_SIZE_DELTA( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) + +#define FT_FIELD_OFFSET( f ) \ + (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) + +#define FT_FRAME_FIELD( frame_op, field ) \ + { \ + frame_op, \ + FT_FIELD_SIZE( field ), \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_START( size ) { ft_frame_start, 0, size } +#define FT_FRAME_END { ft_frame_end, 0, 0 } + +#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) +#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) +#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) +#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) +#define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) +#define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) +#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) +#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) + +#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) +#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) +#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) +#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) +#define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) +#define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) + +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } + +#define FT_FRAME_BYTES( field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + FT_FIELD_OFFSET( field ) \ + } + +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } + + + /************************************************************************** + * + * Integer extraction macros -- the 'buffer' parameter must ALWAYS be of + * type 'char*' or equivalent (1-byte elements). + */ + +#define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) + +#define FT_INT16( x ) ( (FT_Int16)(x) ) +#define FT_UINT16( x ) ( (FT_UInt16)(x) ) +#define FT_INT32( x ) ( (FT_Int32)(x) ) +#define FT_UINT32( x ) ( (FT_UInt32)(x) ) + + +#define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) + + + /* + * function acts on increases does range for emits + * pointer checking frames error + * ------------------------------------------------------------------- + * FT_PEEK_XXX buffer pointer no no no no + * FT_NEXT_XXX buffer pointer yes no no no + * FT_GET_XXX stream->cursor yes yes yes no + * FT_READ_XXX stream->pos yes yes no yes + */ + + + /* + * `FT_PEEK_XXX' are generic macros to get data from a buffer position. No + * safety checks are performed. + */ +#define FT_PEEK_SHORT( p ) FT_INT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) + +#define FT_PEEK_LONG( p ) FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) + +#define FT_PEEK_OFF3( p ) ( FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) ) >> 8 ) + +#define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 2, 0 ) ) + +#define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) + +#define FT_PEEK_LONG_LE( p ) FT_INT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + +#define FT_PEEK_OFF3_LE( p ) ( FT_INT32( FT_BYTE_U32( p, 2, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 0, 8 ) ) >> 8 ) + +#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) + + /* + * `FT_NEXT_XXX' are generic macros to get data from a buffer position + * which is then increased appropriately. No safety checks are performed. + */ +#define FT_NEXT_CHAR( buffer ) \ + ( (signed char)*buffer++ ) + +#define FT_NEXT_BYTE( buffer ) \ + ( (unsigned char)*buffer++ ) + +#define FT_NEXT_SHORT( buffer ) \ + ( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) + +#define FT_NEXT_USHORT( buffer ) \ + ( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) + +#define FT_NEXT_OFF3( buffer ) \ + ( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) + +#define FT_NEXT_UOFF3( buffer ) \ + ( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) + +#define FT_NEXT_LONG( buffer ) \ + ( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) + +#define FT_NEXT_ULONG( buffer ) \ + ( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) + + +#define FT_NEXT_SHORT_LE( buffer ) \ + ( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) + +#define FT_NEXT_USHORT_LE( buffer ) \ + ( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) + +#define FT_NEXT_OFF3_LE( buffer ) \ + ( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) + +#define FT_NEXT_UOFF3_LE( buffer ) \ + ( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) + +#define FT_NEXT_LONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) + +#define FT_NEXT_ULONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) + + + /************************************************************************** + * + * The `FT_GET_XXX` macros use an implicit 'stream' variable. + * + * Note that a call to `FT_STREAM_SEEK` or `FT_STREAM_POS` has **no** + * effect on `FT_GET_XXX`! They operate on `stream->pos`, while + * `FT_GET_XXX` use `stream->cursor`. + */ +#if 0 +#define FT_GET_MACRO( type ) FT_NEXT_ ## type ( stream->cursor ) + +#define FT_GET_CHAR() FT_GET_MACRO( CHAR ) +#define FT_GET_BYTE() FT_GET_MACRO( BYTE ) +#define FT_GET_SHORT() FT_GET_MACRO( SHORT ) +#define FT_GET_USHORT() FT_GET_MACRO( USHORT ) +#define FT_GET_OFF3() FT_GET_MACRO( OFF3 ) +#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 ) +#define FT_GET_LONG() FT_GET_MACRO( LONG ) +#define FT_GET_ULONG() FT_GET_MACRO( ULONG ) +#define FT_GET_TAG4() FT_GET_MACRO( ULONG ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE ) +#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE ) + +#else +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) + +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetByte, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetByte, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Int16 ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UInt16 ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_UInt32 ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Int32 ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) + +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Int16 ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UInt16 ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Int32 ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_UInt32 ) +#endif + + +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) + + /* + * The `FT_READ_XXX' macros use implicit `stream' and `error' variables. + * + * `FT_READ_XXX' can be controlled with `FT_STREAM_SEEK' and + * `FT_STREAM_POS'. They use the full machinery to check whether a read is + * valid. + */ +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Int16, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UInt16, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_UInt32, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Int32, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_UInt32, var ) + +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Int16, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UInt16, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Int32, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_UInt32, var ) + + +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM + + /* initialize a stream for reading a regular system stream */ + FT_BASE( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ); + +#endif /* FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ + + + /* create a new (input) stream from an FT_Open_Args structure */ + FT_BASE( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ); + + /* free a stream */ + FT_BASE( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ); + + /* initialize a stream for reading in-memory data */ + FT_BASE( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ); + + /* close a stream (does not destroy the stream structure) */ + FT_BASE( void ) + FT_Stream_Close( FT_Stream stream ); + + + /* seek within a stream. position is relative to start of stream */ + FT_BASE( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ); + + /* skip bytes in a stream */ + FT_BASE( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ); + + /* return current stream position */ + FT_BASE( FT_ULong ) + FT_Stream_Pos( FT_Stream stream ); + + /* read bytes from a stream into a user-allocated buffer, returns an */ + /* error if not all bytes could be read. */ + FT_BASE( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* read bytes from a stream at a given position */ + FT_BASE( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); + + /* try to read bytes at the end of a stream; return number of bytes */ + /* really available */ + FT_BASE( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); + + /* Enter a frame of `count' consecutive bytes in a stream. Returns an */ + /* error if the frame could not be read/accessed. The caller can use */ + /* the `FT_Stream_GetXXX' functions to retrieve frame data without */ + /* error checks. */ + /* */ + /* You must _always_ call `FT_Stream_ExitFrame' once you have entered */ + /* a stream frame! */ + /* */ + /* Nested frames are not permitted. */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ); + + /* exit a stream frame */ + FT_BASE( void ) + FT_Stream_ExitFrame( FT_Stream stream ); + + + /* Extract a stream frame. If the stream is disk-based, a heap block */ + /* is allocated and the frame bytes are read into it. If the stream */ + /* is memory-based, this function simply sets a pointer to the data. */ + /* */ + /* Useful to optimize access to memory-based streams transparently. */ + /* */ + /* `FT_Stream_GetXXX' functions can't be used. */ + /* */ + /* An extracted frame must be `freed' with a call to the function */ + /* `FT_Stream_ReleaseFrame'. */ + /* */ + FT_BASE( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); + + /* release an extract frame (see `FT_Stream_ExtractFrame') */ + FT_BASE( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ); + + + /* read a byte from an entered frame */ + FT_BASE( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ); + + /* read a 16-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt16 ) + FT_Stream_GetUShort( FT_Stream stream ); + + /* read a 24-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetUOffset( FT_Stream stream ); + + /* read a 32-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetULong( FT_Stream stream ); + + /* read a 16-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt16 ) + FT_Stream_GetUShortLE( FT_Stream stream ); + + /* read a 32-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_UInt32 ) + FT_Stream_GetULongLE( FT_Stream stream ); + + + /* read a byte from a stream */ + FT_BASE( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_UInt16 ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ); + + /* read a 24-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit big-endian integer from a stream */ + FT_BASE( FT_UInt32 ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ); + + /* read a 16-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_UInt16 ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ); + + /* read a 32-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_UInt32 ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ); + + /* Read a structure from a stream. The structure must be described */ + /* by an array of FT_Frame_Field records. */ + FT_BASE( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + + +#define FT_STREAM_POS() \ + FT_Stream_Pos( stream ) + +#define FT_STREAM_SEEK( position ) \ + FT_SET_ERROR( FT_Stream_Seek( stream, \ + (FT_ULong)(position) ) ) + +#define FT_STREAM_SKIP( distance ) \ + FT_SET_ERROR( FT_Stream_Skip( stream, \ + (FT_Long)(distance) ) ) + +#define FT_STREAM_READ( buffer, count ) \ + FT_SET_ERROR( FT_Stream_Read( stream, \ + (FT_Byte*)(buffer), \ + (FT_ULong)(count) ) ) + +#define FT_STREAM_READ_AT( position, buffer, count ) \ + FT_SET_ERROR( FT_Stream_ReadAt( stream, \ + (FT_ULong)(position), \ + (FT_Byte*)(buffer), \ + (FT_ULong)(count) ) ) + +#define FT_STREAM_READ_FIELDS( fields, object ) \ + FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) + + +#define FT_FRAME_ENTER( size ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, \ + (FT_ULong)(size) ) ) ) + +#define FT_FRAME_EXIT() \ + FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) + +#define FT_FRAME_EXTRACT( size, bytes ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, \ + (FT_ULong)(size), \ + (FT_Byte**)&(bytes) ) ) ) + +#define FT_FRAME_RELEASE( bytes ) \ + FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ + (FT_Byte**)&(bytes) ) ) + + +FT_END_HEADER + +#endif /* FTSTREAM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/fttrace.h b/Dependencies/freetype/freetype/include/freetype/internal/fttrace.h new file mode 100644 index 00000000..42595a29 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/fttrace.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * fttrace.h + * + * Tracing handling (specification only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* definitions of trace levels for FreeType 2 */ + + /* the maximum string length (if the argument to `FT_TRACE_DEF` */ + /* gets used as a string) plus one charachter for ':' plus */ + /* another one for the trace level */ +#define FT_MAX_TRACE_LEVEL_LENGTH (9 + 1 + 1) + + /* the first level must always be `trace_any' */ +FT_TRACE_DEF( any ) + + /* base components */ +FT_TRACE_DEF( calc ) /* calculations (ftcalc.c) */ +FT_TRACE_DEF( gloader ) /* glyph loader (ftgloadr.c) */ +FT_TRACE_DEF( glyph ) /* glyph management (ftglyph.c) */ +FT_TRACE_DEF( memory ) /* memory manager (ftobjs.c) */ +FT_TRACE_DEF( init ) /* initialization (ftinit.c) */ +FT_TRACE_DEF( io ) /* i/o interface (ftsystem.c) */ +FT_TRACE_DEF( list ) /* list management (ftlist.c) */ +FT_TRACE_DEF( objs ) /* base objects (ftobjs.c) */ +FT_TRACE_DEF( outline ) /* outline management (ftoutln.c) */ +FT_TRACE_DEF( stream ) /* stream manager (ftstream.c) */ + +FT_TRACE_DEF( bitmap ) /* bitmap manipulation (ftbitmap.c) */ +FT_TRACE_DEF( checksum ) /* bitmap checksum (ftobjs.c) */ +FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ +FT_TRACE_DEF( psprops ) /* PS driver properties (ftpsprop.c) */ +FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ +FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ + + /* rasterizers */ +FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ +FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ + + /* ot-svg module */ +FT_TRACE_DEF( otsvg ) /* OT-SVG renderer (ftsvg.c) */ + + /* cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + + /* SFNT driver components */ +FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */ +FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */ +FT_TRACE_DEF( sfwoff ) /* WOFF format handler (sfwoff.c) */ +FT_TRACE_DEF( sfwoff2 ) /* WOFF2 format handler (sfwoff2.c) */ +FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */ +FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ +FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */ +FT_TRACE_DEF( ttcpal ) /* color palette table (ttcpal.c) */ +FT_TRACE_DEF( ttgpos ) /* GPOS handler (ttgpos.c) */ +FT_TRACE_DEF( ttsvg ) /* OpenType SVG table (ttsvg.c) */ +FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ +FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ +FT_TRACE_DEF( ttmtx ) /* metrics-related tables (ttmtx.c) */ +FT_TRACE_DEF( ttpost ) /* PS table processing (ttpost.c) */ +FT_TRACE_DEF( ttsbit ) /* TrueType sbit handling (ttsbit.c) */ + + /* TrueType driver components */ +FT_TRACE_DEF( ttdriver ) /* TT font driver (ttdriver.c) */ +FT_TRACE_DEF( ttgload ) /* TT glyph loader (ttgload.c) */ +FT_TRACE_DEF( ttgxvar ) /* TrueType GX var handler (ttgxvar.c) */ +FT_TRACE_DEF( ttinterp ) /* bytecode interpreter (ttinterp.c) */ +FT_TRACE_DEF( ttobjs ) /* TT objects manager (ttobjs.c) */ +FT_TRACE_DEF( ttpload ) /* TT data/program loader (ttpload.c) */ + + /* Type 1 driver components */ +FT_TRACE_DEF( t1afm ) +FT_TRACE_DEF( t1driver ) +FT_TRACE_DEF( t1gload ) +FT_TRACE_DEF( t1load ) +FT_TRACE_DEF( t1objs ) +FT_TRACE_DEF( t1parse ) + + /* PostScript helper module `psaux' */ +FT_TRACE_DEF( afmparse ) +FT_TRACE_DEF( cffdecode ) +FT_TRACE_DEF( psconv ) +FT_TRACE_DEF( psobjs ) +FT_TRACE_DEF( t1decode ) + + /* PostScript hinting module `pshinter' */ +FT_TRACE_DEF( pshalgo ) +FT_TRACE_DEF( pshrec ) + + /* Type 2 driver components */ +FT_TRACE_DEF( cffdriver ) +FT_TRACE_DEF( cffgload ) +FT_TRACE_DEF( cffload ) +FT_TRACE_DEF( cffobjs ) +FT_TRACE_DEF( cffparse ) + +FT_TRACE_DEF( cf2blues ) +FT_TRACE_DEF( cf2hints ) +FT_TRACE_DEF( cf2interp ) + + /* Type 42 driver component */ +FT_TRACE_DEF( t42 ) + + /* CID driver components */ +FT_TRACE_DEF( ciddriver ) +FT_TRACE_DEF( cidgload ) +FT_TRACE_DEF( cidload ) +FT_TRACE_DEF( cidobjs ) +FT_TRACE_DEF( cidparse ) + + /* Windows font component */ +FT_TRACE_DEF( winfnt ) + + /* PCF font components */ +FT_TRACE_DEF( pcfdriver ) +FT_TRACE_DEF( pcfread ) + + /* BDF font components */ +FT_TRACE_DEF( bdfdriver ) +FT_TRACE_DEF( bdflib ) + + /* PFR font component */ +FT_TRACE_DEF( pfr ) + + /* OpenType validation components */ +FT_TRACE_DEF( otvcommon ) +FT_TRACE_DEF( otvbase ) +FT_TRACE_DEF( otvgdef ) +FT_TRACE_DEF( otvgpos ) +FT_TRACE_DEF( otvgsub ) +FT_TRACE_DEF( otvjstf ) +FT_TRACE_DEF( otvmath ) +FT_TRACE_DEF( otvmodule ) + + /* TrueTypeGX/AAT validation components */ +FT_TRACE_DEF( gxvbsln ) +FT_TRACE_DEF( gxvcommon ) +FT_TRACE_DEF( gxvfeat ) +FT_TRACE_DEF( gxvjust ) +FT_TRACE_DEF( gxvkern ) +FT_TRACE_DEF( gxvmodule ) +FT_TRACE_DEF( gxvmort ) +FT_TRACE_DEF( gxvmorx ) +FT_TRACE_DEF( gxvlcar ) +FT_TRACE_DEF( gxvopbd ) +FT_TRACE_DEF( gxvprop ) +FT_TRACE_DEF( gxvtrak ) + + /* autofit components */ +FT_TRACE_DEF( afcjk ) +FT_TRACE_DEF( afglobal ) +FT_TRACE_DEF( afhints ) +FT_TRACE_DEF( afmodule ) +FT_TRACE_DEF( aflatin ) +FT_TRACE_DEF( afshaper ) + + /* SDF components */ +FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */ +FT_TRACE_DEF( bsdf ) /* signed distance raster for bitmaps (ftbsdf.c) */ + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/ftvalid.h b/Dependencies/freetype/freetype/include/freetype/internal/ftvalid.h new file mode 100644 index 00000000..a1312f2a --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/ftvalid.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * + * ftvalid.h + * + * FreeType validation support (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTVALID_H_ +#define FTVALID_H_ + +#include +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_jmpbuf */ + +#include "compiler-macros.h" + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** V A L I D A T I O N ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to a validation object */ + typedef struct FT_ValidatorRec_ volatile* FT_Validator; + + + /************************************************************************** + * + * There are three distinct validation levels defined here: + * + * FT_VALIDATE_DEFAULT :: + * A table that passes this validation level can be used reliably by + * FreeType. It generally means that all offsets have been checked to + * prevent out-of-bound reads, that array counts are correct, etc. + * + * FT_VALIDATE_TIGHT :: + * A table that passes this validation level can be used reliably and + * doesn't contain invalid data. For example, a charmap table that + * returns invalid glyph indices will not pass, even though it can be + * used with FreeType in default mode (the library will simply return an + * error later when trying to load the glyph). + * + * It also checks that fields which must be a multiple of 2, 4, or 8, + * don't have incorrect values, etc. + * + * FT_VALIDATE_PARANOID :: + * Only for font debugging. Checks that a table follows the + * specification by 100%. Very few fonts will be able to pass this level + * anyway but it can be useful for certain tools like font + * editors/converters. + */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + + } FT_ValidationLevel; + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `structure was padded due to */ + /* __declspec(align())' in order to compile cleanly with */ + /* the maximum level of warnings. */ +#pragma warning( push ) +#pragma warning( disable : 4324 ) +#endif /* _MSC_VER */ + + /* validator structure */ + typedef struct FT_ValidatorRec_ + { + ft_jmp_buf jump_buffer; /* used for exception handling */ + + const FT_Byte* base; /* address of table in memory */ + const FT_Byte* limit; /* `base' + sizeof(table) in memory */ + FT_ValidationLevel level; /* validation level */ + FT_Error error; /* error returned. 0 means success */ + + } FT_ValidatorRec; + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#define FT_VALIDATOR( x ) ( (FT_Validator)( x ) ) + + + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); + + /* Do not use this. It's broken and will cause your validator to crash */ + /* if you run it on an invalid font. */ + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); + + /* Sets the error field in a validator, then calls `longjmp' to return */ + /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ + /* error checks within the validation routines. */ + /* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); + + + /* Calls ft_validate_error. Assumes that the `valid' local variable */ + /* holds a pointer to the current validator object. */ + /* */ +#define FT_INVALID( _error ) FT_INVALID_( _error ) +#define FT_INVALID_( _error ) \ + ft_validator_error( valid, FT_THROW( _error ) ) + + /* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( Invalid_Table ) + + /* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( Invalid_Offset ) + + /* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( Invalid_Table ) + + /* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( Invalid_Glyph_Index ) + + /* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( Invalid_Table ) + + +FT_END_HEADER + +#endif /* FTVALID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/psaux.h b/Dependencies/freetype/freetype/include/freetype/internal/psaux.h new file mode 100644 index 00000000..745d2cb5 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/psaux.h @@ -0,0 +1,1447 @@ +/**************************************************************************** + * + * psaux.h + * + * Auxiliary functions and data structures related to PostScript fonts + * (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSAUX_H_ +#define PSAUX_H_ + + +#include +#include +#include +#include +#include +#include +#include + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * PostScript modules driver class. + */ + typedef struct PS_DriverRec_ + { + FT_DriverRec root; + + FT_UInt hinting_engine; + FT_Bool no_stem_darkening; + FT_Int darken_params[8]; + FT_Int32 random_seed; + + } PS_DriverRec, *PS_Driver; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_TableRec_* PS_Table; + typedef const struct PS_Table_FuncsRec_* PS_Table_Funcs; + + + /************************************************************************** + * + * @struct: + * PS_Table_FuncsRec + * + * @description: + * A set of function pointers to manage PS_Table objects. + * + * @fields: + * table_init :: + * Used to initialize a table. + * + * table_done :: + * Finalizes resp. destroy a given table. + * + * table_add :: + * Adds a new object to a table. + * + * table_release :: + * Releases table data, then finalizes it. + */ + typedef struct PS_Table_FuncsRec_ + { + FT_Error + (*init)( PS_Table table, + FT_Int count, + FT_Memory memory ); + + void + (*done)( PS_Table table ); + + FT_Error + (*add)( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ); + + void + (*release)( PS_Table table ); + + } PS_Table_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_TableRec + * + * @description: + * A PS_Table is a simple object used to store an array of objects in a + * single memory block. + * + * @fields: + * block :: + * The address in memory of the growheap's block. This can change + * between two object adds, due to reallocation. + * + * cursor :: + * The current top of the grow heap within its block. + * + * capacity :: + * The current size of the heap block. Increments by 1kByte chunks. + * + * init :: + * Set to 0xDEADBEEF if 'elements' and 'lengths' have been allocated. + * + * max_elems :: + * The maximum number of elements in table. + * + * elements :: + * A table of element addresses within the block. + * + * lengths :: + * A table of element sizes within the block. + * + * memory :: + * The object used for memory operations (alloc/realloc). + * + * funcs :: + * A table of method pointers for this object. + */ + typedef struct PS_TableRec_ + { + FT_Byte* block; /* current memory block */ + FT_Offset cursor; /* current cursor in memory block */ + FT_Offset capacity; /* current size of memory block */ + FT_ULong init; + + FT_Int max_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_UInt* lengths; /* lengths of table elements */ + + FT_Memory memory; + PS_Table_FuncsRec funcs; + + } PS_TableRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 FIELDS & TOKENS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PS_ParserRec_* PS_Parser; + + typedef struct T1_TokenRec_* T1_Token; + + typedef struct T1_FieldRec_* T1_Field; + + + /* simple enumeration type used to identify token types */ + typedef enum T1_TokenType_ + { + T1_TOKEN_TYPE_NONE = 0, + T1_TOKEN_TYPE_ANY, + T1_TOKEN_TYPE_STRING, + T1_TOKEN_TYPE_ARRAY, + T1_TOKEN_TYPE_KEY, /* aka `name' */ + + /* do not remove */ + T1_TOKEN_TYPE_MAX + + } T1_TokenType; + + + /* a simple structure used to identify tokens */ + typedef struct T1_TokenRec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + T1_TokenType type; /* type of token */ + + } T1_TokenRec; + + + /* enumeration type used to identify object fields */ + typedef enum T1_FieldType_ + { + T1_FIELD_TYPE_NONE = 0, + T1_FIELD_TYPE_BOOL, + T1_FIELD_TYPE_INTEGER, + T1_FIELD_TYPE_FIXED, + T1_FIELD_TYPE_FIXED_1000, + T1_FIELD_TYPE_STRING, + T1_FIELD_TYPE_KEY, + T1_FIELD_TYPE_BBOX, + T1_FIELD_TYPE_MM_BBOX, + T1_FIELD_TYPE_INTEGER_ARRAY, + T1_FIELD_TYPE_FIXED_ARRAY, + T1_FIELD_TYPE_CALLBACK, + + /* do not remove */ + T1_FIELD_TYPE_MAX + + } T1_FieldType; + + + typedef enum T1_FieldLocation_ + { + T1_FIELD_LOCATION_NONE = 0, + T1_FIELD_LOCATION_CID_INFO, + T1_FIELD_LOCATION_FONT_DICT, + T1_FIELD_LOCATION_FONT_EXTRA, + T1_FIELD_LOCATION_FONT_INFO, + T1_FIELD_LOCATION_PRIVATE, + T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, + + /* do not remove */ + T1_FIELD_LOCATION_MAX + + } T1_FieldLocation; + + + typedef void + (*T1_Field_ParseFunc)( FT_Face face, + FT_Pointer parser ); + + + /* structure type used to model object fields */ + typedef struct T1_FieldRec_ + { + FT_UInt len; /* field identifier length */ + const char* ident; /* field identifier */ + T1_FieldLocation location; + T1_FieldType type; /* type of field */ + T1_Field_ParseFunc reader; + FT_UInt offset; /* offset of field in object */ + FT_Byte size; /* size of field in bytes */ + FT_UInt array_max; /* maximum number of elements for */ + /* array */ + FT_UInt count_offset; /* offset of element count for */ + /* arrays; must not be zero if in */ + /* use -- in other words, a */ + /* `num_FOO' element must not */ + /* start the used structure if we */ + /* parse a `FOO' array */ + FT_UInt dict; /* where we expect it */ + } T1_FieldRec; + +#define T1_FIELD_DICT_FONTDICT ( 1 << 0 ) /* also FontInfo and FDArray */ +#define T1_FIELD_DICT_PRIVATE ( 1 << 1 ) + + + +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ + { \ + sizeof ( _ident ) - 1, \ + _ident, T1CODE, _type, \ + NULL, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE( _fname ), \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ + { \ + sizeof ( _ident ) - 1, \ + _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ + (T1_Field_ParseFunc)_reader, \ + 0, 0, \ + 0, 0, \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ + { \ + sizeof ( _ident ) - 1, \ + _ident, T1CODE, _type, \ + NULL, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, \ + FT_FIELD_OFFSET( num_ ## _fname ), \ + _dict \ + }, + +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ + { \ + sizeof ( _ident ) - 1, \ + _ident, T1CODE, _type, \ + NULL, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, 0, \ + _dict \ + }, + + +#define T1_FIELD_BOOL( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BOOL, _fname, _dict ) + +#define T1_FIELD_NUM( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER, _fname, _dict ) + +#define T1_FIELD_FIXED( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED, _fname, _dict ) + +#define T1_FIELD_FIXED_1000( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_1000, _fname, \ + _dict ) + +#define T1_FIELD_STRING( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_STRING, _fname, _dict ) + +#define T1_FIELD_KEY( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_KEY, _fname, _dict ) + +#define T1_FIELD_BBOX( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BBOX, _fname, _dict ) + + +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) + +#define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ + T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) + +#define T1_FIELD_ZERO \ + { \ + 0, \ + NULL, T1_FIELD_LOCATION_NONE, T1_FIELD_TYPE_NONE, \ + NULL, 0, 0, 0, 0, 0 \ + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct PS_Parser_FuncsRec_* PS_Parser_Funcs; + + typedef struct PS_Parser_FuncsRec_ + { + void + (*init)( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + void + (*done)( PS_Parser parser ); + + void + (*skip_spaces)( PS_Parser parser ); + void + (*skip_PS_token)( PS_Parser parser ); + + FT_Long + (*to_int)( PS_Parser parser ); + FT_Fixed + (*to_fixed)( PS_Parser parser, + FT_Int power_ten ); + + FT_Error + (*to_bytes)( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ); + + FT_Int + (*to_coord_array)( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_Int + (*to_fixed_array)( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + void + (*to_token)( PS_Parser parser, + T1_Token token ); + void + (*to_token_array)( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_Error + (*load_field)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_Error + (*load_field_table)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + } PS_Parser_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_ParserRec + * + * @description: + * A PS_Parser is an object used to parse a Type 1 font very quickly. + * + * @fields: + * cursor :: + * The current position in the text. + * + * base :: + * Start of the processed text. + * + * limit :: + * End of the processed text. + * + * error :: + * The last error returned. + * + * memory :: + * The object used for memory operations (alloc/realloc). + * + * funcs :: + * A table of functions for the parser. + */ + typedef struct PS_ParserRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Error error; + FT_Memory memory; + + PS_Parser_FuncsRec funcs; + + } PS_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct PS_Builder_ PS_Builder; + typedef const struct PS_Builder_FuncsRec_* PS_Builder_Funcs; + + typedef struct PS_Builder_FuncsRec_ + { + void + (*init)( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ); + + void + (*done)( PS_Builder* builder ); + + } PS_Builder_FuncsRec; + + + /************************************************************************** + * + * @struct: + * PS_Builder + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * XXX + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * path_begun :: + * A flag which indicates that a new path has begun. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * is_t1 :: + * Set if current font type is Type 1. + * + * funcs :: + * An array of function pointers for the builder. + */ + struct PS_Builder_ + { + FT_Memory memory; + FT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos* pos_x; + FT_Pos* pos_y; + + FT_Vector* left_bearing; + FT_Vector* advance; + + FT_BBox* bbox; /* bounding box */ + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + FT_Bool is_t1; + + PS_Builder_FuncsRec funcs; + + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define PS_MAX_OPERANDS 48 +#define PS_MAX_SUBRS_CALLS 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ + + /* execution context charstring zone */ + + typedef struct PS_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } PS_Decoder_Zone; + + + typedef FT_Error + (*CFF_Decoder_Get_Glyph_Callback)( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ); + + typedef void + (*CFF_Decoder_Free_Glyph_Callback)( TT_Face face, + FT_Byte** pointer, + FT_ULong length ); + + + typedef struct PS_Decoder_ + { + PS_Builder builder; + + FT_Fixed stack[PS_MAX_OPERANDS + 1]; + FT_Fixed* top; + + PS_Decoder_Zone zones[PS_MAX_SUBRS_CALLS + 1]; + PS_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + CFF_Font cff; + CFF_SubFont current_subfont; /* for current glyph_index */ + FT_Generic* cf2_instance; + + FT_Pos* glyph_width; + FT_Bool width_only; + FT_Int num_hints; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + FT_Byte** glyph_names; /* for pure CFF fonts only */ + FT_UInt num_glyphs; /* number of glyphs in font */ + + FT_Render_Mode hint_mode; + + FT_Bool seac; + + CFF_Decoder_Get_Glyph_Callback get_glyph_callback; + CFF_Decoder_Free_Glyph_Callback free_glyph_callback; + + /* Type 1 stuff */ + FT_Service_PsCMaps psnames; /* for seac */ + + FT_Int lenIV; /* internal for sub routine calls */ + FT_UInt* locals_len; /* array of subrs length (optional) */ + FT_Hash locals_hash; /* used if `num_subrs' was massaged */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + PS_Blend blend; /* for multiple master support */ + + FT_Long* buildchar; + FT_UInt len_buildchar; + + } PS_Decoder; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_BuilderRec_* T1_Builder; + + + typedef FT_Error + (*T1_Builder_Check_Points_Func)( T1_Builder builder, + FT_Int count ); + + typedef void + (*T1_Builder_Add_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + typedef FT_Error + (*T1_Builder_Add_Point1_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef FT_Error + (*T1_Builder_Add_Contour_Func)( T1_Builder builder ); + + typedef FT_Error + (*T1_Builder_Start_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + typedef void + (*T1_Builder_Close_Contour_Func)( T1_Builder builder ); + + + typedef const struct T1_Builder_FuncsRec_* T1_Builder_Funcs; + + typedef struct T1_Builder_FuncsRec_ + { + void + (*init)( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Bool hinting ); + + void + (*done)( T1_Builder builder ); + + T1_Builder_Check_Points_Func check_points; + T1_Builder_Add_Point_Func add_point; + T1_Builder_Add_Point1_Func add_point1; + T1_Builder_Add_Contour_Func add_contour; + T1_Builder_Start_Point_Func start_point; + T1_Builder_Close_Contour_Func close_contour; + + } T1_Builder_FuncsRec; + + + /* an enumeration type to handle charstring parsing states */ + typedef enum T1_ParseState_ + { + T1_Parse_Start, + T1_Parse_Have_Width, + T1_Parse_Have_Moveto, + T1_Parse_Have_Path + + } T1_ParseState; + + + /************************************************************************** + * + * @struct: + * T1_BuilderRec + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * XXX + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * max_points :: + * maximum points in builder outline + * + * max_contours :: + * Maximum number of contours in builder outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * parse_state :: + * An enumeration which controls the charstring parsing state. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * funcs :: + * An array of function pointers for the builder. + */ + typedef struct T1_BuilderRec_ + { + FT_Memory memory; + FT_Face face; + FT_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + T1_ParseState parse_state; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + T1_Builder_FuncsRec funcs; + + } T1_BuilderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 0 + + /************************************************************************** + * + * T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 8 + + + /************************************************************************** + * + * T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A + * minimum of 16 is required. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 + +#endif /* 0 */ + + + typedef struct T1_Decoder_ZoneRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + } T1_Decoder_ZoneRec, *T1_Decoder_Zone; + + + typedef struct T1_DecoderRec_* T1_Decoder; + typedef const struct T1_Decoder_FuncsRec_* T1_Decoder_Funcs; + + + typedef FT_Error + (*T1_Decoder_Callback)( T1_Decoder decoder, + FT_UInt glyph_index ); + + + typedef struct T1_Decoder_FuncsRec_ + { + FT_Error + (*init)( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback callback ); + + void + (*done)( T1_Decoder decoder ); + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + FT_Error + (*parse_charstrings_old)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#else + FT_Error + (*parse_metrics)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#endif + + FT_Error + (*parse_charstrings)( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + + } T1_Decoder_FuncsRec; + + + typedef struct T1_DecoderRec_ + { + T1_BuilderRec builder; + + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + + T1_Decoder_ZoneRec zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone zone; + + FT_Service_PsCMaps psnames; /* for seac */ + FT_UInt num_glyphs; + FT_Byte** glyph_names; + + FT_Int lenIV; /* internal for sub routine calls */ + FT_Int num_subrs; + FT_Byte** subrs; + FT_UInt* subrs_len; /* array of subrs length (optional) */ + FT_Hash subrs_hash; /* used if `num_subrs' was massaged */ + + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + PS_Blend blend; /* for multiple master support */ + + FT_Render_Mode hint_mode; + + T1_Decoder_Callback parse_callback; + T1_Decoder_FuncsRec funcs; + + FT_Long* buildchar; + FT_UInt len_buildchar; + + FT_Bool seac; + + FT_Generic cf2_instance; + + } T1_DecoderRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct CFF_Builder_ CFF_Builder; + + + typedef FT_Error + (*CFF_Builder_Check_Points_Func)( CFF_Builder* builder, + FT_Int count ); + + typedef void + (*CFF_Builder_Add_Point_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + typedef FT_Error + (*CFF_Builder_Add_Point1_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + typedef FT_Error + (*CFF_Builder_Start_Point_Func)( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + typedef void + (*CFF_Builder_Close_Contour_Func)( CFF_Builder* builder ); + + typedef FT_Error + (*CFF_Builder_Add_Contour_Func)( CFF_Builder* builder ); + + typedef const struct CFF_Builder_FuncsRec_* CFF_Builder_Funcs; + + typedef struct CFF_Builder_FuncsRec_ + { + void + (*init)( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ); + + void + (*done)( CFF_Builder* builder ); + + CFF_Builder_Check_Points_Func check_points; + CFF_Builder_Add_Point_Func add_point; + CFF_Builder_Add_Point1_Func add_point1; + CFF_Builder_Add_Contour_Func add_contour; + CFF_Builder_Start_Point_Func start_point; + CFF_Builder_Close_Contour_Func close_contour; + + } CFF_Builder_FuncsRec; + + + /************************************************************************** + * + * @struct: + * CFF_Builder + * + * @description: + * A structure used during glyph loading to store its outline. + * + * @fields: + * memory :: + * The current memory object. + * + * face :: + * The current face object. + * + * glyph :: + * The current glyph slot. + * + * loader :: + * The current glyph loader. + * + * base :: + * The base glyph outline. + * + * current :: + * The current glyph outline. + * + * pos_x :: + * The horizontal translation (if composite glyph). + * + * pos_y :: + * The vertical translation (if composite glyph). + * + * left_bearing :: + * The left side bearing point. + * + * advance :: + * The horizontal advance vector. + * + * bbox :: + * Unused. + * + * path_begun :: + * A flag which indicates that a new path has begun. + * + * load_points :: + * If this flag is not set, no points are loaded. + * + * no_recurse :: + * Set but not used. + * + * metrics_only :: + * A boolean indicating that we only want to compute the metrics of a + * given glyph, not load all of its points. + * + * hints_funcs :: + * Auxiliary pointer for hinting. + * + * hints_globals :: + * Auxiliary pointer for hinting. + * + * funcs :: + * A table of method pointers for this object. + */ + struct CFF_Builder_ + { + FT_Memory memory; + TT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + + FT_Pos pos_x; + FT_Pos pos_y; + + FT_Vector left_bearing; + FT_Vector advance; + + FT_BBox bbox; /* bounding box */ + + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + + FT_Bool metrics_only; + + void* hints_funcs; /* hinter-specific */ + void* hints_globals; /* hinter-specific */ + + CFF_Builder_FuncsRec funcs; + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + +#define CFF_MAX_OPERANDS 48 +#define CFF_MAX_SUBRS_CALLS 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ +#define CFF_MAX_TRANS_ELEMENTS 32 + + /* execution context charstring zone */ + + typedef struct CFF_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } CFF_Decoder_Zone; + + + typedef struct CFF_Decoder_ + { + CFF_Builder builder; + CFF_Font cff; + + FT_Fixed stack[CFF_MAX_OPERANDS + 1]; + FT_Fixed* top; + + CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1]; + CFF_Decoder_Zone* zone; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + FT_Pos glyph_width; + FT_Pos nominal_width; + + FT_Bool read_width; + FT_Bool width_only; + FT_Int num_hints; + FT_Fixed buildchar[CFF_MAX_TRANS_ELEMENTS]; + + FT_UInt num_locals; + FT_UInt num_globals; + + FT_Int locals_bias; + FT_Int globals_bias; + + FT_Byte** locals; + FT_Byte** globals; + + FT_Byte** glyph_names; /* for pure CFF fonts only */ + FT_UInt num_glyphs; /* number of glyphs in font */ + + FT_Render_Mode hint_mode; + + FT_Bool seac; + + CFF_SubFont current_subfont; /* for current glyph_index */ + + CFF_Decoder_Get_Glyph_Callback get_glyph_callback; + CFF_Decoder_Free_Glyph_Callback free_glyph_callback; + + } CFF_Decoder; + + + typedef const struct CFF_Decoder_FuncsRec_* CFF_Decoder_Funcs; + + typedef struct CFF_Decoder_FuncsRec_ + { + void + (*init)( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ); + + FT_Error + (*prepare)( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ); + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_Error + (*parse_charstrings_old)( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ); +#endif + + FT_Error + (*parse_charstrings)( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + } CFF_Decoder_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** AFM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_ParserRec_* AFM_Parser; + + typedef struct AFM_Parser_FuncsRec_ + { + FT_Error + (*init)( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + void + (*done)( AFM_Parser parser ); + + FT_Error + (*parse)( AFM_Parser parser ); + + } AFM_Parser_FuncsRec; + + + typedef struct AFM_StreamRec_* AFM_Stream; + + + /************************************************************************** + * + * @struct: + * AFM_ParserRec + * + * @description: + * An AFM_Parser is a parser for the AFM files. + * + * @fields: + * memory :: + * The object used for memory operations (alloc and realloc). + * + * stream :: + * This is an opaque object. + * + * FontInfo :: + * The result will be stored here. + * + * get_index :: + * A user provided function to get a glyph index by its name. + */ + typedef struct AFM_ParserRec_ + { + FT_Memory memory; + AFM_Stream stream; + + AFM_FontInfo FontInfo; + + FT_Int + (*get_index)( const char* name, + FT_Offset len, + void* user_data ); + + void* user_data; + + } AFM_ParserRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CHARMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef const struct T1_CMap_ClassesRec_* T1_CMap_Classes; + + typedef struct T1_CMap_ClassesRec_ + { + FT_CMap_Class standard; + FT_CMap_Class expert; + FT_CMap_Class custom; + FT_CMap_Class unicode; + + } T1_CMap_ClassesRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PSAux Module Interface *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSAux_ServiceRec_ + { + /* don't use `PS_Table_Funcs' and friends to avoid compiler warnings */ + const PS_Table_FuncsRec* ps_table_funcs; + const PS_Parser_FuncsRec* ps_parser_funcs; + const T1_Builder_FuncsRec* t1_builder_funcs; + const T1_Decoder_FuncsRec* t1_decoder_funcs; + + void + (*t1_decrypt)( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + FT_UInt32 + (*cff_random)( FT_UInt32 r ); + + void + (*ps_decoder_init)( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ); + + void + (*t1_make_subfont)( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ); + + T1_CMap_Classes t1_cmap_classes; + + /* fields after this comment line were added after version 2.1.10 */ + const AFM_Parser_FuncsRec* afm_parser_funcs; + + const CFF_Decoder_FuncsRec* cff_decoder_funcs; + + } PSAux_ServiceRec, *PSAux_Service; + + /* backward compatible type definition */ + typedef PSAux_ServiceRec PSAux_Interface; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Some convenience functions *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) + +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) + +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) + +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) + +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) + +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) + +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) + +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) + + +FT_END_HEADER + +#endif /* PSAUX_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/pshints.h b/Dependencies/freetype/freetype/include/freetype/internal/pshints.h new file mode 100644 index 00000000..dba6c730 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/pshints.h @@ -0,0 +1,699 @@ +/**************************************************************************** + * + * pshints.h + * + * Interface to Postscript-specific (Type 1 and Type 2) hints + * recorders (specification only). These are used to support native + * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHINTS_H_ +#define PSHINTS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INTERNAL REPRESENTATION OF GLOBALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PSH_GlobalsRec_* PSH_Globals; + + typedef FT_Error + (*PSH_Globals_NewFunc)( FT_Memory memory, + T1_Private* private_dict, + PSH_Globals* aglobals ); + + typedef void + (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + typedef void + (*PSH_Globals_DestroyFunc)( PSH_Globals globals ); + + + typedef struct PSH_Globals_FuncsRec_ + { + PSH_Globals_NewFunc create; + PSH_Globals_SetScaleFunc set_scale; + PSH_Globals_DestroyFunc destroy; + + } PSH_Globals_FuncsRec, *PSH_Globals_Funcs; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 1 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @type: + * T1_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 1 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the 'open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method ('stem', 'stem3', or 'reset'). Note that these functions do + * not return an error code. + * + * - Close the recording session by calling the 'close' method. It + * returns an error code if the hints were invalid or something strange + * happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * PostScript hinter. + * + */ + typedef struct T1_HintsRec_* T1_Hints; + + + /************************************************************************** + * + * @type: + * T1_Hints_Funcs + * + * @description: + * A pointer to the @T1_Hints_FuncsRec structure that defines the API of + * a given @T1_Hints object. + * + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; + + + /************************************************************************** + * + * @functype: + * T1_Hints_OpenFunc + * + * @description: + * A method of the @T1_Hints class used to prepare it for a new Type 1 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T1_Hints_OpenFunc)( T1_Hints hints ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_SetStemFunc + * + * @description: + * A method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 'hstem' and 'vstem' + * operators. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * coords :: + * Array of 2 coordinates in 16.16 format, used as (position,length) + * stem descriptor. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * 'coords[0]' is the absolute stem position (lowest coordinate); + * 'coords[1]' is the length. + * + * The length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a 'ghost' stem, according to the Type 1 + * specification. + * + * If the length is -21 (corresponding to a bottom ghost stem), then the + * real stem position is 'coords[0]+coords[1]'. + * + */ + typedef void + (*T1_Hints_SetStemFunc)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_SetStem3Func + * + * @description: + * A method of the @T1_Hints class used to record three + * counter-controlled horizontal or vertical stems at once. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems, 1 for vertical ones. + * + * coords :: + * An array of 6 values in 16.16 format, holding 3 (position,length) + * pairs for the counter-controlled stems. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * The lengths cannot be negative (ghost stems are never + * counter-controlled). + * + */ + typedef void + (*T1_Hints_SetStem3Func)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_ResetFunc + * + * @description: + * A method of the @T1_Hints class used to reset the stems hints in a + * recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph in which the + * previously defined hints apply. + * + */ + typedef void + (*T1_Hints_ResetFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_CloseFunc + * + * @description: + * A method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T1_Hints_CloseFunc)( T1_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T1_Hints_ApplyFunc + * + * @description: + * A method of the @T1_Hints class used to apply hints to the + * corresponding glyph outline. Must be called once all hints have been + * recorded. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64 of pixels. + * + * The scaling transformation is taken from the 'globals' object which + * must correspond to the same font as the glyph. + * + */ + typedef FT_Error + (*T1_Hints_ApplyFunc)( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************** + * + * @struct: + * T1_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T1_Hints objects. + * + * @fields: + * hints :: + * A handle to the T1 Hints recorder. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stem :: + * The function to set a simple stem. + * + * stem3 :: + * The function to set counter-controlled stems. + * + * reset :: + * The function to reset stem hints. + * + * apply :: + * The function to apply the hints to the corresponding glyph outline. + * + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints hints; + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + T1_Hints_ApplyFunc apply; + + } T1_Hints_FuncsRec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PUBLIC TYPE 2 HINTS RECORDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @type: + * T2_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 2 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the 'open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method ('stems', 'hintmask', 'counters'). Note that these functions + * do not return an error code. + * + * - Close the recording session by calling the 'close' method. It + * returns an error code if the hints were invalid or something strange + * happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * Postscript hinter. + * + */ + typedef struct T2_HintsRec_* T2_Hints; + + + /************************************************************************** + * + * @type: + * T2_Hints_Funcs + * + * @description: + * A pointer to the @T2_Hints_FuncsRec structure that defines the API of + * a given @T2_Hints object. + * + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; + + + /************************************************************************** + * + * @functype: + * T2_Hints_OpenFunc + * + * @description: + * A method of the @T2_Hints class used to prepare it for a new Type 2 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T2_Hints_OpenFunc)( T2_Hints hints ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_StemsFunc + * + * @description: + * A method of the @T2_Hints class used to set the table of stems in + * either the vertical or horizontal dimension. Equivalent to the + * 'hstem', 'vstem', 'hstemhm', and 'vstemhm' Type 2 operators. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * count :: + * The number of stems. + * + * coords :: + * An array of 'count' (position,length) pairs in 16.16 format. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * There are '2*count' elements in the 'coords' array. Each even element + * is an absolute position in font units, each odd element is a length in + * font units. + * + * A length can be negative, in which case it must be either -20 or -21. + * It is interpreted as a 'ghost' stem, according to the Type 1 + * specification. + * + */ + typedef void + (*T2_Hints_StemsFunc)( T2_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Fixed* coordinates ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_MaskFunc + * + * @description: + * A method of the @T2_Hints class used to set a given hintmask (this + * corresponds to the 'hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The glyph index of the last point to which the previously defined or + * activated hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point` should be 0. + * + * `bit_count` is the number of meaningful bits in the 'bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The 'bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_MaskFunc)( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_CounterFunc + * + * @description: + * A method of the @T2_Hints class used to set a given counter mask (this + * corresponds to the 'hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * A glyph index of the last point to which the previously defined or + * active hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point` should be 0. + * + * `bit_count` is the number of meaningful bits in the 'bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The 'bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_CloseFunc + * + * @description: + * A method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T2_Hints_CloseFunc)( T2_Hints hints, + FT_UInt end_point ); + + + /************************************************************************** + * + * @functype: + * T2_Hints_ApplyFunc + * + * @description: + * A method of the @T2_Hints class used to apply hints to the + * corresponding glyph outline. Must be called after the 'close' method. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64 of pixels. + * + * The scaling transformation is taken from the 'globals' object which + * must correspond to the same font than the glyph. + * + */ + typedef FT_Error + (*T2_Hints_ApplyFunc)( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + + /************************************************************************** + * + * @struct: + * T2_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T2_Hints objects. + * + * @fields: + * hints :: + * A handle to the T2 hints recorder object. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stems :: + * The function to set the dimension's stems table. + * + * hintmask :: + * The function to set hint masks. + * + * counter :: + * The function to set counter masks. + * + * apply :: + * The function to apply the hints on the corresponding glyph outline. + * + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints hints; + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + T2_Hints_ApplyFunc apply; + + } T2_Hints_FuncsRec; + + + /* */ + + + typedef struct PSHinter_Interface_ + { + PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module ); + T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module ); + T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module ); + + } PSHinter_Interface; + + typedef PSHinter_Interface* PSHinter_Service; + + +#define FT_DEFINE_PSHINTER_INTERFACE( \ + class_, \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ ) \ + static const PSHinter_Interface class_ = \ + { \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ \ + }; + + +FT_END_HEADER + +#endif /* PSHINTS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svbdf.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svbdf.h new file mode 100644 index 00000000..89e9c2e5 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svbdf.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * svbdf.h + * + * The FreeType BDF services (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVBDF_H_ +#define SVBDF_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_BDF "bdf" + + typedef FT_Error + (*FT_BDF_GetCharsetIdFunc)( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + + typedef FT_Error + (*FT_BDF_GetPropertyFunc)( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + + + FT_DEFINE_SERVICE( BDF ) + { + FT_BDF_GetCharsetIdFunc get_charset_id; + FT_BDF_GetPropertyFunc get_property; + }; + + +#define FT_DEFINE_SERVICE_BDFRec( class_, \ + get_charset_id_, \ + get_property_ ) \ + static const FT_Service_BDFRec class_ = \ + { \ + get_charset_id_, get_property_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVBDF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svcfftl.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svcfftl.h new file mode 100644 index 00000000..3cb483c3 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svcfftl.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * svcfftl.h + * + * The FreeType CFF tables loader service (specification). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVCFFTL_H_ +#define SVCFFTL_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_CFF_LOAD "cff-load" + + + typedef FT_UShort + (*FT_Get_Standard_Encoding_Func)( FT_UInt charcode ); + + typedef FT_Error + (*FT_Load_Private_Dict_Func)( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + typedef FT_Byte + (*FT_FD_Select_Get_Func)( CFF_FDSelect fdselect, + FT_UInt glyph_index ); + + typedef FT_Bool + (*FT_Blend_Check_Vector_Func)( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + typedef FT_Error + (*FT_Blend_Build_Vector_Func)( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + + FT_DEFINE_SERVICE( CFFLoad ) + { + FT_Get_Standard_Encoding_Func get_standard_encoding; + FT_Load_Private_Dict_Func load_private_dict; + FT_FD_Select_Get_Func fd_select_get; + FT_Blend_Check_Vector_Func blend_check_vector; + FT_Blend_Build_Vector_Func blend_build_vector; + }; + + +#define FT_DEFINE_SERVICE_CFFLOADREC( class_, \ + get_standard_encoding_, \ + load_private_dict_, \ + fd_select_get_, \ + blend_check_vector_, \ + blend_build_vector_ ) \ + static const FT_Service_CFFLoadRec class_ = \ + { \ + get_standard_encoding_, \ + load_private_dict_, \ + fd_select_get_, \ + blend_check_vector_, \ + blend_build_vector_ \ + }; + + +FT_END_HEADER + + +#endif + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svcid.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svcid.h new file mode 100644 index 00000000..8362cb87 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svcid.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * + * svcid.h + * + * The FreeType CID font services (specification). + * + * Copyright (C) 2007-2024 by + * Derek Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVCID_H_ +#define SVCID_H_ + +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_CID "CID" + + typedef FT_Error + (*FT_CID_GetRegistryOrderingSupplementFunc)( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + typedef FT_Error + (*FT_CID_GetIsInternallyCIDKeyedFunc)( FT_Face face, + FT_Bool *is_cid ); + typedef FT_Error + (*FT_CID_GetCIDFromGlyphIndexFunc)( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + + FT_DEFINE_SERVICE( CID ) + { + FT_CID_GetRegistryOrderingSupplementFunc get_ros; + FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid; + FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index; + }; + + +#define FT_DEFINE_SERVICE_CIDREC( class_, \ + get_ros_, \ + get_is_cid_, \ + get_cid_from_glyph_index_ ) \ + static const FT_Service_CIDRec class_ = \ + { \ + get_ros_, get_is_cid_, get_cid_from_glyph_index_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVCID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svfntfmt.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svfntfmt.h new file mode 100644 index 00000000..6b837e79 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svfntfmt.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * svfntfmt.h + * + * The FreeType font format service (specification only). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVFNTFMT_H_ +#define SVFNTFMT_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A trivial service used to return the name of a face's font driver, + * according to the XFree86 nomenclature. Note that the service data is a + * simple constant string pointer. + */ + +#define FT_SERVICE_ID_FONT_FORMAT "font-format" + +#define FT_FONT_FORMAT_TRUETYPE "TrueType" +#define FT_FONT_FORMAT_TYPE_1 "Type 1" +#define FT_FONT_FORMAT_BDF "BDF" +#define FT_FONT_FORMAT_PCF "PCF" +#define FT_FONT_FORMAT_TYPE_42 "Type 42" +#define FT_FONT_FORMAT_CID "CID Type 1" +#define FT_FONT_FORMAT_CFF "CFF" +#define FT_FONT_FORMAT_PFR "PFR" +#define FT_FONT_FORMAT_WINFNT "Windows FNT" + + /* */ + + +FT_END_HEADER + + +#endif /* SVFNTFMT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svgldict.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svgldict.h new file mode 100644 index 00000000..6126ec9a --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svgldict.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * + * svgldict.h + * + * The FreeType glyph dictionary services (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVGLDICT_H_ +#define SVGLDICT_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A service used to retrieve glyph names, as well as to find the index of + * a given glyph name in a font. + * + */ + +#define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" + + + typedef FT_Error + (*FT_GlyphDict_GetNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + + typedef FT_UInt + (*FT_GlyphDict_NameIndexFunc)( FT_Face face, + const FT_String* glyph_name ); + + + FT_DEFINE_SERVICE( GlyphDict ) + { + FT_GlyphDict_GetNameFunc get_name; + FT_GlyphDict_NameIndexFunc name_index; /* optional */ + }; + + +#define FT_DEFINE_SERVICE_GLYPHDICTREC( class_, \ + get_name_, \ + name_index_ ) \ + static const FT_Service_GlyphDictRec class_ = \ + { \ + get_name_, name_index_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVGLDICT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svgxval.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svgxval.h new file mode 100644 index 00000000..29cf5528 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svgxval.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * + * svgxval.h + * + * FreeType API for validating TrueTypeGX/AAT tables (specification). + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef SVGXVAL_H_ +#define SVGXVAL_H_ + +#include +#include + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_GX_VALIDATE "truetypegx-validate" +#define FT_SERVICE_ID_CLASSICKERN_VALIDATE "classickern-validate" + + typedef FT_Error + (*gxv_validate_func)( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + + + typedef FT_Error + (*ckern_validate_func)( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes *ckern_table ); + + + FT_DEFINE_SERVICE( GXvalidate ) + { + gxv_validate_func validate; + }; + + FT_DEFINE_SERVICE( CKERNvalidate ) + { + ckern_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVGXVAL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svkern.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svkern.h new file mode 100644 index 00000000..ac1bc30c --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svkern.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * svkern.h + * + * The FreeType Kerning service (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVKERN_H_ +#define SVKERN_H_ + +#include +#include + + +FT_BEGIN_HEADER + +#define FT_SERVICE_ID_KERNING "kerning" + + + typedef FT_Error + (*FT_Kerning_TrackGetFunc)( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + + FT_DEFINE_SERVICE( Kerning ) + { + FT_Kerning_TrackGetFunc get_track; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVKERN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svmetric.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svmetric.h new file mode 100644 index 00000000..8b3563b2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svmetric.h @@ -0,0 +1,131 @@ +/**************************************************************************** + * + * svmetric.h + * + * The FreeType services for metrics variations (specification). + * + * Copyright (C) 2016-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVMETRIC_H_ +#define SVMETRIC_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * A service to manage the `HVAR, `MVAR', and `VVAR' OpenType tables. + * + */ + +#define FT_SERVICE_ID_METRICS_VARIATIONS "metrics-variations" + + + /* HVAR */ + + typedef FT_Error + (*FT_HAdvance_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_LSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_RSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + /* VVAR */ + + typedef FT_Error + (*FT_VAdvance_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_TSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_BSB_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + typedef FT_Error + (*FT_VOrg_Adjust_Func)( FT_Face face, + FT_UInt gindex, + FT_Int *avalue ); + + /* MVAR */ + + typedef void + (*FT_Metrics_Adjust_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Size_Reset_Func)( FT_Size size ); + + + FT_DEFINE_SERVICE( MetricsVariations ) + { + FT_HAdvance_Adjust_Func hadvance_adjust; + FT_LSB_Adjust_Func lsb_adjust; + FT_RSB_Adjust_Func rsb_adjust; + + FT_VAdvance_Adjust_Func vadvance_adjust; + FT_TSB_Adjust_Func tsb_adjust; + FT_BSB_Adjust_Func bsb_adjust; + FT_VOrg_Adjust_Func vorg_adjust; + + FT_Metrics_Adjust_Func metrics_adjust; + FT_Size_Reset_Func size_reset; + }; + + +#define FT_DEFINE_SERVICE_METRICSVARIATIONSREC( class_, \ + hadvance_adjust_, \ + lsb_adjust_, \ + rsb_adjust_, \ + vadvance_adjust_, \ + tsb_adjust_, \ + bsb_adjust_, \ + vorg_adjust_, \ + metrics_adjust_, \ + size_reset_ ) \ + static const FT_Service_MetricsVariationsRec class_ = \ + { \ + hadvance_adjust_, \ + lsb_adjust_, \ + rsb_adjust_, \ + vadvance_adjust_, \ + tsb_adjust_, \ + bsb_adjust_, \ + vorg_adjust_, \ + metrics_adjust_, \ + size_reset_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVMETRIC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svmm.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svmm.h new file mode 100644 index 00000000..5288fadf --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svmm.h @@ -0,0 +1,214 @@ +/**************************************************************************** + * + * svmm.h + * + * The FreeType Multiple Masters and GX var services (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVMM_H_ +#define SVMM_H_ + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* + * A service used to manage multiple-masters data in a given face. + * + * See the related APIs in `ftmm.h' (FT_MULTIPLE_MASTERS_H). + * + */ + +#define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" + + + typedef FT_Error + (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + + typedef FT_Error + (*FT_Get_MM_Var_Func)( FT_Face face, + FT_MM_Var* *master ); + + typedef FT_Error + (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + /* use return value -1 to indicate that the new coordinates */ + /* are equal to the current ones; no changes are thus needed */ + typedef FT_Error + (*FT_Set_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + /* use return value -1 to indicate that the new coordinates */ + /* are equal to the current ones; no changes are thus needed */ + typedef FT_Error + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Get_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Set_Named_Instance_Func)( FT_Face face, + FT_UInt instance_index ); + + typedef FT_Error + (*FT_Get_Default_Named_Instance_Func)( FT_Face face, + FT_UInt *instance_index ); + + typedef FT_Error + (*FT_Get_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + typedef FT_Error + (*FT_Get_Var_Blend_Func)( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + typedef void + (*FT_Done_Blend_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Set_MM_WeightVector_Func)( FT_Face face, + FT_UInt len, + FT_Fixed* weight_vector ); + + typedef FT_Error + (*FT_Get_MM_WeightVector_Func)( FT_Face face, + FT_UInt* len, + FT_Fixed* weight_vector ); + + typedef void + (*FT_Construct_PS_Name_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + typedef FT_Error + (*FT_Var_Load_Item_Var_Store_Func)( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + typedef FT_ItemVarDelta + (*FT_Var_Get_Item_Delta_Func)( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + typedef void + (*FT_Var_Done_Item_Var_Store_Func)( FT_Face face, + GX_ItemVarStore itemStore ); + + typedef void + (*FT_Var_Done_Delta_Set_Idx_Map_Func)( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + + + FT_DEFINE_SERVICE( MultiMasters ) + { + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Blend_Func get_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + FT_Get_Var_Design_Func get_var_design; + FT_Set_Named_Instance_Func set_named_instance; + FT_Get_Default_Named_Instance_Func get_default_named_instance; + FT_Set_MM_WeightVector_Func set_mm_weightvector; + FT_Get_MM_WeightVector_Func get_mm_weightvector; + + /* for internal use; only needed for code sharing between modules */ + FT_Construct_PS_Name_Func construct_ps_name; + FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map; + FT_Var_Load_Item_Var_Store_Func load_item_var_store; + FT_Var_Get_Item_Delta_Func get_item_delta; + FT_Var_Done_Item_Var_Store_Func done_item_var_store; + FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_idx_map; + FT_Get_Var_Blend_Func get_var_blend; + FT_Done_Blend_Func done_blend; + }; + + +#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ ) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVMM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svotval.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svotval.h new file mode 100644 index 00000000..7aea7ec1 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svotval.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * svotval.h + * + * The FreeType OpenType validation service (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVOTVAL_H_ +#define SVOTVAL_H_ + +#include +#include + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + + + typedef FT_Error + (*otv_validate_func)( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + + + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVOTVAL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svpfr.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svpfr.h new file mode 100644 index 00000000..b2fac6d0 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svpfr.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * + * svpfr.h + * + * Internal PFR service functions (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPFR_H_ +#define SVPFR_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PFR_METRICS "pfr-metrics" + + + typedef FT_Error + (*FT_PFR_GetMetricsFunc)( FT_Face face, + FT_UInt *aoutline, + FT_UInt *ametrics, + FT_Fixed *ax_scale, + FT_Fixed *ay_scale ); + + typedef FT_Error + (*FT_PFR_GetKerningFunc)( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + + typedef FT_Error + (*FT_PFR_GetAdvanceFunc)( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + + + FT_DEFINE_SERVICE( PfrMetrics ) + { + FT_PFR_GetMetricsFunc get_metrics; + FT_PFR_GetKerningFunc get_kerning; + FT_PFR_GetAdvanceFunc get_advance; + + }; + + +FT_END_HEADER + +#endif /* SVPFR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svpostnm.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svpostnm.h new file mode 100644 index 00000000..d19f3adc --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svpostnm.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * + * svpostnm.h + * + * The FreeType PostScript name services (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPOSTNM_H_ +#define SVPOSTNM_H_ + +#include + + +FT_BEGIN_HEADER + + /* + * A trivial service used to retrieve the PostScript name of a given font + * when available. The `get_name' field should never be `NULL`. + * + * The corresponding function can return `NULL` to indicate that the + * PostScript name is not available. + * + * The name is owned by the face and will be destroyed with it. + */ + +#define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" + + + typedef const char* + (*FT_PsName_GetFunc)( FT_Face face ); + + + FT_DEFINE_SERVICE( PsFontName ) + { + FT_PsName_GetFunc get_ps_font_name; + }; + + +#define FT_DEFINE_SERVICE_PSFONTNAMEREC( class_, get_ps_font_name_ ) \ + static const FT_Service_PsFontNameRec class_ = \ + { \ + get_ps_font_name_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPOSTNM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svprop.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svprop.h new file mode 100644 index 00000000..ba39c0dd --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svprop.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * svprop.h + * + * The FreeType property service (specification). + * + * Copyright (C) 2012-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPROP_H_ +#define SVPROP_H_ + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_PROPERTIES "properties" + + + typedef FT_Error + (*FT_Properties_SetFunc)( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ); + + typedef FT_Error + (*FT_Properties_GetFunc)( FT_Module module, + const char* property_name, + void* value ); + + + FT_DEFINE_SERVICE( Properties ) + { + FT_Properties_SetFunc set_property; + FT_Properties_GetFunc get_property; + }; + + +#define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ + set_property_, \ + get_property_ ) \ + static const FT_Service_PropertiesRec class_ = \ + { \ + set_property_, \ + get_property_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPROP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svpscmap.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svpscmap.h new file mode 100644 index 00000000..d4908ee4 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svpscmap.h @@ -0,0 +1,145 @@ +/**************************************************************************** + * + * svpscmap.h + * + * The FreeType PostScript charmap service (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPSCMAP_H_ +#define SVPSCMAP_H_ + +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" + + + /* + * Adobe glyph name to unicode value. + */ + typedef FT_UInt32 + (*PS_Unicode_ValueFunc)( const char* glyph_name ); + + /* + * Macintosh name id to glyph name. `NULL` if invalid index. + */ + typedef const char* + (*PS_Macintosh_NameFunc)( FT_UInt name_index ); + + /* + * Adobe standard string ID to glyph name. `NULL` if invalid index. + */ + typedef const char* + (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); + + + /* + * Simple unicode -> glyph index charmap built from font glyph names table. + */ + typedef struct PS_UniMap_ + { + FT_UInt32 unicode; /* bit 31 set: is glyph variant */ + FT_UInt glyph_index; + + } PS_UniMap; + + + typedef struct PS_UnicodesRec_* PS_Unicodes; + + typedef struct PS_UnicodesRec_ + { + FT_CMapRec cmap; + FT_UInt num_maps; + PS_UniMap* maps; + + } PS_UnicodesRec; + + + /* + * A function which returns a glyph name for a given index. Returns + * `NULL` if invalid index. + */ + typedef const char* + (*PS_GetGlyphNameFunc)( FT_Pointer data, + FT_UInt string_index ); + + /* + * A function used to release the glyph name returned by + * PS_GetGlyphNameFunc, when needed + */ + typedef void + (*PS_FreeGlyphNameFunc)( FT_Pointer data, + const char* name ); + + typedef FT_Error + (*PS_Unicodes_InitFunc)( FT_Memory memory, + PS_Unicodes unicodes, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ); + + typedef FT_UInt + (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, + FT_UInt32 unicode ); + + typedef FT_UInt + (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, + FT_UInt32 *unicode ); + + + FT_DEFINE_SERVICE( PsCMaps ) + { + PS_Unicode_ValueFunc unicode_value; + + PS_Unicodes_InitFunc unicodes_init; + PS_Unicodes_CharIndexFunc unicodes_char_index; + PS_Unicodes_CharNextFunc unicodes_char_next; + + PS_Macintosh_NameFunc macintosh_name; + PS_Adobe_Std_StringsFunc adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + }; + + +#define FT_DEFINE_SERVICE_PSCMAPSREC( class_, \ + unicode_value_, \ + unicodes_init_, \ + unicodes_char_index_, \ + unicodes_char_next_, \ + macintosh_name_, \ + adobe_std_strings_, \ + adobe_std_encoding_, \ + adobe_expert_encoding_ ) \ + static const FT_Service_PsCMapsRec class_ = \ + { \ + unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPSCMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svpsinfo.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svpsinfo.h new file mode 100644 index 00000000..2aadcdd0 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svpsinfo.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * + * svpsinfo.h + * + * The FreeType PostScript info service (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVPSINFO_H_ +#define SVPSINFO_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" + + + typedef FT_Error + (*PS_GetFontInfoFunc)( FT_Face face, + PS_FontInfoRec* afont_info ); + + typedef FT_Error + (*PS_GetFontExtraFunc)( FT_Face face, + PS_FontExtraRec* afont_extra ); + + typedef FT_Int + (*PS_HasGlyphNamesFunc)( FT_Face face ); + + typedef FT_Error + (*PS_GetFontPrivateFunc)( FT_Face face, + PS_PrivateRec* afont_private ); + + typedef FT_Long + (*PS_GetFontValueFunc)( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); + + + FT_DEFINE_SERVICE( PsInfo ) + { + PS_GetFontInfoFunc ps_get_font_info; + PS_GetFontExtraFunc ps_get_font_extra; + PS_HasGlyphNamesFunc ps_has_glyph_names; + PS_GetFontPrivateFunc ps_get_font_private; + PS_GetFontValueFunc ps_get_font_value; + }; + + +#define FT_DEFINE_SERVICE_PSINFOREC( class_, \ + get_font_info_, \ + ps_get_font_extra_, \ + has_glyph_names_, \ + get_font_private_, \ + get_font_value_ ) \ + static const FT_Service_PsInfoRec class_ = \ + { \ + get_font_info_, ps_get_font_extra_, has_glyph_names_, \ + get_font_private_, get_font_value_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVPSINFO_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svsfnt.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svsfnt.h new file mode 100644 index 00000000..9e0f4ff2 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svsfnt.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * + * svsfnt.h + * + * The FreeType SFNT table loading service (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVSFNT_H_ +#define SVSFNT_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" + + + /* + * Used to implement FT_Load_Sfnt_Table(). + */ + typedef FT_Error + (*FT_SFNT_TableLoadFunc)( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + /* + * Used to implement FT_Get_Sfnt_Table(). + */ + typedef void* + (*FT_SFNT_TableGetFunc)( FT_Face face, + FT_Sfnt_Tag tag ); + + + /* + * Used to implement FT_Sfnt_Table_Info(). + */ + typedef FT_Error + (*FT_SFNT_TableInfoFunc)( FT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ); + + + FT_DEFINE_SERVICE( SFNT_Table ) + { + FT_SFNT_TableLoadFunc load_table; + FT_SFNT_TableGetFunc get_table; + FT_SFNT_TableInfoFunc table_info; + }; + + +#define FT_DEFINE_SERVICE_SFNT_TABLEREC( class_, load_, get_, info_ ) \ + static const FT_Service_SFNT_TableRec class_ = \ + { \ + load_, get_, info_ \ + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVSFNT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svttcmap.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svttcmap.h new file mode 100644 index 00000000..250886bc --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svttcmap.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * svttcmap.h + * + * The FreeType TrueType/sfnt cmap extra information service. + * + * Copyright (C) 2003-2024 by + * Masatake YAMATO, Redhat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/* Development of this service is support of + Information-technology Promotion Agency, Japan. */ + +#ifndef SVTTCMAP_H_ +#define SVTTCMAP_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_CMAP "tt-cmaps" + + + /************************************************************************** + * + * @struct: + * TT_CMapInfo + * + * @description: + * A structure used to store TrueType/sfnt specific cmap information + * which is not covered by the generic @FT_CharMap structure. This + * structure can be accessed with the @FT_Get_TT_CMap_Info function. + * + * @fields: + * language :: + * The language ID used in Mac fonts. Definitions of values are in + * `ttnameid.h`. + * + * format :: + * The cmap format. OpenType 1.6 defines the formats 0 (byte encoding + * table), 2~(high-byte mapping through table), 4~(segment mapping to + * delta values), 6~(trimmed table mapping), 8~(mixed 16-bit and 32-bit + * coverage), 10~(trimmed array), 12~(segmented coverage), 13~(last + * resort font), and 14 (Unicode Variation Sequences). + */ + typedef struct TT_CMapInfo_ + { + FT_ULong language; + FT_Long format; + + } TT_CMapInfo; + + + typedef FT_Error + (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + + FT_DEFINE_SERVICE( TTCMaps ) + { + TT_CMap_Info_GetFunc get_cmap_info; + }; + + +#define FT_DEFINE_SERVICE_TTCMAPSREC( class_, get_cmap_info_ ) \ + static const FT_Service_TTCMapsRec class_ = \ + { \ + get_cmap_info_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVTTCMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svtteng.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svtteng.h new file mode 100644 index 00000000..14967529 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svtteng.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * + * svtteng.h + * + * The FreeType TrueType engine query service (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVTTENG_H_ +#define SVTTENG_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * SFNT table loading service. + */ + +#define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" + + /* + * Used to implement FT_Get_TrueType_Engine_Type + */ + + FT_DEFINE_SERVICE( TrueTypeEngine ) + { + FT_TrueTypeEngineType engine_type; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVTTENG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svttglyf.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svttglyf.h new file mode 100644 index 00000000..f190b398 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svttglyf.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * svttglyf.h + * + * The FreeType TrueType glyph service. + * + * Copyright (C) 2007-2024 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef SVTTGLYF_H_ +#define SVTTGLYF_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_TT_GLYF "tt-glyf" + + + typedef FT_ULong + (*TT_Glyf_GetLocationFunc)( FT_Face face, + FT_UInt gindex, + FT_ULong *psize ); + + FT_DEFINE_SERVICE( TTGlyf ) + { + TT_Glyf_GetLocationFunc get_location; + }; + + +#define FT_DEFINE_SERVICE_TTGLYFREC( class_, get_location_ ) \ + static const FT_Service_TTGlyfRec class_ = \ + { \ + get_location_ \ + }; + + /* */ + + +FT_END_HEADER + +#endif /* SVTTGLYF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/services/svwinfnt.h b/Dependencies/freetype/freetype/include/freetype/internal/services/svwinfnt.h new file mode 100644 index 00000000..49f3fb7f --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/services/svwinfnt.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * svwinfnt.h + * + * The FreeType Windows FNT/FONT service (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVWINFNT_H_ +#define SVWINFNT_H_ + +#include +#include + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_WINFNT "winfonts" + + typedef FT_Error + (*FT_WinFnt_GetHeaderFunc)( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + + + FT_DEFINE_SERVICE( WinFnt ) + { + FT_WinFnt_GetHeaderFunc get_header; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* SVWINFNT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/sfnt.h b/Dependencies/freetype/freetype/include/freetype/internal/sfnt.h new file mode 100644 index 00000000..35e4e73a --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/sfnt.h @@ -0,0 +1,1099 @@ +/**************************************************************************** + * + * sfnt.h + * + * High-level 'sfnt' driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFNT_H_ +#define SFNT_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @functype: + * TT_Init_Face_Func + * + * @description: + * First part of the SFNT face object initialization. This finds the + * face in a SFNT file or collection, and load its format tag in + * face->format_tag. + * + * @input: + * stream :: + * The input stream. + * + * face :: + * A handle to the target face object. + * + * face_index :: + * The index of the TrueType font, if we are opening a collection, in + * bits 0-15. The numbered instance index~+~1 of a GX (sub)font, if + * applicable, in bits 16-30. + * + * num_params :: + * The number of additional parameters. + * + * params :: + * Optional additional parameters. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be at the font file's origin. + * + * This function recognizes fonts embedded in a 'TrueType collection'. + * + * Once the format tag has been validated by the font driver, it should + * then call the TT_Load_Face_Func() callback to read the rest of the + * SFNT tables in the object. + */ + typedef FT_Error + (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Face_Func + * + * @description: + * Second part of the SFNT face object initialization. This loads the + * common SFNT tables (head, OS/2, maxp, metrics, etc.) in the face + * object. + * + * @input: + * stream :: + * The input stream. + * + * face :: + * A handle to the target face object. + * + * face_index :: + * The index of the TrueType font, if we are opening a collection, in + * bits 0-15. The numbered instance index~+~1 of a GX (sub)font, if + * applicable, in bits 16-30. + * + * num_params :: + * The number of additional parameters. + * + * params :: + * Optional additional parameters. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function must be called after TT_Init_Face_Func(). + */ + typedef FT_Error + (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + /************************************************************************** + * + * @functype: + * TT_Done_Face_Func + * + * @description: + * A callback used to delete the common SFNT data from a face. + * + * @input: + * face :: + * A handle to the target face object. + * + * @note: + * This function does NOT destroy the face object. + */ + typedef void + (*TT_Done_Face_Func)( TT_Face face ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Any_Func + * + * @description: + * Load any font table into client memory. + * + * @input: + * face :: + * The face object to look for. + * + * tag :: + * The tag of table to load. Use the value 0 if you want to access the + * whole font file, else set this parameter to a valid TrueType table + * tag that you can forge with the MAKE_TT_TAG macro. + * + * offset :: + * The starting offset in the table (or the file if tag == 0). + * + * length :: + * The address of the decision variable: + * + * If `length == NULL`: Loads the whole table. Returns an error if + * 'offset' == 0! + * + * If `*length == 0`: Exits immediately; returning the length of the + * given table or of the font file, depending on the value of 'tag'. + * + * If `*length != 0`: Loads the next 'length' bytes of table or font, + * starting at offset 'offset' (in table or font too). + * + * @output: + * buffer :: + * The address of target buffer. + * + * @return: + * TrueType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte *buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @functype: + * TT_Find_SBit_Image_Func + * + * @description: + * Check whether an embedded bitmap (an 'sbit') exists for a given glyph, + * at a given strike. + * + * @input: + * face :: + * The target face object. + * + * glyph_index :: + * The glyph index. + * + * strike_index :: + * The current strike index. + * + * @output: + * arange :: + * The SBit range containing the glyph index. + * + * astrike :: + * The SBit strike containing the glyph index. + * + * aglyph_offset :: + * The offset of the glyph data in 'EBDT' table. + * + * @return: + * FreeType error code. 0 means success. Returns + * SFNT_Err_Invalid_Argument if no sbit exists for the requested glyph. + */ + typedef FT_Error + (*TT_Find_SBit_Image_Func)( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); + + + /************************************************************************** + * + * @functype: + * TT_Load_SBit_Metrics_Func + * + * @description: + * Get the big metrics for a given embedded bitmap. + * + * @input: + * stream :: + * The input stream. + * + * range :: + * The SBit range containing the glyph. + * + * @output: + * big_metrics :: + * A big SBit metrics structure for the glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be positioned at the glyph's offset within the + * 'EBDT' table before the call. + * + * If the image format uses variable metrics, the stream cursor is + * positioned just after the metrics header in the 'EBDT' table on + * function exit. + */ + typedef FT_Error + (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); + + + /************************************************************************** + * + * @functype: + * TT_Load_SBit_Image_Func + * + * @description: + * Load a given glyph sbit image from the font resource. This also + * returns its metrics. + * + * @input: + * face :: + * The target face object. + * + * strike_index :: + * The strike index. + * + * glyph_index :: + * The current glyph index. + * + * load_flags :: + * The current load flags. + * + * stream :: + * The input stream. + * + * @output: + * amap :: + * The target pixmap. + * + * ametrics :: + * A big sbit metrics structure for the glyph image. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no glyph + * sbit exists for the index. + * + * @note: + * The `map.buffer` field is always freed before the glyph is loaded. + */ + typedef FT_Error + (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *amap, + TT_SBit_MetricsRec *ametrics ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Svg_Doc_Func + * + * @description: + * Scan the SVG document list to find the document containing the glyph + * that has the ID 'glyph*XXX*', where *XXX* is the value of + * `glyph_index` as a decimal integer. + * + * @inout: + * glyph :: + * The glyph slot from which pointers to the SVG document list is to be + * grabbed. The results are stored back in the slot. + * + * @input: + * glyph_index :: + * The index of the glyph that is to be looked up. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Svg_Doc_Func)( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + + + /************************************************************************** + * + * @functype: + * TT_Set_SBit_Strike_Func + * + * @description: + * Select an sbit strike for a given size request. + * + * @input: + * face :: + * The target face object. + * + * req :: + * The size request. + * + * @output: + * astrike_index :: + * The index of the sbit strike. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no sbit + * strike exists for the selected ppem values. + */ + typedef FT_Error + (*TT_Set_SBit_Strike_Func)( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Strike_Metrics_Func + * + * @description: + * Load the metrics of a given strike. + * + * @input: + * face :: + * The target face object. + * + * strike_index :: + * The strike index. + * + * @output: + * metrics :: + * the metrics of the strike. + * + * @return: + * FreeType error code. 0 means success. Returns an error if no such + * sbit strike exists. + */ + typedef FT_Error + (*TT_Load_Strike_Metrics_Func)( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + + /************************************************************************** + * + * @functype: + * TT_Get_PS_Name_Func + * + * @description: + * Get the PostScript glyph name of a glyph. + * + * @input: + * idx :: + * The glyph index. + * + * PSname :: + * The address of a string pointer. Will be `NULL` in case of error, + * otherwise it is a pointer to the glyph name. + * + * You must not modify the returned string! + * + * @output: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Metrics_Func + * + * @description: + * Load a metrics table, which is a table with a horizontal and a + * vertical version. + * + * @input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load the vertical one. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Metrics_Func + * + * @description: + * Load the horizontal or vertical header in a face object. + * + * @input: + * face :: + * A handle to the target face object. + * + * vertical :: + * A boolean flag. If set, load vertical metrics. + * + * gindex :: + * The glyph index. + * + * @output: + * abearing :: + * The horizontal (or vertical) bearing. Set to zero in case of error. + * + * aadvance :: + * The horizontal (or vertical) advance. Set to zero in case of error. + */ + typedef void + (*TT_Get_Metrics_Func)( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + + + /************************************************************************** + * + * @functype: + * TT_Set_Palette_Func + * + * @description: + * Load the colors into `face->palette` for a given palette index. + * + * @input: + * face :: + * The target face object. + * + * idx :: + * The palette index. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Set_Palette_Func)( TT_Face face, + FT_UInt idx ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colr_Layer_Func + * + * @description: + * Iteratively get the color layer data of a given glyph index. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + */ + typedef FT_Bool + (*TT_Get_Colr_Layer_Func)( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_Paint_Func + * + * @description: + * Find the root @FT_OpaquePaint object for a given glyph ID. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_ClipBox_Func + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @return: + * Value~1 if a ClipBox is found. If no clip box is found or an + * error occured, value~0 is returned. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Layers_Func + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object referencing the actual paint table. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + */ + typedef FT_Bool + ( *TT_Get_Paint_Layers_Func )( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colorline_Stops_Func + * + * @description: + * Get the gradient and solid fill information for a given glyph. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * An @FT_ColorStopIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + */ + typedef FT_Bool + ( *TT_Get_Colorline_Stops_Func )( TT_Face face, + FT_ColorStop *color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Func + * + * @description: + * Get the paint details for a given @FT_OpaquePaint object. + * + * @input: + * face :: + * The target face object. + * + * opaque_paint :: + * The @FT_OpaquePaint object. + * + * @output: + * paint :: + * An @FT_COLR_Paint object holding the details on `opaque_paint`. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + */ + typedef FT_Bool + ( *TT_Get_Paint_Func )( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Blend_Colr_Func + * + * @description: + * Blend the bitmap in `new_glyph` into `base_glyph` using the color + * specified by `color_index`. If `color_index` is 0xFFFF, use + * `face->foreground_color` if `face->have_foreground_color` is set. + * Otherwise check `face->palette_data.palette_flags`: If present and + * @FT_PALETTE_FOR_DARK_BACKGROUND is set, use BGRA value 0xFFFFFFFF + * (white opaque). Otherwise use BGRA value 0x000000FF (black opaque). + * + * @input: + * face :: + * The target face object. + * + * color_index :: + * Color index from the COLR table. + * + * base_glyph :: + * Slot for bitmap to be merged into. The underlying bitmap may get + * reallocated. + * + * new_glyph :: + * Slot to be incooperated into `base_glyph`. + * + * @return: + * FreeType error code. 0 means success. Returns an error if + * color_index is invalid or reallocation fails. + */ + typedef FT_Error + (*TT_Blend_Colr_Func)( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot base_glyph, + FT_GlyphSlot new_glyph ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Name_Func + * + * @description: + * From the 'name' table, return a given ENGLISH name record in ASCII. + * + * @input: + * face :: + * A handle to the source face object. + * + * nameid :: + * The name id of the name record to return. + * + * @inout: + * name :: + * The address of an allocated string pointer. `NULL` if no name is + * present. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Get_Name_Func)( TT_Face face, + FT_UShort nameid, + FT_String** name ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Name_ID_Func + * + * @description: + * Search whether an ENGLISH version for a given name ID is in the 'name' + * table. + * + * @input: + * face :: + * A handle to the source face object. + * + * nameid :: + * The name id of the name record to return. + * + * @output: + * win :: + * If non-negative, an index into the 'name' table with the + * corresponding (3,1) or (3,0) Windows entry. + * + * apple :: + * If non-negative, an index into the 'name' table with the + * corresponding (1,0) Apple entry. + * + * @return: + * 1 if there is either a win or apple entry (or both), 0 otheriwse. + */ + typedef FT_Bool + (*TT_Get_Name_ID_Func)( TT_Face face, + FT_UShort nameid, + FT_Int *win, + FT_Int *apple ); + + + /************************************************************************** + * + * @functype: + * TT_Load_Table_Func + * + * @description: + * Load a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The function uses `face->goto_table` to seek the stream to the start + * of the table, except while loading the font directory. + */ + typedef FT_Error + (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); + + + /************************************************************************** + * + * @functype: + * TT_Free_Table_Func + * + * @description: + * Free a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + */ + typedef void + (*TT_Free_Table_Func)( TT_Face face ); + + + /* + * @functype: + * TT_Face_GetKerningFunc + * + * @description: + * Return the horizontal kerning value between two glyphs. + * + * @input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The left glyph index. + * + * right_glyph :: + * The right glyph index. + * + * @return: + * The kerning value in font units. + */ + typedef FT_Int + (*TT_Face_GetKerningFunc)( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + + + /************************************************************************** + * + * @struct: + * SFNT_Interface + * + * @description: + * This structure holds pointers to the functions used to load and free + * the basic tables that are required in a 'sfnt' font file. + * + * @fields: + * Check the various xxx_Func() descriptions for details. + */ + typedef struct SFNT_Interface_ + { + TT_Loader_GotoTableFunc goto_table; + + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; + + TT_Load_Any_Func load_any; + + /* these functions are called by `load_face' but they can also */ + /* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; + + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; + + /* this field was called `load_kerning' up to version 2.1.10 */ + TT_Load_Table_Func load_kern; + + TT_Load_Table_Func load_gpos; + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; + + /* see `ttload.h'; this field was called `load_bitmap_header' up to */ + /* version 2.1.10 */ + TT_Load_Table_Func load_bhed; + + TT_Load_SBit_Image_Func load_sbit_image; + + /* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; + + /* starting here, the structure differs from version 2.1.7 */ + + /* this field was introduced in version 2.1.8, named `get_psname' */ + TT_Face_GetKerningFunc get_kerning; + + /* new elements introduced after version 2.1.10 */ + + TT_Face_GetKerningFunc get_gpos_kerning; + + /* load the font directory, i.e., the offset table and */ + /* the table directory */ + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; + + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; + + TT_Set_SBit_Strike_Func set_sbit_strike; + TT_Load_Strike_Metrics_Func load_strike_metrics; + + TT_Load_Table_Func load_cpal; + TT_Load_Table_Func load_colr; + TT_Free_Table_Func free_cpal; + TT_Free_Table_Func free_colr; + TT_Set_Palette_Func set_palette; + TT_Get_Colr_Layer_Func get_colr_layer; + TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint; + TT_Get_Color_Glyph_ClipBox_Func get_color_glyph_clipbox; + TT_Get_Paint_Layers_Func get_paint_layers; + TT_Get_Colorline_Stops_Func get_colorline_stops; + TT_Get_Paint_Func get_paint; + TT_Blend_Colr_Func colr_blend; + + TT_Get_Metrics_Func get_metrics; + + TT_Get_Name_Func get_name; + TT_Get_Name_ID_Func get_name_id; + + /* OpenType SVG Support */ + TT_Load_Table_Func load_svg; + TT_Free_Table_Func free_svg; + TT_Load_Svg_Doc_Func load_svg_doc; + + } SFNT_Interface; + + + /* transitional */ + typedef SFNT_Interface* SFNT_Service; + + +#define FT_DEFINE_SFNT_INTERFACE( \ + class_, \ + goto_table_, \ + init_face_, \ + load_face_, \ + done_face_, \ + get_interface_, \ + load_any_, \ + load_head_, \ + load_hhea_, \ + load_cmap_, \ + load_maxp_, \ + load_os2_, \ + load_post_, \ + load_name_, \ + free_name_, \ + load_kern_, \ + load_gpos_, \ + load_gasp_, \ + load_pclt_, \ + load_bhed_, \ + load_sbit_image_, \ + get_psname_, \ + free_psnames_, \ + get_kerning_, \ + get_gpos_kerning_, \ + load_font_dir_, \ + load_hmtx_, \ + load_eblc_, \ + free_eblc_, \ + set_sbit_strike_, \ + load_strike_metrics_, \ + load_cpal_, \ + load_colr_, \ + free_cpal_, \ + free_colr_, \ + set_palette_, \ + get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ + colr_blend_, \ + get_metrics_, \ + get_name_, \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ ) \ + static const SFNT_Interface class_ = \ + { \ + goto_table_, \ + init_face_, \ + load_face_, \ + done_face_, \ + get_interface_, \ + load_any_, \ + load_head_, \ + load_hhea_, \ + load_cmap_, \ + load_maxp_, \ + load_os2_, \ + load_post_, \ + load_name_, \ + free_name_, \ + load_kern_, \ + load_gpos_, \ + load_gasp_, \ + load_pclt_, \ + load_bhed_, \ + load_sbit_image_, \ + get_psname_, \ + free_psnames_, \ + get_kerning_, \ + get_gpos_kerning_, \ + load_font_dir_, \ + load_hmtx_, \ + load_eblc_, \ + free_eblc_, \ + set_sbit_strike_, \ + load_strike_metrics_, \ + load_cpal_, \ + load_colr_, \ + free_cpal_, \ + free_colr_, \ + set_palette_, \ + get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ + colr_blend_, \ + get_metrics_, \ + get_name_, \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ \ + }; + + +FT_END_HEADER + +#endif /* SFNT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/svginterface.h b/Dependencies/freetype/freetype/include/freetype/internal/svginterface.h new file mode 100644 index 00000000..68c99efb --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/svginterface.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * svginterface.h + * + * Interface of ot-svg module (specification only). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVGINTERFACE_H_ +#define SVGINTERFACE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + typedef FT_Error + (*Preset_Bitmap_Func)( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ); + + typedef struct SVG_Interface_ + { + Preset_Bitmap_Func preset_slot; + + } SVG_Interface; + + typedef SVG_Interface* SVG_Service; + +FT_END_HEADER + +#endif /* SVGINTERFACE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/t1types.h b/Dependencies/freetype/freetype/include/freetype/internal/t1types.h new file mode 100644 index 00000000..1821ae5c --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/t1types.h @@ -0,0 +1,307 @@ +/**************************************************************************** + * + * t1types.h + * + * Basic Type1/Type2 type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1TYPES_H_ +#define T1TYPES_H_ + + +#include +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * T1_EncodingRec + * + * @description: + * A structure modeling a custom encoding. + * + * @fields: + * num_chars :: + * The number of character codes in the encoding. Usually 256. + * + * code_first :: + * The lowest valid character code in the encoding. + * + * code_last :: + * The highest valid character code in the encoding + 1. When equal to + * code_first there are no valid character codes. + * + * char_index :: + * An array of corresponding glyph indices. + * + * char_name :: + * An array of corresponding glyph names. + */ + typedef struct T1_EncodingRecRec_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + + FT_UShort* char_index; + const FT_String** char_name; + + } T1_EncodingRec, *T1_Encoding; + + + /* used to hold extra data of PS_FontInfoRec that + * cannot be stored in the publicly defined structure. + * + * Note these can't be blended with multiple-masters. + */ + typedef struct PS_FontExtraRec_ + { + FT_UShort fs_type; + + } PS_FontExtraRec; + + + typedef struct T1_FontRec_ + { + PS_FontInfoRec font_info; /* font info dictionary */ + PS_FontExtraRec font_extra; /* font info extra fields */ + PS_PrivateRec private_dict; /* private dictionary */ + FT_String* font_name; /* top-level dictionary */ + + T1_EncodingType encoding_type; + T1_EncodingRec encoding; + + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + + FT_Int num_subrs; + FT_Byte** subrs; + FT_UInt* subrs_len; + FT_Hash subrs_hash; + + FT_Int num_glyphs; + FT_String** glyph_names; /* array of glyph names */ + FT_Byte** charstrings; /* array of glyph charstrings */ + FT_UInt* charstrings_len; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_BBox font_bbox; + FT_Long font_id; + + FT_Fixed stroke_width; + + } T1_FontRec, *T1_Font; + + + typedef struct CID_SubrsRec_ + { + FT_Int num_subrs; + FT_Byte** code; + + } CID_SubrsRec, *CID_Subrs; + + + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backward compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backward compatible definition */ + typedef PS_BlendRec T1_Blend; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** AFM FONT INFORMATION STRUCTURES ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AFM_TrackKernRec_ + { + FT_Int degree; + FT_Fixed min_ptsize; + FT_Fixed min_kern; + FT_Fixed max_ptsize; + FT_Fixed max_kern; + + } AFM_TrackKernRec, *AFM_TrackKern; + + typedef struct AFM_KernPairRec_ + { + FT_UInt index1; + FT_UInt index2; + FT_Int x; + FT_Int y; + + } AFM_KernPairRec, *AFM_KernPair; + + typedef struct AFM_FontInfoRec_ + { + FT_Bool IsCIDFont; + FT_BBox FontBBox; + FT_Fixed Ascender; /* optional, mind the zero */ + FT_Fixed Descender; /* optional, mind the zero */ + AFM_TrackKern TrackKerns; /* free if non-NULL */ + FT_UInt NumTrackKern; + AFM_KernPair KernPairs; /* free if non-NULL */ + FT_UInt NumKernPair; + + } AFM_FontInfoRec, *AFM_FontInfo; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL T1_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + + + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + + /* support for Multiple Masters fonts */ + PS_Blend blend; + + /* undocumented, optional: indices of subroutines that express */ + /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ + /* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; + + /* undocumented, optional: has the same meaning as len_buildchar */ + /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + FT_Long* buildchar; + + /* since version 2.1 - interface to PostScript hinter */ + const void* pshinter; + + } T1_FaceRec; + + + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + void* psaux; + CID_FaceInfoRec cid; + PS_FontExtraRec font_extra; +#if 0 + void* afm_data; +#endif + CID_Subrs subrs; + + /* since version 2.1 - interface to PostScript hinter */ + void* pshinter; + + /* since version 2.1.8, but was originally positioned after `afm_data' */ + FT_Byte* binary_data; /* used if hex data has been converted */ + FT_Stream cid_stream; + + } CID_FaceRec; + + +FT_END_HEADER + +#endif /* T1TYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/tttypes.h b/Dependencies/freetype/freetype/include/freetype/internal/tttypes.h new file mode 100644 index 00000000..7053e656 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/tttypes.h @@ -0,0 +1,1747 @@ +/**************************************************************************** + * + * tttypes.h + * + * Basic SFNT/TrueType type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTTYPES_H_ +#define TTTYPES_H_ + + +#include +#include +#include +#include "freetype/fttypes.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TTC_HeaderRec + * + * @description: + * TrueType collection header. This table contains the offsets of the + * font headers of each distinct TrueType face in the file. + * + * @fields: + * tag :: + * Must be 'ttc~' to indicate a TrueType collection. + * + * version :: + * The version number. + * + * count :: + * The number of faces in the collection. The specification says this + * should be an unsigned long, but we use a signed long since we need + * the value -1 for specific purposes. + * + * offsets :: + * The offsets of the font headers, one per face. + */ + typedef struct TTC_HeaderRec_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + + } TTC_HeaderRec; + + + /************************************************************************** + * + * @struct: + * SFNT_HeaderRec + * + * @description: + * SFNT file format header. + * + * @fields: + * format_tag :: + * The font format tag. + * + * num_tables :: + * The number of tables in file. + * + * search_range :: + * Must be '16 * (max power of 2 <= num_tables)'. + * + * entry_selector :: + * Must be log2 of 'search_range / 16'. + * + * range_shift :: + * Must be 'num_tables * 16 - search_range'. + */ + typedef struct SFNT_HeaderRec_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; + + FT_ULong offset; /* not in file */ + + } SFNT_HeaderRec, *SFNT_Header; + + + /************************************************************************** + * + * @struct: + * TT_TableRec + * + * @description: + * This structure describes a given table of a TrueType font. + * + * @fields: + * Tag :: + * A four-bytes tag describing the table. + * + * CheckSum :: + * The table checksum. This value can be ignored. + * + * Offset :: + * The offset of the table from the start of the TrueType font in its + * resource. + * + * Length :: + * The table length (in bytes). + */ + typedef struct TT_TableRec_ + { + FT_ULong Tag; /* table type */ + FT_ULong CheckSum; /* table checksum */ + FT_ULong Offset; /* table file offset */ + FT_ULong Length; /* table length */ + + } TT_TableRec, *TT_Table; + + + /************************************************************************** + * + * @struct: + * TT_LongMetricsRec + * + * @description: + * A structure modeling the long metrics of the 'hmtx' and 'vmtx' + * TrueType tables. The values are expressed in font units. + * + * @fields: + * advance :: + * The advance width or height for the glyph. + * + * bearing :: + * The left-side or top-side bearing for the glyph. + */ + typedef struct TT_LongMetricsRec_ + { + FT_UShort advance; + FT_Short bearing; + + } TT_LongMetricsRec, *TT_LongMetrics; + + + /************************************************************************** + * + * @type: + * TT_ShortMetrics + * + * @description: + * A simple type to model the short metrics of the 'hmtx' and 'vmtx' + * tables. + */ + typedef FT_Short TT_ShortMetrics; + + + /************************************************************************** + * + * @struct: + * TT_NameRec + * + * @description: + * A structure modeling TrueType name records. Name records are used to + * store important strings like family name, style name, copyright, + * etc. in _localized_ versions (i.e., language, encoding, etc). + * + * @fields: + * platformID :: + * The ID of the name's encoding platform. + * + * encodingID :: + * The platform-specific ID for the name's encoding. + * + * languageID :: + * The platform-specific ID for the name's language. + * + * nameID :: + * The ID specifying what kind of name this is. + * + * stringLength :: + * The length of the string in bytes. + * + * stringOffset :: + * The offset to the string in the 'name' table. + * + * string :: + * A pointer to the string's bytes. Note that these are usually UTF-16 + * encoded characters. + */ + typedef struct TT_NameRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_NameRec, *TT_Name; + + + /************************************************************************** + * + * @struct: + * TT_LangTagRec + * + * @description: + * A structure modeling language tag records in SFNT 'name' tables, + * introduced in OpenType version 1.6. + * + * @fields: + * stringLength :: + * The length of the string in bytes. + * + * stringOffset :: + * The offset to the string in the 'name' table. + * + * string :: + * A pointer to the string's bytes. Note that these are UTF-16BE + * encoded characters. + */ + typedef struct TT_LangTagRec_ + { + FT_UShort stringLength; + FT_ULong stringOffset; + + /* this last field is not defined in the spec */ + /* but used by the FreeType engine */ + + FT_Byte* string; + + } TT_LangTagRec, *TT_LangTag; + + + /************************************************************************** + * + * @struct: + * TT_NameTableRec + * + * @description: + * A structure modeling the TrueType name table. + * + * @fields: + * format :: + * The format of the name table. + * + * numNameRecords :: + * The number of names in table. + * + * storageOffset :: + * The offset of the name table in the 'name' TrueType table. + * + * names :: + * An array of name records. + * + * numLangTagRecords :: + * The number of language tags in table. + * + * langTags :: + * An array of language tag records. + * + * stream :: + * The file's input stream. + */ + typedef struct TT_NameTableRec_ + { + FT_UShort format; + FT_UInt numNameRecords; + FT_UInt storageOffset; + TT_NameRec* names; + FT_UInt numLangTagRecords; + TT_LangTagRec* langTags; + FT_Stream stream; + + } TT_NameTableRec, *TT_NameTable; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_GaspRangeRec + * + * @description: + * A tiny structure used to model a gasp range according to the TrueType + * specification. + * + * @fields: + * maxPPEM :: + * The maximum ppem value to which `gaspFlag` applies. + * + * gaspFlag :: + * A flag describing the grid-fitting and anti-aliasing modes to be + * used. + */ + typedef struct TT_GaspRangeRec_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + + } TT_GaspRangeRec, *TT_GaspRange; + + +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 + + + /************************************************************************** + * + * @struct: + * TT_GaspRec + * + * @description: + * A structure modeling the TrueType 'gasp' table used to specify + * grid-fitting and anti-aliasing behaviour. + * + * @fields: + * version :: + * The version number. + * + * numRanges :: + * The number of gasp ranges in table. + * + * gaspRanges :: + * An array of gasp ranges. + */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange gaspRanges; + + } TT_GaspRec; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BITMAPS SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_SBit_MetricsRec + * + * @description: + * A structure used to hold the big metrics of a given glyph bitmap in a + * TrueType or OpenType font. These are usually found in the 'EBDT' + * (Microsoft) or 'bloc' (Apple) table. + * + * @fields: + * height :: + * The glyph height in pixels. + * + * width :: + * The glyph width in pixels. + * + * horiBearingX :: + * The horizontal left bearing. + * + * horiBearingY :: + * The horizontal top bearing. + * + * horiAdvance :: + * The horizontal advance. + * + * vertBearingX :: + * The vertical left bearing. + * + * vertBearingY :: + * The vertical top bearing. + * + * vertAdvance :: + * The vertical advance. + */ + typedef struct TT_SBit_MetricsRec_ + { + FT_UShort height; + FT_UShort width; + + FT_Short horiBearingX; + FT_Short horiBearingY; + FT_UShort horiAdvance; + + FT_Short vertBearingX; + FT_Short vertBearingY; + FT_UShort vertAdvance; + + } TT_SBit_MetricsRec, *TT_SBit_Metrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_SmallMetricsRec + * + * @description: + * A structure used to hold the small metrics of a given glyph bitmap in + * a TrueType or OpenType font. These are usually found in the 'EBDT' + * (Microsoft) or the 'bdat' (Apple) table. + * + * @fields: + * height :: + * The glyph height in pixels. + * + * width :: + * The glyph width in pixels. + * + * bearingX :: + * The left-side bearing. + * + * bearingY :: + * The top-side bearing. + * + * advance :: + * The advance width or height. + */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + + } TT_SBit_SmallMetricsRec, *TT_SBit_SmallMetrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_LineMetricsRec + * + * @description: + * A structure used to describe the text line metrics of a given bitmap + * strike, for either a horizontal or vertical layout. + * + * @fields: + * ascender :: + * The ascender in pixels. + * + * descender :: + * The descender in pixels. + * + * max_width :: + * The maximum glyph width in pixels. + * + * caret_slope_enumerator :: + * Rise of the caret slope, typically set to 1 for non-italic fonts. + * + * caret_slope_denominator :: + * Rise of the caret slope, typically set to 0 for non-italic fonts. + * + * caret_offset :: + * Offset in pixels to move the caret for proper positioning. + * + * min_origin_SB :: + * Minimum of horiBearingX (resp. vertBearingY). + * min_advance_SB :: + * Minimum of + * + * horizontal advance - ( horiBearingX + width ) + * + * resp. + * + * vertical advance - ( vertBearingY + height ) + * + * max_before_BL :: + * Maximum of horiBearingY (resp. vertBearingY). + * + * min_after_BL :: + * Minimum of + * + * horiBearingY - height + * + * resp. + * + * vertBearingX - width + * + * pads :: + * Unused (to make the size of the record a multiple of 32 bits. + */ + typedef struct TT_SBit_LineMetricsRec_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + + } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; + + + /************************************************************************** + * + * @struct: + * TT_SBit_RangeRec + * + * @description: + * A TrueType/OpenType subIndexTable as defined in the 'EBLC' (Microsoft) + * or 'bloc' (Apple) tables. + * + * @fields: + * first_glyph :: + * The first glyph index in the range. + * + * last_glyph :: + * The last glyph index in the range. + * + * index_format :: + * The format of index table. Valid values are 1 to 5. + * + * image_format :: + * The format of 'EBDT' image data. + * + * image_offset :: + * The offset to image data in 'EBDT'. + * + * image_size :: + * For index formats 2 and 5. This is the size in bytes of each glyph + * bitmap. + * + * big_metrics :: + * For index formats 2 and 5. This is the big metrics for each glyph + * bitmap. + * + * num_glyphs :: + * For index formats 4 and 5. This is the number of glyphs in the code + * array. + * + * glyph_offsets :: + * For index formats 1 and 3. + * + * glyph_codes :: + * For index formats 4 and 5. + * + * table_offset :: + * The offset of the index table in the 'EBLC' table. Only used during + * strike loading. + */ + typedef struct TT_SBit_RangeRec_ + { + FT_UShort first_glyph; + FT_UShort last_glyph; + + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + + FT_ULong image_size; + TT_SBit_MetricsRec metrics; + FT_ULong num_glyphs; + + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + + FT_ULong table_offset; + + } TT_SBit_RangeRec, *TT_SBit_Range; + + + /************************************************************************** + * + * @struct: + * TT_SBit_StrikeRec + * + * @description: + * A structure used describe a given bitmap strike in the 'EBLC' + * (Microsoft) or 'bloc' (Apple) tables. + * + * @fields: + * num_index_ranges :: + * The number of index ranges. + * + * index_ranges :: + * An array of glyph index ranges. + * + * color_ref :: + * Unused. `color_ref` is put in for future enhancements, but these + * fields are already in use by other platforms (e.g. Newton). For + * details, please see + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bloc.html + * + * hori :: + * The line metrics for horizontal layouts. + * + * vert :: + * The line metrics for vertical layouts. + * + * start_glyph :: + * The lowest glyph index for this strike. + * + * end_glyph :: + * The highest glyph index for this strike. + * + * x_ppem :: + * The number of horizontal pixels per EM. + * + * y_ppem :: + * The number of vertical pixels per EM. + * + * bit_depth :: + * The bit depth. Valid values are 1, 2, 4, and 8. + * + * flags :: + * Is this a vertical or horizontal strike? For details, please see + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bloc.html + */ + typedef struct TT_SBit_StrikeRec_ + { + FT_Int num_ranges; + TT_SBit_Range sbit_ranges; + FT_ULong ranges_offset; + + FT_ULong color_ref; + + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_UShort start_glyph; + FT_UShort end_glyph; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte bit_depth; + FT_Char flags; + + } TT_SBit_StrikeRec, *TT_SBit_Strike; + + + /************************************************************************** + * + * @struct: + * TT_SBit_ComponentRec + * + * @description: + * A simple structure to describe a compound sbit element. + * + * @fields: + * glyph_code :: + * The element's glyph index. + * + * x_offset :: + * The element's left bearing. + * + * y_offset :: + * The element's top bearing. + */ + typedef struct TT_SBit_ComponentRec_ + { + FT_UShort glyph_code; + FT_Char x_offset; + FT_Char y_offset; + + } TT_SBit_ComponentRec, *TT_SBit_Component; + + + /************************************************************************** + * + * @struct: + * TT_SBit_ScaleRec + * + * @description: + * A structure used describe a given bitmap scaling table, as defined in + * the 'EBSC' table. + * + * @fields: + * hori :: + * The horizontal line metrics. + * + * vert :: + * The vertical line metrics. + * + * x_ppem :: + * The number of horizontal pixels per EM. + * + * y_ppem :: + * The number of vertical pixels per EM. + * + * x_ppem_substitute :: + * Substitution x_ppem value. + * + * y_ppem_substitute :: + * Substitution y_ppem value. + */ + typedef struct TT_SBit_ScaleRec_ + { + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + + FT_Byte x_ppem; + FT_Byte y_ppem; + + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + + } TT_SBit_ScaleRec, *TT_SBit_Scale; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @struct: + * TT_Post_NamesRec + * + * @description: + * Postscript names table, either format 2.0 or 2.5. + * + * @fields: + * loaded :: + * A flag to indicate whether the PS names are loaded. + * + * num_glyphs :: + * The number of named glyphs in the table. + * + * num_names :: + * The number of PS names stored in the table. + * + * glyph_indices :: + * The indices of the glyphs in the names arrays. + * + * glyph_names :: + * The PS names not in Mac Encoding. + */ + typedef struct TT_Post_NamesRec_ + { + FT_Bool loaded; + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Byte** glyph_names; + + } TT_Post_NamesRec, *TT_Post_Names; + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** GX VARIATION TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + typedef struct GX_BlendRec_ *GX_Blend; +#endif + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** EMBEDDED BDF PROPERTIES TABLE SUPPORT ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * These types are used to support a `BDF ' table that isn't part of the + * official TrueType specification. It is mainly used in SFNT-based bitmap + * fonts that were generated from a set of BDF fonts. + * + * The format of the table is as follows. + * + * USHORT version `BDF ' table version number, should be 0x0001. USHORT + * strikeCount Number of strikes (bitmap sizes) in this table. ULONG + * stringTable Offset (from start of BDF table) to string + * table. + * + * This is followed by an array of `strikeCount' descriptors, having the + * following format. + * + * USHORT ppem Vertical pixels per EM for this strike. USHORT numItems + * Number of items for this strike (properties and + * atoms). Maximum is 255. + * + * This array in turn is followed by `strikeCount' value sets. Each `value + * set' is an array of `numItems' items with the following format. + * + * ULONG item_name Offset in string table to item name. + * USHORT item_type The item type. Possible values are + * 0 => string (e.g., COMMENT) + * 1 => atom (e.g., FONT or even SIZE) + * 2 => int32 + * 3 => uint32 + * 0x10 => A flag to indicate a properties. This + * is ORed with the above values. + * ULONG item_value For strings => Offset into string table without + * the corresponding double quotes. + * For atoms => Offset into string table. + * For integers => Direct value. + * + * All strings in the string table consist of bytes and are + * zero-terminated. + * + */ + +#ifdef TT_CONFIG_OPTION_BDF + + typedef struct TT_BDFRec_ + { + FT_Byte* table; + FT_Byte* table_end; + FT_Byte* strings; + FT_ULong strings_size; + FT_UInt num_strikes; + FT_Bool loaded; + + } TT_BDFRec, *TT_BDF; + +#endif /* TT_CONFIG_OPTION_BDF */ + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** ***/ + /*** ORIGINAL TT_FACE CLASS DEFINITION ***/ + /*** ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * This structure/class is defined here because it is common to the + * following formats: TTF, OpenType-TT, and OpenType-CFF. + * + * Note, however, that the classes TT_Size and TT_GlyphSlot are not shared + * between font drivers, and are thus defined in `ttobjs.h`. + * + */ + + + /************************************************************************** + * + * @type: + * TT_Face + * + * @description: + * A handle to a TrueType face/font object. A TT_Face encapsulates the + * resolution and scaling independent parts of a TrueType font resource. + * + * @note: + * The TT_Face structure is also used as a 'parent class' for the + * OpenType-CFF class (T2_Face). + */ + typedef struct TT_FaceRec_* TT_Face; + + + /* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error + (*TT_Interpreter)( void* exec_context ); + + /* forward declaration */ + typedef struct TT_LoaderRec_* TT_Loader; + + + /************************************************************************** + * + * @functype: + * TT_Loader_GotoTableFunc + * + * @description: + * Seeks a stream to the start of a given TrueType table. + * + * @input: + * face :: + * A handle to the target face object. + * + * tag :: + * A 4-byte tag used to name the table. + * + * stream :: + * The input stream. + * + * @output: + * length :: + * The length of the table in bytes. Set to 0 if not needed. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The stream cursor must be at the font file's origin. + */ + typedef FT_Error + (*TT_Loader_GotoTableFunc)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_StartGlyphFunc + * + * @description: + * Seeks a stream to the start of a given glyph element, and opens a + * frame for it. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + * + * glyph index :: The index of the glyph to access. + * + * offset :: + * The offset of the glyph according to the 'locations' table. + * + * byte_count :: + * The size of the frame in bytes. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function is normally equivalent to FT_STREAM_SEEK(offset) + * followed by FT_FRAME_ENTER(byte_count) with the loader's stream, but + * alternative formats (e.g. compressed ones) might use something + * different. + */ + typedef FT_Error + (*TT_Loader_StartGlyphFunc)( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_ReadGlyphFunc + * + * @description: + * Reads one glyph element (its header, a simple glyph, or a composite) + * from the loader's current stream frame. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); + + + /************************************************************************** + * + * @functype: + * TT_Loader_EndGlyphFunc + * + * @description: + * Closes the current loader stream frame for the glyph. + * + * @input: + * loader :: + * The current TrueType glyph loader object. + */ + typedef void + (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); + + + typedef enum TT_SbitTableType_ + { + TT_SBIT_TABLE_TYPE_NONE = 0, + TT_SBIT_TABLE_TYPE_EBLC, /* `EBLC' (Microsoft), */ + /* `bloc' (Apple) */ + TT_SBIT_TABLE_TYPE_CBLC, /* `CBLC' (Google) */ + TT_SBIT_TABLE_TYPE_SBIX, /* `sbix' (Apple) */ + + /* do not remove */ + TT_SBIT_TABLE_TYPE_MAX + + } TT_SbitTableType; + + + /* OpenType 1.8 brings new tables for variation font support; */ + /* to make the old MM and GX fonts still work we need to check */ + /* the presence (and validity) of the functionality provided */ + /* by those tables. The following flag macros are for the */ + /* field `variation_support'. */ + /* */ + /* Note that `fvar' gets checked immediately at font loading, */ + /* while the other features are only loaded if MM support is */ + /* actually requested. */ + + /* FVAR */ +#define TT_FACE_FLAG_VAR_FVAR ( 1 << 0 ) + + /* HVAR */ +#define TT_FACE_FLAG_VAR_HADVANCE ( 1 << 1 ) +#define TT_FACE_FLAG_VAR_LSB ( 1 << 2 ) +#define TT_FACE_FLAG_VAR_RSB ( 1 << 3 ) + + /* VVAR */ +#define TT_FACE_FLAG_VAR_VADVANCE ( 1 << 4 ) +#define TT_FACE_FLAG_VAR_TSB ( 1 << 5 ) +#define TT_FACE_FLAG_VAR_BSB ( 1 << 6 ) +#define TT_FACE_FLAG_VAR_VORG ( 1 << 7 ) + + /* MVAR */ +#define TT_FACE_FLAG_VAR_MVAR ( 1 << 8 ) + + + /************************************************************************** + * + * TrueType Face Type + * + * @struct: + * TT_Face + * + * @description: + * The TrueType face class. These objects model the resolution and + * point-size independent data found in a TrueType font file. + * + * @fields: + * root :: + * The base FT_Face structure, managed by the base layer. + * + * ttc_header :: + * The TrueType collection header, used when the file is a 'ttc' rather + * than a 'ttf'. For ordinary font files, the field `ttc_header.count` + * is set to 0. + * + * format_tag :: + * The font format tag. + * + * num_tables :: + * The number of TrueType tables in this font file. + * + * dir_tables :: + * The directory of TrueType tables for this font file. + * + * header :: + * The font's font header ('head' table). Read on font opening. + * + * horizontal :: + * The font's horizontal header ('hhea' table). This field also + * contains the associated horizontal metrics table ('hmtx'). + * + * max_profile :: + * The font's maximum profile table. Read on font opening. Note that + * some maximum values cannot be taken directly from this table. We + * thus define additional fields below to hold the computed maxima. + * + * vertical_info :: + * A boolean which is set when the font file contains vertical metrics. + * If not, the value of the 'vertical' field is undefined. + * + * vertical :: + * The font's vertical header ('vhea' table). This field also contains + * the associated vertical metrics table ('vmtx'), if found. + * IMPORTANT: The contents of this field is undefined if the + * `vertical_info` field is unset. + * + * num_names :: + * The number of name records within this TrueType font. + * + * name_table :: + * The table of name records ('name'). + * + * os2 :: + * The font's OS/2 table ('OS/2'). + * + * postscript :: + * The font's PostScript table ('post' table). The PostScript glyph + * names are not loaded by the driver on face opening. See the + * 'ttpost' module for more details. + * + * cmap_table :: + * Address of the face's 'cmap' SFNT table in memory (it's an extracted + * frame). + * + * cmap_size :: + * The size in bytes of the `cmap_table` described above. + * + * goto_table :: + * A function called by each TrueType table loader to position a + * stream's cursor to the start of a given table according to its tag. + * It defaults to TT_Goto_Face but can be different for strange formats + * (e.g. Type 42). + * + * access_glyph_frame :: + * A function used to access the frame of a given glyph within the + * face's font file. + * + * forget_glyph_frame :: + * A function used to forget the frame of a given glyph when all data + * has been loaded. + * + * read_glyph_header :: + * A function used to read a glyph header. It must be called between + * an 'access' and 'forget'. + * + * read_simple_glyph :: + * A function used to read a simple glyph. It must be called after the + * header was read, and before the 'forget'. + * + * read_composite_glyph :: + * A function used to read a composite glyph. It must be called after + * the header was read, and before the 'forget'. + * + * sfnt :: + * A pointer to the SFNT service. + * + * psnames :: + * A pointer to the PostScript names service. + * + * mm :: + * A pointer to the Multiple Masters service. + * + * tt_var :: + * A pointer to the Metrics Variations service for the "truetype" + * driver. + * + * face_var :: + * A pointer to the Metrics Variations service for this `TT_Face`'s + * driver. + * + * psaux :: + * A pointer to the PostScript Auxiliary service. + * + * gasp :: + * The grid-fitting and scaling properties table ('gasp'). This table + * is optional in TrueType/OpenType fonts. + * + * pclt :: + * The 'pclt' SFNT table. + * + * num_sbit_scales :: + * The number of sbit scales for this font. + * + * sbit_scales :: + * Array of sbit scales embedded in this font. This table is optional + * in a TrueType/OpenType font. + * + * postscript_names :: + * A table used to store the Postscript names of the glyphs for this + * font. See the file `ttconfig.h` for comments on the + * TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. + * + * palette_data :: + * Some fields from the 'CPAL' table that are directly indexed. + * + * palette_index :: + * The current palette index, as set by @FT_Palette_Select. + * + * palette :: + * An array containing the current palette's colors. + * + * have_foreground_color :: + * There was a call to @FT_Palette_Set_Foreground_Color. + * + * foreground_color :: + * The current foreground color corresponding to 'CPAL' color index + * 0xFFFF. Only valid if `have_foreground_color` is set. + * + * font_program_size :: + * Size in bytecodes of the face's font program. 0 if none defined. + * Ignored for Type 2 fonts. + * + * font_program :: + * The face's font program (bytecode stream) executed at load time, + * also used during glyph rendering. Comes from the 'fpgm' table. + * Ignored for Type 2 font fonts. + * + * cvt_program_size :: + * The size in bytecodes of the face's cvt program. Ignored for Type 2 + * fonts. + * + * cvt_program :: + * The face's cvt program (bytecode stream) executed each time an + * instance/size is changed/reset. Comes from the 'prep' table. + * Ignored for Type 2 fonts. + * + * cvt_size :: + * Size of the control value table (in entries). Ignored for Type 2 + * fonts. + * + * cvt :: + * The face's original control value table. Coordinates are expressed + * in unscaled font units (in 26.6 format). Comes from the 'cvt~' + * table. Ignored for Type 2 fonts. + * + * If varied by the `CVAR' table, non-integer values are possible. + * + * interpreter :: + * A pointer to the TrueType bytecode interpreters field is also used + * to hook the debugger in 'ttdebug'. + * + * extra :: + * Reserved for third-party font drivers. + * + * postscript_name :: + * The PS name of the font. Used by the postscript name service. + * + * glyf_len :: + * The length of the 'glyf' table. Needed for malformed 'loca' tables. + * + * glyf_offset :: + * The file offset of the 'glyf' table. + * + * is_cff2 :: + * Set if the font format is CFF2. + * + * doblend :: + * A boolean which is set if the font should be blended (this is for GX + * var). + * + * blend :: + * Contains the data needed to control GX variation tables (rather like + * Multiple Master data). + * + * variation_support :: + * Flags that indicate which OpenType functionality related to font + * variation support is present, valid, and usable. For example, + * TT_FACE_FLAG_VAR_FVAR is only set if we have at least one design + * axis. + * + * var_postscript_prefix :: + * The PostScript name prefix needed for constructing a variation font + * instance's PS name . + * + * var_postscript_prefix_len :: + * The length of the `var_postscript_prefix` string. + * + * var_default_named_instance :: + * The index of the default named instance. + * + * non_var_style_name :: + * The non-variation style name, used as a backup. + * + * horz_metrics_size :: + * The size of the 'hmtx' table. + * + * vert_metrics_size :: + * The size of the 'vmtx' table. + * + * num_locations :: + * The number of glyph locations in this TrueType file. This should be + * one more than the number of glyphs. Ignored for Type 2 fonts. + * + * glyph_locations :: + * An array of longs. These are offsets to glyph data within the + * 'glyf' table. Ignored for Type 2 font faces. + * + * hdmx_table :: + * A pointer to the 'hdmx' table. + * + * hdmx_table_size :: + * The size of the 'hdmx' table. + * + * hdmx_record_count :: + * The number of hdmx records. + * + * hdmx_record_size :: + * The size of a single hdmx record. + * + * hdmx_records :: + * A array of pointers to the 'hdmx' table records sorted by ppem. + * + * sbit_table :: + * A pointer to the font's embedded bitmap location table. + * + * sbit_table_size :: + * The size of `sbit_table`. + * + * sbit_table_type :: + * The sbit table type (CBLC, sbix, etc.). + * + * sbit_num_strikes :: + * The number of sbit strikes exposed by FreeType's API, omitting + * invalid strikes. + * + * sbit_strike_map :: + * A mapping between the strike indices exposed by the API and the + * indices used in the font's sbit table. + * + * kern_table :: + * A pointer to the 'kern' table. + * + * kern_table_size :: + * The size of the 'kern' table. + * + * num_kern_tables :: + * The number of supported kern subtables (up to 32; FreeType + * recognizes only horizontal ones with format 0). + * + * kern_avail_bits :: + * The availability status of kern subtables; if bit n is set, table n + * is available. + * + * kern_order_bits :: + * The sortedness status of kern subtables; if bit n is set, table n is + * sorted. + * + * bdf :: + * Data related to an SFNT font's 'bdf' table; see `tttypes.h`. + * + * horz_metrics_offset :: + * The file offset of the 'hmtx' table. + * + * vert_metrics_offset :: + * The file offset of the 'vmtx' table. + * + * ebdt_start :: + * The file offset of the sbit data table (CBDT, bdat, etc.). + * + * ebdt_size :: + * The size of the sbit data table. + * + * cpal :: + * A pointer to data related to the 'CPAL' table. `NULL` if the table + * is not available. + * + * colr :: + * A pointer to data related to the 'COLR' table. `NULL` if the table + * is not available. + * + * svg :: + * A pointer to data related to the 'SVG' table. `NULL` if the table + * is not available. + */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + + TTC_HeaderRec ttc_header; + + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table dir_tables; + + TT_Header header; /* TrueType header table */ + TT_HoriHeader horizontal; /* TrueType horizontal header */ + + TT_MaxProfile max_profile; + + FT_Bool vertical_info; + TT_VertHeader vertical; /* TT Vertical header, if present */ + + FT_UShort num_names; /* number of name records */ + TT_NameTableRec name_table; /* name table */ + + TT_OS2 os2; /* TrueType OS/2 table */ + TT_Postscript postscript; /* TrueType Postscript table */ + + FT_Byte* cmap_table; /* extracted `cmap' table */ + FT_ULong cmap_size; + + TT_Loader_GotoTableFunc goto_table; + + TT_Loader_StartGlyphFunc access_glyph_frame; + TT_Loader_EndGlyphFunc forget_glyph_frame; + TT_Loader_ReadGlyphFunc read_glyph_header; + TT_Loader_ReadGlyphFunc read_simple_glyph; + TT_Loader_ReadGlyphFunc read_composite_glyph; + + /* a typeless pointer to the SFNT_Interface table used to load */ + /* the basic TrueType tables in the face object */ + void* sfnt; + + /* a typeless pointer to the FT_Service_PsCMapsRec table used to */ + /* handle glyph names <-> unicode & Mac values */ + void* psnames; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* a typeless pointer to the FT_Service_MultiMasters table used to */ + /* handle variation fonts */ + void* mm; + + /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the */ + /* "truetype" driver */ + void* tt_var; + + /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */ + /* TT_Face's driver */ + void* face_var; /* since 2.13.1 */ +#endif + + /* a typeless pointer to the PostScript Aux service */ + void* psaux; + + + /************************************************************************ + * + * Optional TrueType/OpenType tables + * + */ + + /* grid-fitting and scaling table */ + TT_GaspRec gasp; /* the `gasp' table */ + + /* PCL 5 table */ + TT_PCLT pclt; + + /* embedded bitmaps support */ + FT_ULong num_sbit_scales; + TT_SBit_Scale sbit_scales; + + /* postscript names table */ + TT_Post_NamesRec postscript_names; + + /* glyph colors */ + FT_Palette_Data palette_data; /* since 2.10 */ + FT_UShort palette_index; + FT_Color* palette; + FT_Bool have_foreground_color; + FT_Color foreground_color; + + + /************************************************************************ + * + * TrueType-specific fields (ignored by the CFF driver) + * + */ + + /* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; + + /* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; + + /* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Int32* cvt; + + /* A pointer to the bytecode interpreter to use. This is also */ + /* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; + + + /************************************************************************ + * + * Other tables or fields. This is used by derivative formats like + * OpenType. + * + */ + + FT_Generic extra; + + const char* postscript_name; + + FT_ULong glyf_len; + FT_ULong glyf_offset; /* since 2.7.1 */ + + FT_Bool is_cff2; /* since 2.7.1 */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Bool doblend; + GX_Blend blend; + + FT_UInt32 variation_support; /* since 2.7.1 */ + + const char* var_postscript_prefix; /* since 2.7.2 */ + FT_UInt var_postscript_prefix_len; /* since 2.7.2 */ + + FT_UInt var_default_named_instance; /* since 2.13.1 */ + + const char* non_var_style_name; /* since 2.13.1 */ +#endif + + /* since version 2.2 */ + + FT_ULong horz_metrics_size; + FT_ULong vert_metrics_size; + + FT_ULong num_locations; /* up to 0xFFFF + 1 */ + FT_Byte* glyph_locations; + + FT_Byte* hdmx_table; + FT_ULong hdmx_table_size; + FT_UInt hdmx_record_count; + FT_ULong hdmx_record_size; + FT_Byte** hdmx_records; + + FT_Byte* sbit_table; + FT_ULong sbit_table_size; + TT_SbitTableType sbit_table_type; + FT_UInt sbit_num_strikes; + FT_UInt* sbit_strike_map; + + FT_Byte* kern_table; + FT_ULong kern_table_size; + FT_UInt num_kern_tables; + FT_UInt32 kern_avail_bits; + FT_UInt32 kern_order_bits; + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + FT_Byte* gpos_table; + FT_Bool gpos_kerning_available; +#endif + +#ifdef TT_CONFIG_OPTION_BDF + TT_BDFRec bdf; +#endif /* TT_CONFIG_OPTION_BDF */ + + /* since 2.3.0 */ + FT_ULong horz_metrics_offset; + FT_ULong vert_metrics_offset; + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /* since 2.7 */ + FT_ULong ebdt_start; /* either `CBDT', `EBDT', or `bdat' */ + FT_ULong ebdt_size; +#endif + + /* since 2.10 */ + void* cpal; + void* colr; + + /* since 2.12 */ + void* svg; + + } TT_FaceRec; + + + /************************************************************************** + * + * @struct: + * TT_GlyphZoneRec + * + * @description: + * A glyph zone is used to load, scale and hint glyph outline + * coordinates. + * + * @fields: + * memory :: + * A handle to the memory manager. + * + * max_points :: + * The maximum size in points of the zone. + * + * max_contours :: + * Max size in links contours of the zone. + * + * n_points :: + * The current number of points in the zone. + * + * n_contours :: + * The current number of contours in the zone. + * + * org :: + * The original glyph coordinates (font units/scaled). + * + * cur :: + * The current glyph coordinates (scaled/hinted). + * + * tags :: + * The point control tags. + * + * contours :: + * The contours end points. + * + * first_point :: + * Offset of the current subglyph's first point. + */ + typedef struct TT_GlyphZoneRec_ + { + FT_Memory memory; + FT_UShort max_points; + FT_UShort max_contours; + FT_UShort n_points; /* number of points in zone */ + FT_UShort n_contours; /* number of contours */ + + FT_Vector* org; /* original point coordinates */ + FT_Vector* cur; /* current point coordinates */ + FT_Vector* orus; /* original (unscaled) point coordinates */ + + FT_Byte* tags; /* current touch flags */ + FT_UShort* contours; /* contour end points */ + + FT_UShort first_point; /* offset of first (#0) point */ + + } TT_GlyphZoneRec, *TT_GlyphZone; + + + /* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; + + + /************************************************************************** + * + * @type: + * TT_Size + * + * @description: + * A handle to a TrueType size object. + */ + typedef struct TT_SizeRec_* TT_Size; + + + /* glyph loader structure */ + typedef struct TT_LoaderRec_ + { + TT_Face face; + TT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader gloader; + + FT_ULong load_flags; + FT_UInt glyph_index; + + FT_Stream stream; + FT_UInt byte_len; + + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Int linear; + FT_Bool linear_def; + FT_Vector pp1; + FT_Vector pp2; + + /* the zone where we load our glyphs */ + TT_GlyphZoneRec base; + TT_GlyphZoneRec zone; + + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; + + /* for possible extensibility in other formats */ + void* other; + + /* since version 2.1.8 */ + FT_Int top_bearing; + FT_Int vadvance; + FT_Vector pp3; + FT_Vector pp4; + + /* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + + /* since version 2.6.2 */ + FT_ListRec composites; + + /* since version 2.11.2 */ + FT_Byte* widthp; + + } TT_LoaderRec; + + +FT_END_HEADER + +#endif /* TTTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/internal/wofftypes.h b/Dependencies/freetype/freetype/include/freetype/internal/wofftypes.h new file mode 100644 index 00000000..4a169d12 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/internal/wofftypes.h @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * wofftypes.h + * + * Basic WOFF/WOFF2 type definitions and interface (specification + * only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WOFFTYPES_H_ +#define WOFFTYPES_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * WOFF_HeaderRec + * + * @description: + * WOFF file format header. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF/#WOFFHeader + */ + typedef struct WOFF_HeaderRec_ + { + FT_ULong signature; + FT_ULong flavor; + FT_ULong length; + FT_UShort num_tables; + FT_UShort reserved; + FT_ULong totalSfntSize; + FT_UShort majorVersion; + FT_UShort minorVersion; + FT_ULong metaOffset; + FT_ULong metaLength; + FT_ULong metaOrigLength; + FT_ULong privOffset; + FT_ULong privLength; + + } WOFF_HeaderRec, *WOFF_Header; + + + /************************************************************************** + * + * @struct: + * WOFF_TableRec + * + * @description: + * This structure describes a given table of a WOFF font. + * + * @fields: + * Tag :: + * A four-bytes tag describing the table. + * + * Offset :: + * The offset of the table from the start of the WOFF font in its + * resource. + * + * CompLength :: + * Compressed table length (in bytes). + * + * OrigLength :: + * Uncompressed table length (in bytes). + * + * CheckSum :: + * The table checksum. This value can be ignored. + * + * OrigOffset :: + * The uncompressed table file offset. This value gets computed while + * constructing the (uncompressed) SFNT header. It is not contained in + * the WOFF file. + */ + typedef struct WOFF_TableRec_ + { + FT_Tag Tag; /* table ID */ + FT_ULong Offset; /* table file offset */ + FT_ULong CompLength; /* compressed table length */ + FT_ULong OrigLength; /* uncompressed table length */ + FT_ULong CheckSum; /* uncompressed checksum */ + + FT_ULong OrigOffset; /* uncompressed table file offset */ + /* (not in the WOFF file) */ + } WOFF_TableRec, *WOFF_Table; + + + /************************************************************************** + * + * @struct: + * WOFF2_TtcFontRec + * + * @description: + * Metadata for a TTC font entry in WOFF2. + * + * @fields: + * flavor :: + * TTC font flavor. + * + * num_tables :: + * Number of tables in TTC, indicating number of elements in + * `table_indices`. + * + * table_indices :: + * Array of table indices for each TTC font. + */ + typedef struct WOFF2_TtcFontRec_ + { + FT_ULong flavor; + FT_UShort num_tables; + FT_UShort* table_indices; + + } WOFF2_TtcFontRec, *WOFF2_TtcFont; + + + /************************************************************************** + * + * @struct: + * WOFF2_HeaderRec + * + * @description: + * WOFF2 file format header. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#woff20Header + * + * @note: + * We don't care about the fields `reserved`, `majorVersion` and + * `minorVersion`, so they are not included. The `totalSfntSize` field + * does not necessarily represent the actual size of the uncompressed + * SFNT font stream, so that is used as a reference value instead. + */ + typedef struct WOFF2_HeaderRec_ + { + FT_ULong signature; + FT_ULong flavor; + FT_ULong length; + FT_UShort num_tables; + FT_ULong totalSfntSize; + FT_ULong totalCompressedSize; + FT_ULong metaOffset; + FT_ULong metaLength; + FT_ULong metaOrigLength; + FT_ULong privOffset; + FT_ULong privLength; + + FT_ULong uncompressed_size; /* uncompressed brotli stream size */ + FT_ULong compressed_offset; /* compressed stream offset */ + FT_ULong header_version; /* version of original TTC Header */ + FT_UShort num_fonts; /* number of fonts in TTC */ + FT_ULong actual_sfnt_size; /* actual size of sfnt stream */ + + WOFF2_TtcFont ttc_fonts; /* metadata for fonts in a TTC */ + + } WOFF2_HeaderRec, *WOFF2_Header; + + + /************************************************************************** + * + * @struct: + * WOFF2_TableRec + * + * @description: + * This structure describes a given table of a WOFF2 font. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + */ + typedef struct WOFF2_TableRec_ + { + FT_Byte FlagByte; /* table type and flags */ + FT_Tag Tag; /* table file offset */ + FT_ULong dst_length; /* uncompressed table length */ + FT_ULong TransformLength; /* transformed length */ + + FT_ULong flags; /* calculated flags */ + FT_ULong src_offset; /* compressed table offset */ + FT_ULong src_length; /* compressed table length */ + FT_ULong dst_offset; /* uncompressed table offset */ + + } WOFF2_TableRec, *WOFF2_Table; + + + /************************************************************************** + * + * @struct: + * WOFF2_InfoRec + * + * @description: + * Metadata for WOFF2 font that may be required for reconstruction of + * sfnt tables. + * + * @fields: + * header_checksum :: + * Checksum of SFNT offset table. + * + * num_glyphs :: + * Number of glyphs in the font. + * + * num_hmetrics :: + * `numberOfHMetrics` field in the 'hhea' table. + * + * x_mins :: + * `xMin` values of glyph bounding box. + * + * glyf_table :: + * A pointer to the `glyf' table record. + * + * loca_table :: + * A pointer to the `loca' table record. + * + * head_table :: + * A pointer to the `head' table record. + */ + typedef struct WOFF2_InfoRec_ + { + FT_ULong header_checksum; + FT_UShort num_glyphs; + FT_UShort num_hmetrics; + FT_Short* x_mins; + + WOFF2_Table glyf_table; + WOFF2_Table loca_table; + WOFF2_Table head_table; + + } WOFF2_InfoRec, *WOFF2_Info; + + + /************************************************************************** + * + * @struct: + * WOFF2_SubstreamRec + * + * @description: + * This structure stores information about a substream in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * start :: + * Beginning of the substream relative to uncompressed table stream. + * + * offset :: + * Offset of the substream relative to uncompressed table stream. + * + * size :: + * Size of the substream. + */ + typedef struct WOFF2_SubstreamRec_ + { + FT_ULong start; + FT_ULong offset; + FT_ULong size; + + } WOFF2_SubstreamRec, *WOFF2_Substream; + + + /************************************************************************** + * + * @struct: + * WOFF2_PointRec + * + * @description: + * This structure stores information about a point in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * x :: + * x-coordinate of point. + * + * y :: + * y-coordinate of point. + * + * on_curve :: + * Set if point is on-curve. + */ + typedef struct WOFF2_PointRec_ + { + FT_Int x; + FT_Int y; + FT_Bool on_curve; + + } WOFF2_PointRec, *WOFF2_Point; + + +FT_END_HEADER + +#endif /* WOFFTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/otsvg.h b/Dependencies/freetype/freetype/include/freetype/otsvg.h new file mode 100644 index 00000000..9d356938 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/otsvg.h @@ -0,0 +1,336 @@ +/**************************************************************************** + * + * otsvg.h + * + * Interface for OT-SVG support related things (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTSVG_H_ +#define OTSVG_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * svg_fonts + * + * @title: + * OpenType SVG Fonts + * + * @abstract: + * OT-SVG API between FreeType and an external SVG rendering library. + * + * @description: + * This section describes the four hooks necessary to render SVG + * 'documents' that are contained in an OpenType font's 'SVG~' table. + * + * For more information on the implementation, see our standard hooks + * based on 'librsvg' in the [FreeType Demo + * Programs](https://gitlab.freedesktop.org/freetype/freetype-demos) + * repository. + * + */ + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Init_Func + * + * @description: + * A callback that is called when the first OT-SVG glyph is rendered in + * the lifetime of an @FT_Library object. In a typical implementation, + * one would want to allocate a structure and point the `data_pointer` + * to it and perform any library initializations that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Init_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Free_Func + * + * @description: + * A callback that is called when the `ot-svg` module is being freed. + * It is only called if the init hook was called earlier. This means + * that neither the init nor the free hook is called if no OT-SVG glyph + * is rendered. + * + * In a typical implementation, one would want to free any state + * structure that was allocated in the init hook and perform any + * library-related closure that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @since: + * 2.12 + */ + typedef void + (*SVG_Lib_Free_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Render_Func + * + * @description: + * A callback that is called to render an OT-SVG glyph. This callback + * hook is called right after the preset hook @SVG_Lib_Preset_Slot_Func + * has been called with `cache` set to `TRUE`. The data necessary to + * render is available through the handle @FT_SVG_Document, which is set + * in the `other` field of @FT_GlyphSlotRec. + * + * The render hook is expected to render the SVG glyph to the bitmap + * buffer that is allocated already at `slot->bitmap.buffer`. It also + * sets the `num_grays` value as well as `slot->format`. + * + * @input: + * slot :: + * The slot to render. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Render_Func)( FT_GlyphSlot slot, + FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Preset_Slot_Func + * + * @description: + * A callback that is called to preset the glyph slot. It is called from + * two places. + * + * 1. When `FT_Load_Glyph` needs to preset the glyph slot. + * + * 2. Right before the `svg` module calls the render callback hook. + * + * When it is the former, the argument `cache` is set to `FALSE`. When + * it is the latter, the argument `cache` is set to `TRUE`. This + * distinction has been made because many calculations that are necessary + * for presetting a glyph slot are the same needed later for the render + * callback hook. Thus, if `cache` is `TRUE`, the hook can _cache_ those + * calculations in a memory block referenced by the state pointer. + * + * This hook is expected to preset the slot by setting parameters such as + * `bitmap_left`, `bitmap_top`, `width`, `rows`, `pitch`, and + * `pixel_mode`. It is also expected to set all the metrics for the slot + * including the vertical advance if it is not already set. Typically, + * fonts have horizontal advances but not vertical ones. If those are + * available, they had already been set, otherwise they have to be + * estimated and set manually. The hook must take into account the + * transformations that have been set, and translate the transformation + * matrices into the SVG coordinate system, as the original matrix is + * intended for the TTF/CFF coordinate system. + * + * @input: + * slot :: + * The glyph slot that has the SVG document loaded. + * + * cache :: + * See description. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot slot, + FT_Bool cache, + FT_Pointer *state ); + + + /************************************************************************** + * + * @struct: + * SVG_RendererHooks + * + * @description: + * A structure that stores the four hooks needed to render OT-SVG glyphs + * properly. The structure is publicly used to set the hooks via the + * @svg-hooks driver property. + * + * The behavior of each hook is described in its documentation. One + * thing to note is that the preset hook and the render hook often need + * to do the same operations; therefore, it's better to cache the + * intermediate data in a state structure to avoid calculating it twice. + * For example, in the preset hook one can draw the glyph on a recorder + * surface and later create a bitmap surface from it in the render hook. + * + * All four hooks must be non-NULL. + * + * @fields: + * init_svg :: + * The initialization hook. + * + * free_svg :: + * The cleanup hook. + * + * render_hook :: + * The render hook. + * + * preset_slot :: + * The preset hook. + * + * @since: + * 2.12 + */ + typedef struct SVG_RendererHooks_ + { + SVG_Lib_Init_Func init_svg; + SVG_Lib_Free_Func free_svg; + SVG_Lib_Render_Func render_svg; + + SVG_Lib_Preset_Slot_Func preset_slot; + + } SVG_RendererHooks; + + + /************************************************************************** + * + * @struct: + * FT_SVG_DocumentRec + * + * @description: + * A structure that models one SVG document. + * + * @fields: + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * The translation to apply to the glyph while rendering. + * + * @note: + * When an @FT_GlyphSlot object `slot` is passed down to a renderer, the + * renderer can only access the `metrics` and `units_per_EM` fields via + * `slot->face`. However, when @FT_Glyph_To_Bitmap sets up a dummy + * object, it has no way to set a `face` object. Thus, metrics + * information and `units_per_EM` (which is necessary for OT-SVG) has to + * be stored separately. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_ + { + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SVG_DocumentRec; + + + /************************************************************************** + * + * @type: + * FT_SVG_Document + * + * @description: + * A handle to an @FT_SVG_DocumentRec object. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_* FT_SVG_Document; + + +FT_END_HEADER + +#endif /* OTSVG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/t1tables.h b/Dependencies/freetype/freetype/include/freetype/t1tables.h new file mode 100644 index 00000000..fbd558aa --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/t1tables.h @@ -0,0 +1,735 @@ +/**************************************************************************** + * + * t1tables.h + * + * Basic Type 1/Type 2 tables definitions and interface (specification + * only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1TABLES_H_ +#define T1TABLES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * type1_tables + * + * @title: + * Type 1 Tables + * + * @abstract: + * Type~1-specific font tables. + * + * @description: + * This section contains the definition of Type~1-specific tables, + * including structures related to other PostScript font formats. + * + * @order: + * PS_FontInfoRec + * PS_FontInfo + * PS_PrivateRec + * PS_Private + * + * CID_FaceDictRec + * CID_FaceDict + * CID_FaceInfoRec + * CID_FaceInfo + * + * FT_Has_PS_Glyph_Names + * FT_Get_PS_Font_Info + * FT_Get_PS_Font_Private + * FT_Get_PS_Font_Value + * + * T1_Blend_Flags + * T1_EncodingType + * PS_Dict_Keys + * + */ + + + /* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ + /* structures in order to support Multiple Master fonts. */ + + + /************************************************************************** + * + * @struct: + * PS_FontInfoRec + * + * @description: + * A structure used to model a Type~1 or Type~2 FontInfo dictionary. + * Note that for Multiple Master fonts, each instance has its own + * FontInfo dictionary. + */ + typedef struct PS_FontInfoRec_ + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + + } PS_FontInfoRec; + + + /************************************************************************** + * + * @struct: + * PS_FontInfo + * + * @description: + * A handle to a @PS_FontInfoRec structure. + */ + typedef struct PS_FontInfoRec_* PS_FontInfo; + + + /************************************************************************** + * + * @struct: + * T1_FontInfo + * + * @description: + * This type is equivalent to @PS_FontInfoRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef PS_FontInfoRec T1_FontInfo; + + + /************************************************************************** + * + * @struct: + * PS_PrivateRec + * + * @description: + * A structure used to model a Type~1 or Type~2 private dictionary. Note + * that for Multiple Master fonts, each instance has its own Private + * dictionary. + */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + + FT_Short blue_values[14]; + FT_Short other_blues[10]; + + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; + + FT_Short snap_widths [13]; /* including std width */ + FT_Short snap_heights[13]; /* including std height */ + + FT_Fixed expansion_factor; + + FT_Long language_group; + FT_Long password; + + FT_Short min_feature[2]; + + } PS_PrivateRec; + + + /************************************************************************** + * + * @struct: + * PS_Private + * + * @description: + * A handle to a @PS_PrivateRec structure. + */ + typedef struct PS_PrivateRec_* PS_Private; + + + /************************************************************************** + * + * @struct: + * T1_Private + * + * @description: + * This type is equivalent to @PS_PrivateRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef PS_PrivateRec T1_Private; + + + /************************************************************************** + * + * @enum: + * T1_Blend_Flags + * + * @description: + * A set of flags used to indicate which fields are present in a given + * blend dictionary (font info or private). Used to support Multiple + * Masters fonts. + * + * @values: + * T1_BLEND_UNDERLINE_POSITION :: + * T1_BLEND_UNDERLINE_THICKNESS :: + * T1_BLEND_ITALIC_ANGLE :: + * T1_BLEND_BLUE_VALUES :: + * T1_BLEND_OTHER_BLUES :: + * T1_BLEND_STANDARD_WIDTH :: + * T1_BLEND_STANDARD_HEIGHT :: + * T1_BLEND_STEM_SNAP_WIDTHS :: + * T1_BLEND_STEM_SNAP_HEIGHTS :: + * T1_BLEND_BLUE_SCALE :: + * T1_BLEND_BLUE_SHIFT :: + * T1_BLEND_FAMILY_BLUES :: + * T1_BLEND_FAMILY_OTHER_BLUES :: + * T1_BLEND_FORCE_BOLD :: + */ + typedef enum T1_Blend_Flags_ + { + /* required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, + + /* required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, + + T1_BLEND_MAX /* do not remove */ + + } T1_Blend_Flags; + + + /* these constants are deprecated; use the corresponding */ + /* `T1_Blend_Flags` values instead */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX + + /* */ + + + /************************************************************************** + * + * @struct: + * CID_FaceDictRec + * + * @description: + * A structure used to represent data in a CID top-level dictionary. In + * most cases, they are part of the font's '/FDArray' array. Within a + * CID font file, such (internal) subfont dictionaries are enclosed by + * '%ADOBeginFontDict' and '%ADOEndFontDict' comments. + * + * Note that `CID_FaceDictRec` misses a field for the '/FontName' + * keyword, specifying the subfont's name (the top-level font name is + * given by the '/CIDFontName' keyword). This is an oversight, but it + * doesn't limit the 'cid' font module's functionality because FreeType + * neither needs this entry nor gives access to CID subfonts. + */ + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; /* this is a duplicate of */ + /* `private_dict->expansion_factor' */ + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_UInt sd_bytes; + + } CID_FaceDictRec; + + + /************************************************************************** + * + * @struct: + * CID_FaceDict + * + * @description: + * A handle to a @CID_FaceDictRec structure. + */ + typedef struct CID_FaceDictRec_* CID_FaceDict; + + + /************************************************************************** + * + * @struct: + * CID_FontDict + * + * @description: + * This type is equivalent to @CID_FaceDictRec. It is deprecated but + * kept to maintain source compatibility between various versions of + * FreeType. + */ + typedef CID_FaceDictRec CID_FontDict; + + + /************************************************************************** + * + * @struct: + * CID_FaceInfoRec + * + * @description: + * A structure used to represent CID Face information. + */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + + FT_Int num_xuid; + FT_ULong xuid[16]; + + FT_ULong cidmap_offset; + FT_UInt fd_bytes; + FT_UInt gd_bytes; + FT_ULong cid_count; + + FT_UInt num_dicts; + CID_FaceDict font_dicts; + + FT_ULong data_offset; + + } CID_FaceInfoRec; + + + /************************************************************************** + * + * @struct: + * CID_FaceInfo + * + * @description: + * A handle to a @CID_FaceInfoRec structure. + */ + typedef struct CID_FaceInfoRec_* CID_FaceInfo; + + + /************************************************************************** + * + * @struct: + * CID_Info + * + * @description: + * This type is equivalent to @CID_FaceInfoRec. It is deprecated but kept + * to maintain source compatibility between various versions of FreeType. + */ + typedef CID_FaceInfoRec CID_Info; + + + /************************************************************************** + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable PostScript glyph names. + * This is similar to using the @FT_HAS_GLYPH_NAMES macro, except that + * certain fonts (mostly TrueType) contain incorrect glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + * + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_info :: + * A pointer to a @PS_FontInfoRec object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * String pointers within the @PS_FontInfoRec structure are owned by the + * face and don't need to be freed by the caller. Missing entries in the + * font's FontInfo dictionary are represented by `NULL` pointers. + * + * The following font formats support this feature: 'Type~1', 'Type~42', + * 'CFF', 'CID~Type~1'. For other font formats this function returns the + * `FT_Err_Invalid_Argument` error code. + * + * @example: + * ``` + * PS_FontInfoRec font_info; + * + * + * error = FT_Get_PS_Font_Info( face, &font_info ); + * ... + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfo afont_info ); + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_private :: + * A pointer to a @PS_PrivateRec object. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the @PS_PrivateRec structure are owned by + * the face and don't need to be freed by the caller. + * + * Only the 'Type~1' font format supports this feature. For other font + * formats this function returns the `FT_Err_Invalid_Argument` error + * code. + * + * @example: + * ``` + * PS_PrivateRec font_private; + * + * + * error = FT_Get_PS_Font_Private( face, &font_private ); + * ... + * ``` + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_Private afont_private ); + + + /************************************************************************** + * + * @enum: + * T1_EncodingType + * + * @description: + * An enumeration describing the 'Encoding' entry in a Type 1 dictionary. + * + * @values: + * T1_ENCODING_TYPE_NONE :: + * T1_ENCODING_TYPE_ARRAY :: + * T1_ENCODING_TYPE_STANDARD :: + * T1_ENCODING_TYPE_ISOLATIN1 :: + * T1_ENCODING_TYPE_EXPERT :: + * + * @since: + * 2.4.8 + */ + typedef enum T1_EncodingType_ + { + T1_ENCODING_TYPE_NONE = 0, + T1_ENCODING_TYPE_ARRAY, + T1_ENCODING_TYPE_STANDARD, + T1_ENCODING_TYPE_ISOLATIN1, + T1_ENCODING_TYPE_EXPERT + + } T1_EncodingType; + + + /************************************************************************** + * + * @enum: + * PS_Dict_Keys + * + * @description: + * An enumeration used in calls to @FT_Get_PS_Font_Value to identify the + * Type~1 dictionary entry to retrieve. + * + * @values: + * PS_DICT_FONT_TYPE :: + * PS_DICT_FONT_MATRIX :: + * PS_DICT_FONT_BBOX :: + * PS_DICT_PAINT_TYPE :: + * PS_DICT_FONT_NAME :: + * PS_DICT_UNIQUE_ID :: + * PS_DICT_NUM_CHAR_STRINGS :: + * PS_DICT_CHAR_STRING_KEY :: + * PS_DICT_CHAR_STRING :: + * PS_DICT_ENCODING_TYPE :: + * PS_DICT_ENCODING_ENTRY :: + * PS_DICT_NUM_SUBRS :: + * PS_DICT_SUBR :: + * PS_DICT_STD_HW :: + * PS_DICT_STD_VW :: + * PS_DICT_NUM_BLUE_VALUES :: + * PS_DICT_BLUE_VALUE :: + * PS_DICT_BLUE_FUZZ :: + * PS_DICT_NUM_OTHER_BLUES :: + * PS_DICT_OTHER_BLUE :: + * PS_DICT_NUM_FAMILY_BLUES :: + * PS_DICT_FAMILY_BLUE :: + * PS_DICT_NUM_FAMILY_OTHER_BLUES :: + * PS_DICT_FAMILY_OTHER_BLUE :: + * PS_DICT_BLUE_SCALE :: + * PS_DICT_BLUE_SHIFT :: + * PS_DICT_NUM_STEM_SNAP_H :: + * PS_DICT_STEM_SNAP_H :: + * PS_DICT_NUM_STEM_SNAP_V :: + * PS_DICT_STEM_SNAP_V :: + * PS_DICT_FORCE_BOLD :: + * PS_DICT_RND_STEM_UP :: + * PS_DICT_MIN_FEATURE :: + * PS_DICT_LEN_IV :: + * PS_DICT_PASSWORD :: + * PS_DICT_LANGUAGE_GROUP :: + * PS_DICT_VERSION :: + * PS_DICT_NOTICE :: + * PS_DICT_FULL_NAME :: + * PS_DICT_FAMILY_NAME :: + * PS_DICT_WEIGHT :: + * PS_DICT_IS_FIXED_PITCH :: + * PS_DICT_UNDERLINE_POSITION :: + * PS_DICT_UNDERLINE_THICKNESS :: + * PS_DICT_FS_TYPE :: + * PS_DICT_ITALIC_ANGLE :: + * + * @since: + * 2.4.8 + */ + typedef enum PS_Dict_Keys_ + { + /* conventionally in the font dictionary */ + PS_DICT_FONT_TYPE, /* FT_Byte */ + PS_DICT_FONT_MATRIX, /* FT_Fixed */ + PS_DICT_FONT_BBOX, /* FT_Fixed */ + PS_DICT_PAINT_TYPE, /* FT_Byte */ + PS_DICT_FONT_NAME, /* FT_String* */ + PS_DICT_UNIQUE_ID, /* FT_Int */ + PS_DICT_NUM_CHAR_STRINGS, /* FT_Int */ + PS_DICT_CHAR_STRING_KEY, /* FT_String* */ + PS_DICT_CHAR_STRING, /* FT_String* */ + PS_DICT_ENCODING_TYPE, /* T1_EncodingType */ + PS_DICT_ENCODING_ENTRY, /* FT_String* */ + + /* conventionally in the font Private dictionary */ + PS_DICT_NUM_SUBRS, /* FT_Int */ + PS_DICT_SUBR, /* FT_String* */ + PS_DICT_STD_HW, /* FT_UShort */ + PS_DICT_STD_VW, /* FT_UShort */ + PS_DICT_NUM_BLUE_VALUES, /* FT_Byte */ + PS_DICT_BLUE_VALUE, /* FT_Short */ + PS_DICT_BLUE_FUZZ, /* FT_Int */ + PS_DICT_NUM_OTHER_BLUES, /* FT_Byte */ + PS_DICT_OTHER_BLUE, /* FT_Short */ + PS_DICT_NUM_FAMILY_BLUES, /* FT_Byte */ + PS_DICT_FAMILY_BLUE, /* FT_Short */ + PS_DICT_NUM_FAMILY_OTHER_BLUES, /* FT_Byte */ + PS_DICT_FAMILY_OTHER_BLUE, /* FT_Short */ + PS_DICT_BLUE_SCALE, /* FT_Fixed */ + PS_DICT_BLUE_SHIFT, /* FT_Int */ + PS_DICT_NUM_STEM_SNAP_H, /* FT_Byte */ + PS_DICT_STEM_SNAP_H, /* FT_Short */ + PS_DICT_NUM_STEM_SNAP_V, /* FT_Byte */ + PS_DICT_STEM_SNAP_V, /* FT_Short */ + PS_DICT_FORCE_BOLD, /* FT_Bool */ + PS_DICT_RND_STEM_UP, /* FT_Bool */ + PS_DICT_MIN_FEATURE, /* FT_Short */ + PS_DICT_LEN_IV, /* FT_Int */ + PS_DICT_PASSWORD, /* FT_Long */ + PS_DICT_LANGUAGE_GROUP, /* FT_Long */ + + /* conventionally in the font FontInfo dictionary */ + PS_DICT_VERSION, /* FT_String* */ + PS_DICT_NOTICE, /* FT_String* */ + PS_DICT_FULL_NAME, /* FT_String* */ + PS_DICT_FAMILY_NAME, /* FT_String* */ + PS_DICT_WEIGHT, /* FT_String* */ + PS_DICT_IS_FIXED_PITCH, /* FT_Bool */ + PS_DICT_UNDERLINE_POSITION, /* FT_Short */ + PS_DICT_UNDERLINE_THICKNESS, /* FT_UShort */ + PS_DICT_FS_TYPE, /* FT_UShort */ + PS_DICT_ITALIC_ANGLE, /* FT_Long */ + + PS_DICT_MAX = PS_DICT_ITALIC_ANGLE + + } PS_Dict_Keys; + + + /************************************************************************** + * + * @function: + * FT_Get_PS_Font_Value + * + * @description: + * Retrieve the value for the supplied key from a PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * key :: + * An enumeration value representing the dictionary key to retrieve. + * + * idx :: + * For array values, this specifies the index to be returned. + * + * value :: + * A pointer to memory into which to write the value. + * + * valen_len :: + * The size, in bytes, of the memory supplied for the value. + * + * @output: + * value :: + * The value matching the above key, if it exists. + * + * @return: + * The amount of memory (in bytes) required to hold the requested value + * (if it exists, -1 otherwise). + * + * @note: + * The values returned are not pointers into the internal structures of + * the face, but are 'fresh' copies, so that the memory containing them + * belongs to the calling application. This also enforces the + * 'read-only' nature of these values, i.e., this function cannot be + * used to manipulate the face. + * + * `value` is a void pointer because the values returned can be of + * various types. + * + * If either `value` is `NULL` or `value_len` is too small, just the + * required memory size for the requested entry is returned. + * + * The `idx` parameter is used, not only to retrieve elements of, for + * example, the FontMatrix or FontBBox, but also to retrieve name keys + * from the CharStrings dictionary, and the charstrings themselves. It + * is ignored for atomic values. + * + * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To + * get the value as in the font stream, you need to divide by 65536000.0 + * (to remove the FT_Fixed scale, and the x1000 scale). + * + * IMPORTANT: Only key/value pairs read by the FreeType interpreter can + * be retrieved. So, for example, PostScript procedures such as NP, ND, + * and RD are not available. Arbitrary keys are, obviously, not be + * available either. + * + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument` error code. + * + * @since: + * 2.4.8 + * + */ + FT_EXPORT( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); + + /* */ + +FT_END_HEADER + +#endif /* T1TABLES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/ttnameid.h b/Dependencies/freetype/freetype/include/freetype/ttnameid.h new file mode 100644 index 00000000..d5d470e3 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/ttnameid.h @@ -0,0 +1,1235 @@ +/**************************************************************************** + * + * ttnameid.h + * + * TrueType name ID definitions (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTNAMEID_H_ +#define TTNAMEID_H_ + + + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * truetype_tables + */ + + + /************************************************************************** + * + * Possible values for the 'platform' identifier code in the name records + * of an SFNT 'name' table. + * + */ + + + /************************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id` identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id` values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name + * entry. See @TT_MAC_ID_XXX for corresponding `encoding_id` values. + * Note that most TrueType fonts contain an Apple roman charmap to be + * usable on MacOS systems (even if they contain a Microsoft charmap as + * well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify ISO/IEC 10646 charmaps. It is + * however now deprecated. See @TT_ISO_ID_XXX for a list of + * corresponding `encoding_id` values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id` values. + * Note that most fonts contain a Unicode charmap using + * (`TT_PLATFORM_MICROSOFT`, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ + +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +#define TT_PLATFORM_ISO 2 /* deprecated */ +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +#define TT_PLATFORM_ADOBE 7 /* artificial */ + + + /************************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + * + * TT_APPLE_ID_VARIANT_SELECTOR :: + * From Adobe, not Apple. Not a normal cmap. Specifies variations on + * a real cmap. + * + * TT_APPLE_ID_FULL_UNICODE :: + * Used for fallback fonts that provide complete Unicode coverage with + * a type~13 cmap. + */ + +#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */ +#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */ +#define TT_APPLE_ID_ISO_10646 2 /* deprecated */ +#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */ +#define TT_APPLE_ID_UNICODE_32 4 /* 2.0 or later, full repertoire */ +#define TT_APPLE_ID_VARIANT_SELECTOR 5 /* variation selector data */ +#define TT_APPLE_ID_FULL_UNICODE 6 /* used with type 13 cmaps */ + + + /************************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + */ + +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 + + + /************************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for @TT_PLATFORM_ISO + * charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ + +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 + + + /************************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Microsoft symbol encoding. See @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Microsoft WGL4 charmap, matching Unicode. See @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Shift JIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_PRC :: + * Chinese encodings as used in the People's Republic of China (PRC). + * This means the encodings GB~2312 and its supersets GBK and GB~18030. + * See @FT_ENCODING_PRC. + * + * TT_MS_ID_BIG_5 :: + * Traditional Chinese as used in Taiwan and Hong Kong. See + * @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Korean Extended Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Korean Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * UCS-4 or UTF-32 charmaps. This has been added to the OpenType + * specification version 1.4 (mid-2001). + */ + +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_PRC 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 + + /* this value is deprecated */ +#define TT_MS_ID_GB2312 TT_MS_ID_PRC + + + /************************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id` for @TT_PLATFORM_ADOBE + * charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + * TT_ADOBE_ID_LATIN_1 :: + * Adobe Latin~1 encoding. + */ + +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 + + + /************************************************************************** + * + * @enum: + * TT_MAC_LANGID_XXX + * + * @description: + * Possible values of the language identifier field in the name records + * of the SFNT 'name' table if the 'platform' identifier code is + * @TT_PLATFORM_MACINTOSH. These values are also used as return values + * for function @FT_Get_CMap_Language_ID. + * + * The canonical source for Apple's IDs is + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html + */ + +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 + + /* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 + + + /************************************************************************** + * + * @enum: + * TT_MS_LANGID_XXX + * + * @description: + * Possible values of the language identifier field in the name records + * of the SFNT 'name' table if the 'platform' identifier code is + * @TT_PLATFORM_MICROSOFT. These values are also used as return values + * for function @FT_Get_CMap_Language_ID. + * + * The canonical source for Microsoft's IDs is + * + * https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings , + * + * however, we only provide macros for language identifiers present in + * the OpenType specification: Microsoft has abandoned the concept of + * LCIDs (language code identifiers), and format~1 of the 'name' table + * provides a better mechanism for languages not covered here. + * + * More legacy values not listed in the reference can be found in the + * @FT_TRUETYPE_IDS_H header file. + */ + +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0C01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1C01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2C01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3C01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_CATALAN 0x0403 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0C04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 +#define TT_MS_LANGID_CHINESE_MACAO 0x1404 +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0C07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEIN 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0C09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1C09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2C09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040A +#define TT_MS_LANGID_SPANISH_MEXICO 0x080A +#define TT_MS_LANGID_SPANISH_SPAIN_MODERN_SORT 0x0C0A +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100A +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140A +#define TT_MS_LANGID_SPANISH_PANAMA 0x180A +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1C0A +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200A +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240A +#define TT_MS_LANGID_SPANISH_PERU 0x280A +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2C0A +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300A +#define TT_MS_LANGID_SPANISH_CHILE 0x340A +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380A +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3C0A +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400A +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440A +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480A +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4C0A +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500A +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540A +#define TT_MS_LANGID_FINNISH_FINLAND 0x040B +#define TT_MS_LANGID_FRENCH_FRANCE 0x040C +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080C +#define TT_MS_LANGID_FRENCH_CANADA 0x0C0C +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100C +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140C +#define TT_MS_LANGID_FRENCH_MONACO 0x180C +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040D +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040E +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040F +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_KOREA 0x0412 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_ROMANSH_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041A +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081A +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0C1A +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101A +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141A +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181A +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x1C1A +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZ_CYRILLIC 0x201A +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041B +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041C +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041D +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081D +#define TT_MS_LANGID_THAI_THAILAND 0x041E +#define TT_MS_LANGID_TURKISH_TURKEY 0x041F +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENIAN_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042A +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042B +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042C +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082C +#define TT_MS_LANGID_BASQUE_BASQUE 0x042D +#define TT_MS_LANGID_UPPER_SORBIAN_GERMANY 0x042E +#define TT_MS_LANGID_LOWER_SORBIAN_GERMANY 0x082E +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042F +#define TT_MS_LANGID_SETSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_ISIXHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ISIZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043A +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043B +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083B +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3B +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103B +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143B +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183B +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3B +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203B +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243B +#define TT_MS_LANGID_IRISH_IRELAND 0x083C +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043E +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083E +#define TT_MS_LANGID_KAZAKH_KAZAKHSTAN 0x043F +#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic */ 0x0440 +#define TT_MS_LANGID_KISWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_RUSSIA 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ODIA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044A +#define TT_MS_LANGID_KANNADA_INDIA 0x044B +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044C +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044D +#define TT_MS_LANGID_MARATHI_INDIA 0x044E +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044F +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA /* Cyrillic */ 0x0450 +#define TT_MS_LANGID_MONGOLIAN_PRC 0x0850 +#define TT_MS_LANGID_TIBETAN_PRC 0x0451 +#define TT_MS_LANGID_WELSH_UNITED_KINGDOM 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_GALICIAN_GALICIAN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045A +#define TT_MS_LANGID_SINHALA_SRI_LANKA 0x045B +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045D +#define TT_MS_LANGID_INUKTITUT_CANADA_LATIN 0x085D +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045E +#define TT_MS_LANGID_TAMAZIGHT_ALGERIA 0x085F +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046A +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046B +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086B +#define TT_MS_LANGID_QUECHUA_PERU 0x0C6B +#define TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA 0x046C +#define TT_MS_LANGID_BASHKIR_RUSSIA 0x046D +#define TT_MS_LANGID_LUXEMBOURGISH_LUXEMBOURG 0x046E +#define TT_MS_LANGID_GREENLANDIC_GREENLAND 0x046F +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_YI_PRC 0x0478 +#define TT_MS_LANGID_MAPUDUNGUN_CHILE 0x047A +#define TT_MS_LANGID_MOHAWK_MOHAWK 0x047C +#define TT_MS_LANGID_BRETON_FRANCE 0x047E +#define TT_MS_LANGID_UIGHUR_PRC 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 +#define TT_MS_LANGID_OCCITAN_FRANCE 0x0482 +#define TT_MS_LANGID_CORSICAN_FRANCE 0x0483 +#define TT_MS_LANGID_ALSATIAN_FRANCE 0x0484 +#define TT_MS_LANGID_YAKUT_RUSSIA 0x0485 +#define TT_MS_LANGID_KICHE_GUATEMALA 0x0486 +#define TT_MS_LANGID_KINYARWANDA_RWANDA 0x0487 +#define TT_MS_LANGID_WOLOF_SENEGAL 0x0488 +#define TT_MS_LANGID_DARI_AFGHANISTAN 0x048C + + /* */ + + + /* legacy macro definitions not present in OpenType 1.8.1 */ +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_CATALAN_SPAIN \ + TT_MS_LANGID_CATALAN_CATALAN +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_MACAU \ + TT_MS_LANGID_CHINESE_MACAO +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI \ + TT_MS_LANGID_GERMAN_LIECHTENSTEIN +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3C09 +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT \ + TT_MS_LANGID_SPANISH_SPAIN_MODERN_SORT +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40AU +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1C0C +#define TT_MS_LANGID_FRENCH_REUNION 0x200C +#define TT_MS_LANGID_FRENCH_CONGO 0x240C + /* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE \ + TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280C +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2C0C +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300C +#define TT_MS_LANGID_FRENCH_MALI 0x340C +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380C +#define TT_MS_LANGID_FRENCH_HAITI 0x3C0C +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40CU +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA \ + TT_MS_LANGID_KOREAN_KOREA +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND \ + TT_MS_LANGID_ROMANSH_SWITZERLAND +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_SLOVENE_SLOVENIA \ + TT_MS_LANGID_SLOVENIAN_SLOVENIA +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_BASQUE_SPAIN \ + TT_MS_LANGID_BASQUE_BASQUE +#define TT_MS_LANGID_SORBIAN_GERMANY \ + TT_MS_LANGID_UPPER_SORBIAN_GERMANY +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA \ + TT_MS_LANGID_SETSWANA_SOUTH_AFRICA +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA \ + TT_MS_LANGID_ISIXHOSA_SOUTH_AFRICA +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA \ + TT_MS_LANGID_ISIZULU_SOUTH_AFRICA +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043B + /* the next two values are incorrectly inverted */ +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043C +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083C +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043D +#define TT_MS_LANGID_KAZAK_KAZAKSTAN \ + TT_MS_LANGID_KAZAKH_KAZAKHSTAN +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KYRGYZ_KYRGYZSTAN +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN \ + TT_MS_LANGID_KYRGYZ_KYRGYZSTAN +#define TT_MS_LANGID_SWAHILI_KENYA \ + TT_MS_LANGID_KISWAHILI_KENYA +#define TT_MS_LANGID_TATAR_TATARSTAN \ + TT_MS_LANGID_TATAR_RUSSIA +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_ORIYA_INDIA \ + TT_MS_LANGID_ODIA_INDIA +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN \ + TT_MS_LANGID_MONGOLIAN_PRC +#define TT_MS_LANGID_TIBETAN_CHINA \ + TT_MS_LANGID_TIBETAN_PRC +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 +#define TT_MS_LANGID_TIBETAN_BHUTAN \ + TT_MS_LANGID_DZONGHKA_BHUTAN +#define TT_MS_LANGID_WELSH_WALES \ + TT_MS_LANGID_WELSH_UNITED_KINGDOM +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN \ + TT_MS_LANGID_GALICIAN_GALICIAN +#define TT_MS_LANGID_MANIPURI_INDIA /* Bengali */ 0x0458 +#define TT_MS_LANGID_SINDHI_INDIA /* Arabic */ 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 +#define TT_MS_LANGID_SINHALESE_SRI_LANKA \ + TT_MS_LANGID_SINHALA_SRI_LANKA +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045C +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO /* Arabic */ 0x045F +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN \ + TT_MS_LANGID_TAMAZIGHT_ALGERIA +#define TT_MS_LANGID_KASHMIRI_PAKISTAN /* Arabic */ 0x0460 +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 +#define TT_MS_LANGID_KASHMIRI_INDIA \ + TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_DIVEHI_MALDIVES \ + TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA \ + TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SESOTHO_SA_LEBOA_SOUTH_AFRICA +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 +#define TT_MS_LANGID_TIGRIGNA_ERYTREA \ + TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 +#define TT_MS_LANGID_YI_CHINA \ + TT_MS_LANGID_YI_PRC +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 +#define TT_MS_LANGID_UIGHUR_CHINA \ + TT_MS_LANGID_UIGHUR_PRC + + + /************************************************************************** + * + * @enum: + * TT_NAME_ID_XXX + * + * @description: + * Possible values of the 'name' identifier field in the name records of + * an SFNT 'name' table. These values are platform independent. + */ + +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 + + /* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 + /* number 15 is reserved */ +#define TT_NAME_ID_TYPOGRAPHIC_FAMILY 16 +#define TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 + + /* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 + + /* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 + + /* This is new in OpenType 1.5 */ +#define TT_NAME_ID_WWS_FAMILY 21 +#define TT_NAME_ID_WWS_SUBFAMILY 22 + + /* This is new in OpenType 1.7 */ +#define TT_NAME_ID_LIGHT_BACKGROUND 23 +#define TT_NAME_ID_DARK_BACKGROUND 24 + + /* This is new in OpenType 1.8 */ +#define TT_NAME_ID_VARIATIONS_PREFIX 25 + + /* these two values are deprecated */ +#define TT_NAME_ID_PREFERRED_FAMILY TT_NAME_ID_TYPOGRAPHIC_FAMILY +#define TT_NAME_ID_PREFERRED_SUBFAMILY TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY + + + /************************************************************************** + * + * @enum: + * TT_UCR_XXX + * + * @description: + * Possible bit mask values for the `ulUnicodeRangeX` fields in an SFNT + * 'OS/2' table. + */ + + /* ulUnicodeRange1 */ + /* --------------- */ + + /* Bit 0 Basic Latin */ +#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ + /* Bit 1 C1 Controls and Latin-1 Supplement */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ + /* Bit 2 Latin Extended-A */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ + /* Bit 3 Latin Extended-B */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ + /* Bit 4 IPA Extensions */ + /* Phonetic Extensions */ + /* Phonetic Extensions Supplement */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ + /* U+1D00-U+1D7F */ + /* U+1D80-U+1DBF */ + /* Bit 5 Spacing Modifier Letters */ + /* Modifier Tone Letters */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ + /* U+A700-U+A71F */ + /* Bit 6 Combining Diacritical Marks */ + /* Combining Diacritical Marks Supplement */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1L << 6) /* U+0300-U+036F */ + /* U+1DC0-U+1DFF */ + /* Bit 7 Greek and Coptic */ +#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ + /* Bit 8 Coptic */ +#define TT_UCR_COPTIC (1L << 8) /* U+2C80-U+2CFF */ + /* Bit 9 Cyrillic */ + /* Cyrillic Supplement */ + /* Cyrillic Extended-A */ + /* Cyrillic Extended-B */ +#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ + /* U+0500-U+052F */ + /* U+2DE0-U+2DFF */ + /* U+A640-U+A69F */ + /* Bit 10 Armenian */ +#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ + /* Bit 11 Hebrew */ +#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ + /* Bit 12 Vai */ +#define TT_UCR_VAI (1L << 12) /* U+A500-U+A63F */ + /* Bit 13 Arabic */ + /* Arabic Supplement */ +#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ + /* U+0750-U+077F */ + /* Bit 14 NKo */ +#define TT_UCR_NKO (1L << 14) /* U+07C0-U+07FF */ + /* Bit 15 Devanagari */ +#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ + /* Bit 16 Bengali */ +#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ + /* Bit 17 Gurmukhi */ +#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ + /* Bit 18 Gujarati */ +#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya */ +#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ + /* Bit 20 Tamil */ +#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ + /* Bit 21 Telugu */ +#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ + /* Bit 22 Kannada */ +#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ + /* Bit 23 Malayalam */ +#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ + /* Bit 24 Thai */ +#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ + /* Bit 25 Lao */ +#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ + /* Bit 26 Georgian */ + /* Georgian Supplement */ +#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ + /* U+2D00-U+2D2F */ + /* Bit 27 Balinese */ +#define TT_UCR_BALINESE (1L << 27) /* U+1B00-U+1B7F */ + /* Bit 28 Hangul Jamo */ +#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ + /* Bit 29 Latin Extended Additional */ + /* Latin Extended-C */ + /* Latin Extended-D */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ + /* U+2C60-U+2C7F */ + /* U+A720-U+A7FF */ + /* Bit 30 Greek Extended */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ + /* Bit 31 General Punctuation */ + /* Supplemental Punctuation */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ + /* U+2E00-U+2E7F */ + + /* ulUnicodeRange2 */ + /* --------------- */ + + /* Bit 32 Superscripts And Subscripts */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ + /* Bit 33 Currency Symbols */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ + /* Bit 34 Combining Diacritical Marks For Symbols */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + (1L << 2) /* U+20D0-U+20FF */ + /* Bit 35 Letterlike Symbols */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ + /* Bit 36 Number Forms */ +#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ + /* Bit 37 Arrows */ + /* Supplemental Arrows-A */ + /* Supplemental Arrows-B */ + /* Miscellaneous Symbols and Arrows */ +#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ + /* U+27F0-U+27FF */ + /* U+2900-U+297F */ + /* U+2B00-U+2BFF */ + /* Bit 38 Mathematical Operators */ + /* Supplemental Mathematical Operators */ + /* Miscellaneous Mathematical Symbols-A */ + /* Miscellaneous Mathematical Symbols-B */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ + /* U+2A00-U+2AFF */ + /* U+27C0-U+27EF */ + /* U+2980-U+29FF */ + /* Bit 39 Miscellaneous Technical */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ + /* Bit 40 Control Pictures */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ + /* Bit 41 Optical Character Recognition */ +#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ + /* Bit 42 Enclosed Alphanumerics */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ + /* Bit 43 Box Drawing */ +#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ + /* Bit 44 Block Elements */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ + /* Bit 45 Geometric Shapes */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ + /* Bit 46 Miscellaneous Symbols */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ + /* Bit 47 Dingbats */ +#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ + /* Bit 48 CJK Symbols and Punctuation */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ + /* Bit 49 Hiragana */ +#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ + /* Bit 50 Katakana */ + /* Katakana Phonetic Extensions */ +#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ + /* U+31F0-U+31FF */ + /* Bit 51 Bopomofo */ + /* Bopomofo Extended */ +#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ + /* U+31A0-U+31BF */ + /* Bit 52 Hangul Compatibility Jamo */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ + /* Bit 53 Phags-Pa */ +#define TT_UCR_CJK_MISC (1L << 21) /* U+A840-U+A87F */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC /* deprecated */ +#define TT_UCR_PHAGSPA + /* Bit 54 Enclosed CJK Letters and Months */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ + /* Bit 55 CJK Compatibility */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ + /* Bit 56 Hangul Syllables */ +#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ + /* Bit 57 High Surrogates */ + /* High Private Use Surrogates */ + /* Low Surrogates */ + + /* According to OpenType specs v.1.3+, */ + /* setting bit 57 implies that there is */ + /* at least one codepoint beyond the */ + /* Basic Multilingual Plane that is */ + /* supported by this font. So it really */ + /* means >= U+10000. */ +#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ + /* U+DB80-U+DBFF */ + /* U+DC00-U+DFFF */ +#define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES + /* Bit 58 Phoenician */ +#define TT_UCR_PHOENICIAN (1L << 26) /*U+10900-U+1091F*/ + /* Bit 59 CJK Unified Ideographs */ + /* CJK Radicals Supplement */ + /* Kangxi Radicals */ + /* Ideographic Description Characters */ + /* CJK Unified Ideographs Extension A */ + /* CJK Unified Ideographs Extension B */ + /* Kanbun */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ + /* U+2E80-U+2EFF */ + /* U+2F00-U+2FDF */ + /* U+2FF0-U+2FFF */ + /* U+3400-U+4DB5 */ + /*U+20000-U+2A6DF*/ + /* U+3190-U+319F */ + /* Bit 60 Private Use */ +#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ + /* Bit 61 CJK Strokes */ + /* CJK Compatibility Ideographs */ + /* CJK Compatibility Ideographs Supplement */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+31C0-U+31EF */ + /* U+F900-U+FAFF */ + /*U+2F800-U+2FA1F*/ + /* Bit 62 Alphabetic Presentation Forms */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ + /* Bit 63 Arabic Presentation Forms-A */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1L << 31) /* U+FB50-U+FDFF */ + + /* ulUnicodeRange3 */ + /* --------------- */ + + /* Bit 64 Combining Half Marks */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ + /* Bit 65 Vertical forms */ + /* CJK Compatibility Forms */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE10-U+FE1F */ + /* U+FE30-U+FE4F */ + /* Bit 66 Small Form Variants */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ + /* Bit 67 Arabic Presentation Forms-B */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1L << 3) /* U+FE70-U+FEFE */ + /* Bit 68 Halfwidth and Fullwidth Forms */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ + /* Bit 69 Specials */ +#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ + /* Bit 70 Tibetan */ +#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ + /* Bit 71 Syriac */ +#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ + /* Bit 72 Thaana */ +#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ + /* Bit 73 Sinhala */ +#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ + /* Bit 74 Myanmar */ +#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ + /* Bit 75 Ethiopic */ + /* Ethiopic Supplement */ + /* Ethiopic Extended */ +#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ + /* U+1380-U+139F */ + /* U+2D80-U+2DDF */ + /* Bit 76 Cherokee */ +#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ + /* Bit 77 Unified Canadian Aboriginal Syllabics */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ + /* Bit 78 Ogham */ +#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ + /* Bit 79 Runic */ +#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ + /* Bit 80 Khmer */ + /* Khmer Symbols */ +#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ + /* U+19E0-U+19FF */ + /* Bit 81 Mongolian */ +#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ + /* Bit 82 Braille Patterns */ +#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ + /* Bit 83 Yi Syllables */ + /* Yi Radicals */ +#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ + /* U+A490-U+A4CF */ + /* Bit 84 Tagalog */ + /* Hanunoo */ + /* Buhid */ + /* Tagbanwa */ +#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ + /* U+1720-U+173F */ + /* U+1740-U+175F */ + /* U+1760-U+177F */ + /* Bit 85 Old Italic */ +#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ + /* Bit 86 Gothic */ +#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ + /* Bit 87 Deseret */ +#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ + /* Bit 88 Byzantine Musical Symbols */ + /* Musical Symbols */ + /* Ancient Greek Musical Notation */ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ + /*U+1D100-U+1D1FF*/ + /*U+1D200-U+1D24F*/ + /* Bit 89 Mathematical Alphanumeric Symbols */ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ + /* Bit 90 Private Use (plane 15) */ + /* Private Use (plane 16) */ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ + /*U+100000-U+10FFFD*/ + /* Bit 91 Variation Selectors */ + /* Variation Selectors Supplement */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ + /*U+E0100-U+E01EF*/ + /* Bit 92 Tags */ +#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ + /* Bit 93 Limbu */ +#define TT_UCR_LIMBU (1L << 29) /* U+1900-U+194F */ + /* Bit 94 Tai Le */ +#define TT_UCR_TAI_LE (1L << 30) /* U+1950-U+197F */ + /* Bit 95 New Tai Lue */ +#define TT_UCR_NEW_TAI_LUE (1L << 31) /* U+1980-U+19DF */ + + /* ulUnicodeRange4 */ + /* --------------- */ + + /* Bit 96 Buginese */ +#define TT_UCR_BUGINESE (1L << 0) /* U+1A00-U+1A1F */ + /* Bit 97 Glagolitic */ +#define TT_UCR_GLAGOLITIC (1L << 1) /* U+2C00-U+2C5F */ + /* Bit 98 Tifinagh */ +#define TT_UCR_TIFINAGH (1L << 2) /* U+2D30-U+2D7F */ + /* Bit 99 Yijing Hexagram Symbols */ +#define TT_UCR_YIJING (1L << 3) /* U+4DC0-U+4DFF */ + /* Bit 100 Syloti Nagri */ +#define TT_UCR_SYLOTI_NAGRI (1L << 4) /* U+A800-U+A82F */ + /* Bit 101 Linear B Syllabary */ + /* Linear B Ideograms */ + /* Aegean Numbers */ +#define TT_UCR_LINEAR_B (1L << 5) /*U+10000-U+1007F*/ + /*U+10080-U+100FF*/ + /*U+10100-U+1013F*/ + /* Bit 102 Ancient Greek Numbers */ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) /*U+10140-U+1018F*/ + /* Bit 103 Ugaritic */ +#define TT_UCR_UGARITIC (1L << 7) /*U+10380-U+1039F*/ + /* Bit 104 Old Persian */ +#define TT_UCR_OLD_PERSIAN (1L << 8) /*U+103A0-U+103DF*/ + /* Bit 105 Shavian */ +#define TT_UCR_SHAVIAN (1L << 9) /*U+10450-U+1047F*/ + /* Bit 106 Osmanya */ +#define TT_UCR_OSMANYA (1L << 10) /*U+10480-U+104AF*/ + /* Bit 107 Cypriot Syllabary */ +#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) /*U+10800-U+1083F*/ + /* Bit 108 Kharoshthi */ +#define TT_UCR_KHAROSHTHI (1L << 12) /*U+10A00-U+10A5F*/ + /* Bit 109 Tai Xuan Jing Symbols */ +#define TT_UCR_TAI_XUAN_JING (1L << 13) /*U+1D300-U+1D35F*/ + /* Bit 110 Cuneiform */ + /* Cuneiform Numbers and Punctuation */ +#define TT_UCR_CUNEIFORM (1L << 14) /*U+12000-U+123FF*/ + /*U+12400-U+1247F*/ + /* Bit 111 Counting Rod Numerals */ +#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) /*U+1D360-U+1D37F*/ + /* Bit 112 Sundanese */ +#define TT_UCR_SUNDANESE (1L << 16) /* U+1B80-U+1BBF */ + /* Bit 113 Lepcha */ +#define TT_UCR_LEPCHA (1L << 17) /* U+1C00-U+1C4F */ + /* Bit 114 Ol Chiki */ +#define TT_UCR_OL_CHIKI (1L << 18) /* U+1C50-U+1C7F */ + /* Bit 115 Saurashtra */ +#define TT_UCR_SAURASHTRA (1L << 19) /* U+A880-U+A8DF */ + /* Bit 116 Kayah Li */ +#define TT_UCR_KAYAH_LI (1L << 20) /* U+A900-U+A92F */ + /* Bit 117 Rejang */ +#define TT_UCR_REJANG (1L << 21) /* U+A930-U+A95F */ + /* Bit 118 Cham */ +#define TT_UCR_CHAM (1L << 22) /* U+AA00-U+AA5F */ + /* Bit 119 Ancient Symbols */ +#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) /*U+10190-U+101CF*/ + /* Bit 120 Phaistos Disc */ +#define TT_UCR_PHAISTOS_DISC (1L << 24) /*U+101D0-U+101FF*/ + /* Bit 121 Carian */ + /* Lycian */ + /* Lydian */ +#define TT_UCR_OLD_ANATOLIAN (1L << 25) /*U+102A0-U+102DF*/ + /*U+10280-U+1029F*/ + /*U+10920-U+1093F*/ + /* Bit 122 Domino Tiles */ + /* Mahjong Tiles */ +#define TT_UCR_GAME_TILES (1L << 26) /*U+1F030-U+1F09F*/ + /*U+1F000-U+1F02F*/ + /* Bit 123-127 Reserved for process-internal usage */ + + /* */ + + /* for backward compatibility with older FreeType versions */ +#define TT_UCR_ARABIC_PRESENTATION_A \ + TT_UCR_ARABIC_PRESENTATION_FORMS_A +#define TT_UCR_ARABIC_PRESENTATION_B \ + TT_UCR_ARABIC_PRESENTATION_FORMS_B + +#define TT_UCR_COMBINING_DIACRITICS \ + TT_UCR_COMBINING_DIACRITICAL_MARKS +#define TT_UCR_COMBINING_DIACRITICS_SYMB \ + TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB + + +FT_END_HEADER + +#endif /* TTNAMEID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/tttables.h b/Dependencies/freetype/freetype/include/freetype/tttables.h new file mode 100644 index 00000000..2cf0ff1b --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/tttables.h @@ -0,0 +1,856 @@ +/**************************************************************************** + * + * tttables.h + * + * Basic SFNT/TrueType tables definitions and interface + * (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTTABLES_H_ +#define TTTABLES_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @section: + * truetype_tables + * + * @title: + * TrueType Tables + * + * @abstract: + * TrueType-specific table types and functions. + * + * @description: + * This section contains definitions of some basic tables specific to + * TrueType and OpenType as well as some routines used to access and + * process them. + * + * @order: + * TT_Header + * TT_HoriHeader + * TT_VertHeader + * TT_OS2 + * TT_Postscript + * TT_PCLT + * TT_MaxProfile + * + * FT_Sfnt_Tag + * FT_Get_Sfnt_Table + * FT_Load_Sfnt_Table + * FT_Sfnt_Table_Info + * + * FT_Get_CMap_Language_ID + * FT_Get_CMap_Format + * + * FT_PARAM_TAG_UNPATENTED_HINTING + * + */ + + + /************************************************************************** + * + * @struct: + * TT_Header + * + * @description: + * A structure to model a TrueType font header table. All fields follow + * the OpenType specification. The 64-bit timestamps are stored in + * two-element arrays `Created` and `Modified`, first the upper then + * the lower 32~bits. + */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + + FT_UShort Flags; + FT_UShort Units_Per_EM; + + FT_ULong Created [2]; + FT_ULong Modified[2]; + + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + + } TT_Header; + + + /************************************************************************** + * + * @struct: + * TT_HoriHeader + * + * @description: + * A structure to model a TrueType horizontal header, the 'hhea' table, + * as well as the corresponding horizontal metrics table, 'hmtx'. + * + * @fields: + * Version :: + * The table version. + * + * Ascender :: + * The font's ascender, i.e., the distance from the baseline to the + * top-most of all glyph points found in the font. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoAscender` field of the 'OS/2' table instead + * if you want the correct one. + * + * Descender :: + * The font's descender, i.e., the distance from the baseline to the + * bottom-most of all glyph points found in the font. It is negative. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoDescender` field of the 'OS/2' table + * instead if you want the correct one. + * + * Line_Gap :: + * The font's line gap, i.e., the distance to add to the ascender and + * descender to get the BTB, i.e., the baseline-to-baseline distance + * for the font. + * + * advance_Width_Max :: + * This field is the maximum of all advance widths found in the font. + * It can be used to compute the maximum width of an arbitrary string + * of text. + * + * min_Left_Side_Bearing :: + * The minimum left side bearing of all glyphs within the font. + * + * min_Right_Side_Bearing :: + * The minimum right side bearing of all glyphs within the font. + * + * xMax_Extent :: + * The maximum horizontal extent (i.e., the 'width' of a glyph's + * bounding box) for all glyphs in the font. + * + * caret_Slope_Rise :: + * The rise coefficient of the cursor's slope of the cursor + * (slope=rise/run). + * + * caret_Slope_Run :: + * The run coefficient of the cursor's slope. + * + * caret_Offset :: + * The cursor's offset for slanted fonts. + * + * Reserved :: + * 8~reserved bytes. + * + * metric_Data_Format :: + * Always~0. + * + * number_Of_HMetrics :: + * Number of HMetrics entries in the 'hmtx' table -- this value can be + * smaller than the total number of glyphs in the font. + * + * long_metrics :: + * A pointer into the 'hmtx' table. + * + * short_metrics :: + * A pointer into the 'hmtx' table. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `caret_Slope_Rise`, + * `caret_Slope_Run`, and `caret_Offset`. + */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Width_Max; /* advance width maximum */ + + FT_Short min_Left_Side_Bearing; /* minimum left-sb */ + FT_Short min_Right_Side_Bearing; /* minimum right-sb */ + FT_Short xMax_Extent; /* xmax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; + + /* The following fields are not defined by the OpenType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* 'hmtx' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_HoriHeader; + + + /************************************************************************** + * + * @struct: + * TT_VertHeader + * + * @description: + * A structure used to model a TrueType vertical header, the 'vhea' + * table, as well as the corresponding vertical metrics table, 'vmtx'. + * + * @fields: + * Version :: + * The table version. + * + * Ascender :: + * The font's ascender, i.e., the distance from the baseline to the + * top-most of all glyph points found in the font. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoAscender` field of the 'OS/2' table instead + * if you want the correct one. + * + * Descender :: + * The font's descender, i.e., the distance from the baseline to the + * bottom-most of all glyph points found in the font. It is negative. + * + * This value is invalid in many fonts, as it is usually set by the + * font designer, and often reflects only a portion of the glyphs found + * in the font (maybe ASCII). + * + * You should use the `sTypoDescender` field of the 'OS/2' table + * instead if you want the correct one. + * + * Line_Gap :: + * The font's line gap, i.e., the distance to add to the ascender and + * descender to get the BTB, i.e., the baseline-to-baseline distance + * for the font. + * + * advance_Height_Max :: + * This field is the maximum of all advance heights found in the font. + * It can be used to compute the maximum height of an arbitrary string + * of text. + * + * min_Top_Side_Bearing :: + * The minimum top side bearing of all glyphs within the font. + * + * min_Bottom_Side_Bearing :: + * The minimum bottom side bearing of all glyphs within the font. + * + * yMax_Extent :: + * The maximum vertical extent (i.e., the 'height' of a glyph's + * bounding box) for all glyphs in the font. + * + * caret_Slope_Rise :: + * The rise coefficient of the cursor's slope of the cursor + * (slope=rise/run). + * + * caret_Slope_Run :: + * The run coefficient of the cursor's slope. + * + * caret_Offset :: + * The cursor's offset for slanted fonts. + * + * Reserved :: + * 8~reserved bytes. + * + * metric_Data_Format :: + * Always~0. + * + * number_Of_VMetrics :: + * Number of VMetrics entries in the 'vmtx' table -- this value can be + * smaller than the total number of glyphs in the font. + * + * long_metrics :: + * A pointer into the 'vmtx' table. + * + * short_metrics :: + * A pointer into the 'vmtx' table. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `Ascender`, `Descender`, + * `Line_Gap`, `caret_Slope_Rise`, `caret_Slope_Run`, and `caret_Offset`. + */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; + + FT_UShort advance_Height_Max; /* advance height maximum */ + + FT_Short min_Top_Side_Bearing; /* minimum top-sb */ + FT_Short min_Bottom_Side_Bearing; /* minimum bottom-sb */ + FT_Short yMax_Extent; /* ymax extents */ + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + + FT_Short Reserved[4]; + + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; + + /* The following fields are not defined by the OpenType specification */ + /* but they are used to connect the metrics header to the relevant */ + /* 'vmtx' table. */ + + void* long_metrics; + void* short_metrics; + + } TT_VertHeader; + + + /************************************************************************** + * + * @struct: + * TT_OS2 + * + * @description: + * A structure to model a TrueType 'OS/2' table. All fields comply to + * the OpenType specification. + * + * Note that we now support old Mac fonts that do not include an 'OS/2' + * table. In this case, the `version` field is always set to 0xFFFF. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `sCapHeight`, `sTypoAscender`, + * `sTypoDescender`, `sTypoLineGap`, `sxHeight`, `usWinAscent`, + * `usWinDescent`, `yStrikeoutPosition`, `yStrikeoutSize`, + * `ySubscriptXOffset`, `ySubScriptXSize`, `ySubscriptYOffset`, + * `ySubscriptYSize`, `ySuperscriptXOffset`, `ySuperscriptXSize`, + * `ySuperscriptYOffset`, and `ySuperscriptYSize`. + * + * Possible values for bits in the `ulUnicodeRangeX` fields are given by + * the @TT_UCR_XXX macros. + */ + + typedef struct TT_OS2_ + { + FT_UShort version; /* 0x0001 - more or 0xFFFF */ + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_UShort fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + + FT_Byte panose[10]; + + FT_ULong ulUnicodeRange1; /* Bits 0-31 */ + FT_ULong ulUnicodeRange2; /* Bits 32-63 */ + FT_ULong ulUnicodeRange3; /* Bits 64-95 */ + FT_ULong ulUnicodeRange4; /* Bits 96-127 */ + + FT_Char achVendID[4]; + + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; + + /* only version 1 and higher: */ + + FT_ULong ulCodePageRange1; /* Bits 0-31 */ + FT_ULong ulCodePageRange2; /* Bits 32-63 */ + + /* only version 2 and higher: */ + + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + + /* only version 5 and higher: */ + + FT_UShort usLowerOpticalPointSize; /* in twips (1/20 points) */ + FT_UShort usUpperOpticalPointSize; /* in twips (1/20 points) */ + + } TT_OS2; + + + /************************************************************************** + * + * @struct: + * TT_Postscript + * + * @description: + * A structure to model a TrueType 'post' table. All fields comply to + * the OpenType specification. This structure does not reference a + * font's PostScript glyph names; use @FT_Get_Glyph_Name to retrieve + * them. + * + * @note: + * For an OpenType variation font, the values of the following fields can + * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if + * the font contains an 'MVAR' table: `underlinePosition` and + * `underlineThickness`. + */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; + + /* Glyph names follow in the 'post' table, but we don't */ + /* load them by default. */ + + } TT_Postscript; + + + /************************************************************************** + * + * @struct: + * TT_PCLT + * + * @description: + * A structure to model a TrueType 'PCLT' table. All fields comply to + * the OpenType specification. + */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + + } TT_PCLT; + + + /************************************************************************** + * + * @struct: + * TT_MaxProfile + * + * @description: + * The maximum profile ('maxp') table contains many max values, which can + * be used to pre-allocate arrays for speeding up glyph loading and + * hinting. + * + * @fields: + * version :: + * The version number. + * + * numGlyphs :: + * The number of glyphs in this TrueType font. + * + * maxPoints :: + * The maximum number of points in a non-composite TrueType glyph. See + * also `maxCompositePoints`. + * + * maxContours :: + * The maximum number of contours in a non-composite TrueType glyph. + * See also `maxCompositeContours`. + * + * maxCompositePoints :: + * The maximum number of points in a composite TrueType glyph. See + * also `maxPoints`. + * + * maxCompositeContours :: + * The maximum number of contours in a composite TrueType glyph. See + * also `maxContours`. + * + * maxZones :: + * The maximum number of zones used for glyph hinting. + * + * maxTwilightPoints :: + * The maximum number of points in the twilight zone used for glyph + * hinting. + * + * maxStorage :: + * The maximum number of elements in the storage area used for glyph + * hinting. + * + * maxFunctionDefs :: + * The maximum number of function definitions in the TrueType bytecode + * for this font. + * + * maxInstructionDefs :: + * The maximum number of instruction definitions in the TrueType + * bytecode for this font. + * + * maxStackElements :: + * The maximum number of stack elements used during bytecode + * interpretation. + * + * maxSizeOfInstructions :: + * The maximum number of TrueType opcodes used for glyph hinting. + * + * maxComponentElements :: + * The maximum number of simple (i.e., non-composite) glyphs in a + * composite glyph. + * + * maxComponentDepth :: + * The maximum nesting depth of composite glyphs. + * + * @note: + * This structure is only used during font loading. + */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + + } TT_MaxProfile; + + + /************************************************************************** + * + * @enum: + * FT_Sfnt_Tag + * + * @description: + * An enumeration to specify indices of SFNT tables loaded and parsed by + * FreeType during initialization of an SFNT font. Used in the + * @FT_Get_Sfnt_Table API function. + * + * @values: + * FT_SFNT_HEAD :: + * To access the font's @TT_Header structure. + * + * FT_SFNT_MAXP :: + * To access the font's @TT_MaxProfile structure. + * + * FT_SFNT_OS2 :: + * To access the font's @TT_OS2 structure. + * + * FT_SFNT_HHEA :: + * To access the font's @TT_HoriHeader structure. + * + * FT_SFNT_VHEA :: + * To access the font's @TT_VertHeader structure. + * + * FT_SFNT_POST :: + * To access the font's @TT_Postscript structure. + * + * FT_SFNT_PCLT :: + * To access the font's @TT_PCLT structure. + */ + typedef enum FT_Sfnt_Tag_ + { + FT_SFNT_HEAD, + FT_SFNT_MAXP, + FT_SFNT_OS2, + FT_SFNT_HHEA, + FT_SFNT_VHEA, + FT_SFNT_POST, + FT_SFNT_PCLT, + + FT_SFNT_MAX + + } FT_Sfnt_Tag; + + /* these constants are deprecated; use the corresponding `FT_Sfnt_Tag` */ + /* values instead */ +#define ft_sfnt_head FT_SFNT_HEAD +#define ft_sfnt_maxp FT_SFNT_MAXP +#define ft_sfnt_os2 FT_SFNT_OS2 +#define ft_sfnt_hhea FT_SFNT_HHEA +#define ft_sfnt_vhea FT_SFNT_VHEA +#define ft_sfnt_post FT_SFNT_POST +#define ft_sfnt_pclt FT_SFNT_PCLT + + + /************************************************************************** + * + * @function: + * FT_Get_Sfnt_Table + * + * @description: + * Return a pointer to a given SFNT table stored within a face. + * + * @input: + * face :: + * A handle to the source. + * + * tag :: + * The index of the SFNT table. + * + * @return: + * A type-less pointer to the table. This will be `NULL` in case of + * error, or if the corresponding table was not found **OR** loaded from + * the file. + * + * Use a typecast according to `tag` to access the structure elements. + * + * @note: + * The table is owned by the face object and disappears with it. + * + * This function is only useful to access SFNT tables that are loaded by + * the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for a + * list. + * + * @example: + * Here is an example demonstrating access to the 'vhea' table. + * + * ``` + * TT_VertHeader* vert_header; + * + * + * vert_header = + * (TT_VertHeader*)FT_Get_Sfnt_Table( face, FT_SFNT_VHEA ); + * ``` + */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); + + + /************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Load any SFNT font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use value~0 if you want to + * access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag~==~0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length` parameter is `NULL`, try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length` is~0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length` set to~0, as in the following example: + * + * ``` + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * ``` + * + * Note that structures like @TT_Header or @TT_OS2 can't be used with + * this function; they are limited to @FT_Get_Sfnt_Table. Reason is that + * those structures depend on the processor architecture, with varying + * size (e.g. 32bit vs. 64bit) or order (big endian vs. little endian). + * + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + /************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Return information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @inout: + * tag :: + * The name tag of the SFNT table. If the value is `NULL`, + * `table_index` is ignored, and `length` returns the number of SFNT + * tables in the font. + * + * @output: + * length :: + * The length of the SFNT table (or the number of SFNT tables, + * depending on `tag`). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * While parsing fonts, FreeType handles SFNT tables with length zero as + * missing. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); + + + /************************************************************************** + * + * @function: + * FT_Get_CMap_Language_ID + * + * @description: + * Return cmap language ID as specified in the OpenType standard. + * Definitions of language ID values are in file @FT_TRUETYPE_IDS_H. + * + * @input: + * charmap :: + * The target charmap. + * + * @return: + * The language ID of `charmap`. If `charmap` doesn't belong to an SFNT + * face, just return~0 as the default value. + * + * For a format~14 cmap (to access Unicode IVS), the return value is + * 0xFFFFFFFF. + */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); + + + /************************************************************************** + * + * @function: + * FT_Get_CMap_Format + * + * @description: + * Return the format of an SFNT 'cmap' table. + * + * @input: + * charmap :: + * The target charmap. + * + * @return: + * The format of `charmap`. If `charmap` doesn't belong to an SFNT face + * (including the synthetic Unicode charmap sometimes created by + * FreeType), return -1. + */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); + + /* */ + + +FT_END_HEADER + +#endif /* TTTABLES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/freetype/tttags.h b/Dependencies/freetype/freetype/include/freetype/tttags.h new file mode 100644 index 00000000..da0af5d3 --- /dev/null +++ b/Dependencies/freetype/freetype/include/freetype/tttags.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * + * tttags.h + * + * Tags for TrueType and OpenType tables (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTAGS_H_ +#define TTAGS_H_ + + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' ) +#define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_CFF2 FT_MAKE_TAG( 'C', 'F', 'F', '2' ) +#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_COLR FT_MAKE_TAG( 'C', 'O', 'L', 'R' ) +#define TTAG_CPAL FT_MAKE_TAG( 'C', 'P', 'A', 'L' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_FOND FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) +#define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_MVAR FT_MAKE_TAG( 'M', 'V', 'A', 'R' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_POST FT_MAKE_TAG( 'P', 'O', 'S', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' ) +#define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_SVG FT_MAKE_TAG( 'S', 'V', 'G', ' ' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_TYP1 FT_MAKE_TAG( 'T', 'Y', 'P', '1' ) +#define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) +#define TTAG_VVAR FT_MAKE_TAG( 'V', 'V', 'A', 'R' ) +#define TTAG_wOFF FT_MAKE_TAG( 'w', 'O', 'F', 'F' ) +#define TTAG_wOF2 FT_MAKE_TAG( 'w', 'O', 'F', '2' ) + +/* used by "Keyboard.dfont" on legacy Mac OS X */ +#define TTAG_0xA5kbd FT_MAKE_TAG( 0xA5, 'k', 'b', 'd' ) + +/* used by "LastResort.dfont" on legacy Mac OS X */ +#define TTAG_0xA5lst FT_MAKE_TAG( 0xA5, 'l', 's', 't' ) + + +FT_END_HEADER + +#endif /* TTAGS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/include/ft2build.h b/Dependencies/freetype/freetype/include/ft2build.h new file mode 100644 index 00000000..d3d76850 --- /dev/null +++ b/Dependencies/freetype/freetype/include/ft2build.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ft2build.h + * + * FreeType 2 build and setup macros. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This is the 'entry point' for FreeType header file inclusions, to be + * loaded before all other header files. + * + * A typical example is + * + * ``` + * #include + * #include + * ``` + * + */ + + +#ifndef FT2BUILD_H_ +#define FT2BUILD_H_ + +#include + +#endif /* FT2BUILD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/modules.cfg b/Dependencies/freetype/freetype/modules.cfg new file mode 100644 index 00000000..948d219b --- /dev/null +++ b/Dependencies/freetype/freetype/modules.cfg @@ -0,0 +1,253 @@ +# modules.cfg +# +# Copyright (C) 2005-2024 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. +# +# +# In case you compile the FreeType library with GNU make or makepp, this +# file controls which components are built into the library. Otherwise, +# please read this file for information on the various modules and its +# dependencies, then follow the instructions in the file `docs/INSTALL.ANY'. +# +# To deactivate a module, simply comment out the corresponding line. To +# activate a module, remove the comment character. +# +# Note that many modules and components are further controlled with macros +# in the file `include/freetype/config/ftoption.h'. + + +#### +#### font modules -- at least one is required +#### +#### The order given here (from top to down) is the order used for testing +#### font formats in the compiled library. +#### + +# TrueType font driver. +# +# This driver needs the `sfnt' module. +FONT_MODULES += truetype + +# PostScript Type 1 font driver. +# +# This driver needs the `psaux', `pshinter', and `psnames' modules. +FONT_MODULES += type1 + +# CFF/OpenType font driver. +# +# This driver needs the `sfnt', `psaux', `pshinter', and `psnames' modules. +FONT_MODULES += cff + +# Type 1 CID-keyed font driver. +# +# This driver needs the `psaux', `pshinter', and `psnames' modules. +FONT_MODULES += cid + +# PFR/TrueDoc font driver. See optional extension ftpfr.c below also. +FONT_MODULES += pfr + +# PostScript Type 42 font driver. +# +# This driver needs the `truetype' and `psaux' modules. +FONT_MODULES += type42 + +# Windows FONT/FNT font driver. See optional extension ftwinfnt.c below +# also. +FONT_MODULES += winfonts + +# PCF font driver. If debugging and tracing is enabled, needs `ftbitmap.c'. +FONT_MODULES += pcf + +# BDF font driver. See optional extension ftbdf.c below also. +FONT_MODULES += bdf + +# SFNT files support. If used without `truetype' or `cff', it supports +# bitmap-only fonts within an SFNT wrapper. +# +# This driver needs the `psnames' module. +FONT_MODULES += sfnt + + +#### +#### hinting modules +#### + +# FreeType's auto hinter. +HINTING_MODULES += autofit + +# PostScript hinter. +HINTING_MODULES += pshinter + +# The TrueType hinting engine doesn't have a module of its own but is +# controlled in file include/freetype/config/ftoption.h +# (TT_CONFIG_OPTION_BYTECODE_INTERPRETER and friends). + + +#### +#### raster modules -- at least one is required for vector font formats +#### + +# Anti-aliasing rasterizer. +RASTER_MODULES += smooth + +# Monochrome rasterizer. +RASTER_MODULES += raster + +# OT-SVG. +RASTER_MODULES += svg + +# Signed distance field rasterizer. +RASTER_MODULES += sdf + + +#### +#### auxiliary modules +#### + +# FreeType's cache sub-system (quite stable but still in beta -- this means +# that its public API is subject to change if necessary). See +# include/freetype/ftcache.h. Needs `ftglyph.c'. +AUX_MODULES += cache + +# TrueType GX/AAT table validation. Needs `ftgxval.c' below. +# +# AUX_MODULES += gxvalid + +# Support for streams compressed with gzip (files with suffix .gz). +# +# See include/freetype/ftgzip.h for the API. +AUX_MODULES += gzip + +# Support for streams compressed with LZW (files with suffix .Z). +# +# See include/freetype/ftlzw.h for the API. +AUX_MODULES += lzw + +# Support for streams compressed with bzip2 (files with suffix .bz2). +# +# See include/freetype/ftbzip2.h for the API. +AUX_MODULES += bzip2 + +# OpenType table validation. Needs `ftotval.c' below. +# +# AUX_MODULES += otvalid + +# Auxiliary PostScript driver component to share common code. +# +# This module depends on `psnames'. +AUX_MODULES += psaux + +# Support for PostScript glyph names. +# +# This module can be controlled in ftconfig.h +# (FT_CONFIG_OPTION_POSTSCRIPT_NAMES). +AUX_MODULES += psnames + + +#### +#### base module extensions +#### + +# Exact bounding box calculation. +# +# See include/freetype/ftbbox.h for the API. +BASE_EXTENSIONS += ftbbox.c + +# Access BDF-specific strings. Needs BDF font driver. +# +# See include/freetype/ftbdf.h for the API. +BASE_EXTENSIONS += ftbdf.c + +# Utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp bitmaps into +# 8bpp format, and for emboldening of bitmap glyphs. +# +# See include/freetype/ftbitmap.h for the API. +BASE_EXTENSIONS += ftbitmap.c + +# Access CID font information. +# +# See include/freetype/ftcid.h for the API. +BASE_EXTENSIONS += ftcid.c + +# Access FSType information. Needs `fttype1.c'. +# +# See include/freetype/freetype.h for the API. +BASE_EXTENSIONS += ftfstype.c + +# Support for GASP table queries. +# +# See include/freetype/ftgasp.h for the API. +BASE_EXTENSIONS += ftgasp.c + +# Convenience functions to handle glyphs. Needs `ftbitmap.c'. +# +# See include/freetype/ftglyph.h for the API. +BASE_EXTENSIONS += ftglyph.c + +# Interface for gxvalid module. +# +# See include/freetype/ftgxval.h for the API. +BASE_EXTENSIONS += ftgxval.c + +# Multiple Master font interface. +# +# See include/freetype/ftmm.h for the API. +BASE_EXTENSIONS += ftmm.c + +# Interface for otvalid module. +# +# See include/freetype/ftotval.h for the API. +BASE_EXTENSIONS += ftotval.c + +# Support for FT_Face_CheckTrueTypePatents. +# +# See include/freetype/freetype.h for the API. +BASE_EXTENSIONS += ftpatent.c + +# Interface for accessing PFR-specific data. Needs PFR font driver. +# +# See include/freetype/ftpfr.h for the API. +BASE_EXTENSIONS += ftpfr.c + +# Path stroker. Needs `ftglyph.c'. +# +# See include/freetype/ftstroke.h for the API. +BASE_EXTENSIONS += ftstroke.c + +# Support for synthetic emboldening and slanting of fonts. Needs +# `ftbitmap.c'. +# +# See include/freetype/ftsynth.h for the API. +BASE_EXTENSIONS += ftsynth.c + +# Interface to access data specific to PostScript Type 1 and Type 2 (CFF) +# fonts. +# +# See include/freetype/t1tables.h for the API. +BASE_EXTENSIONS += fttype1.c + +# Interface for accessing data specific to Windows FNT files. Needs winfnt +# driver. +# +# See include/freetype/ftwinfnt.h for the API. +BASE_EXTENSIONS += ftwinfnt.c + +#### +#### The components `ftsystem.c' (for memory allocation and stream I/O +#### management) and `ftdebug.c' (for emitting debug messages to the user) +#### are controlled with the following variables. +#### +#### ftsystem.c: $(FTSYS_SRC) +#### ftdebug.c: $(FTDEBUG_SRC) +#### +#### Please refer to docs/CUSTOMIZE for details. +#### + + +# EOF diff --git a/Dependencies/freetype/freetype/src/autofit/afblue.c b/Dependencies/freetype/freetype/src/autofit/afblue.c new file mode 100644 index 00000000..ea83969c --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afblue.c @@ -0,0 +1,779 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/**************************************************************************** + * + * afblue.c + * + * Auto-fitter data for blue strings (body). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ + '\xF0', '\x9E', '\xA4', '\x8C', ' ', '\xF0', '\x9E', '\xA4', '\x85', ' ', '\xF0', '\x9E', '\xA4', '\x88', ' ', '\xF0', '\x9E', '\xA4', '\x8F', ' ', '\xF0', '\x9E', '\xA4', '\x94', ' ', '\xF0', '\x9E', '\xA4', '\x9A', /* 𞤌 𞤅 𞤈 𞤏 𞤔 𞤚 */ + '\0', + '\xF0', '\x9E', '\xA4', '\x82', ' ', '\xF0', '\x9E', '\xA4', '\x96', /* 𞤂 𞤖 */ + '\0', + '\xF0', '\x9E', '\xA4', '\xAC', ' ', '\xF0', '\x9E', '\xA4', '\xAE', ' ', '\xF0', '\x9E', '\xA4', '\xBB', ' ', '\xF0', '\x9E', '\xA4', '\xBC', ' ', '\xF0', '\x9E', '\xA4', '\xBE', /* 𞤬 𞤮 𞤻 𞤼 𞤾 */ + '\0', + '\xF0', '\x9E', '\xA4', '\xA4', ' ', '\xF0', '\x9E', '\xA4', '\xA8', ' ', '\xF0', '\x9E', '\xA4', '\xA9', ' ', '\xF0', '\x9E', '\xA4', '\xAD', ' ', '\xF0', '\x9E', '\xA4', '\xB4', ' ', '\xF0', '\x9E', '\xA4', '\xB8', ' ', '\xF0', '\x9E', '\xA4', '\xBA', ' ', '\xF0', '\x9E', '\xA5', '\x80', /* 𞤤 𞤨 𞤩 𞤭 𞤴 𞤸 𞤺 𞥀 */ + '\0', + '\xD8', '\xA7', ' ', '\xD8', '\xA5', ' ', '\xD9', '\x84', ' ', '\xD9', '\x83', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', /* ا إ ل ك ط ظ */ + '\0', + '\xD8', '\xAA', ' ', '\xD8', '\xAB', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', ' ', '\xD9', '\x83', /* ت ث ط ظ ك */ + '\0', + '\xD9', '\x80', /* ـ */ + '\0', + '\xD4', '\xB1', ' ', '\xD5', '\x84', ' ', '\xD5', '\x92', ' ', '\xD5', '\x8D', ' ', '\xD4', '\xB2', ' ', '\xD4', '\xB3', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x95', /* Ա Մ Ւ Ս Բ Գ Դ Օ */ + '\0', + '\xD5', '\x92', ' ', '\xD5', '\x88', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x83', ' ', '\xD5', '\x87', ' ', '\xD5', '\x8D', ' ', '\xD5', '\x8F', ' ', '\xD5', '\x95', /* Ւ Ո Դ Ճ Շ Ս Տ Օ */ + '\0', + '\xD5', '\xA5', ' ', '\xD5', '\xA7', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xB4', ' ', '\xD5', '\xBE', ' ', '\xD6', '\x86', ' ', '\xD5', '\xB3', /* ե է ի մ վ ֆ ճ */ + '\0', + '\xD5', '\xA1', ' ', '\xD5', '\xB5', ' ', '\xD6', '\x82', ' ', '\xD5', '\xBD', ' ', '\xD5', '\xA3', ' ', '\xD5', '\xB7', ' ', '\xD6', '\x80', ' ', '\xD6', '\x85', /* ա յ ւ ս գ շ ր օ */ + '\0', + '\xD5', '\xB0', ' ', '\xD5', '\xB8', ' ', '\xD5', '\xB3', ' ', '\xD5', '\xA1', ' ', '\xD5', '\xA5', ' ', '\xD5', '\xAE', ' ', '\xD5', '\xBD', ' ', '\xD6', '\x85', /* հ ո ճ ա ե ծ ս օ */ + '\0', + '\xD5', '\xA2', ' ', '\xD5', '\xA8', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xAC', ' ', '\xD5', '\xB2', ' ', '\xD5', '\xBA', ' ', '\xD6', '\x83', ' ', '\xD6', '\x81', /* բ ը ի լ ղ պ փ ց */ + '\0', + '\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', ' ', '\xF0', '\x90', '\xAC', '\x90', ' ', '\xF0', '\x90', '\xAC', '\x9B', /* 𐬀 𐬁 𐬐 𐬛 */ + '\0', + '\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', /* 𐬀 𐬁 */ + '\0', + '\xEA', '\x9A', '\xA7', ' ', '\xEA', '\x9A', '\xA8', ' ', '\xEA', '\x9B', '\x9B', ' ', '\xEA', '\x9B', '\x89', ' ', '\xEA', '\x9B', '\x81', ' ', '\xEA', '\x9B', '\x88', ' ', '\xEA', '\x9B', '\xAB', ' ', '\xEA', '\x9B', '\xAF', /* ꚧ ꚨ ꛛ ꛉ ꛁ ꛈ ꛫ ꛯ */ + '\0', + '\xEA', '\x9A', '\xAD', ' ', '\xEA', '\x9A', '\xB3', ' ', '\xEA', '\x9A', '\xB6', ' ', '\xEA', '\x9B', '\xAC', ' ', '\xEA', '\x9A', '\xA2', ' ', '\xEA', '\x9A', '\xBD', ' ', '\xEA', '\x9B', '\xAF', ' ', '\xEA', '\x9B', '\xB2', /* ꚭ ꚳ ꚶ ꛬ ꚢ ꚽ ꛯ ꛲ */ + '\0', + '\xE0', '\xA6', '\x85', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xAD', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* অ ড ত ন ব ভ ল ক */ + '\0', + '\xE0', '\xA6', '\x87', ' ', '\xE0', '\xA6', '\x9F', ' ', '\xE0', '\xA6', '\xA0', ' ', '\xE0', '\xA6', '\xBF', ' ', '\xE0', '\xA7', '\x80', ' ', '\xE0', '\xA7', '\x88', ' ', '\xE0', '\xA7', '\x97', /* ই ট ঠ ি ী ৈ ৗ */ + '\0', + '\xE0', '\xA6', '\x93', ' ', '\xE0', '\xA6', '\x8F', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* ও এ ড ত ন ব ল ক */ + '\0', + '\xE1', '\x9D', '\x90', ' ', '\xE1', '\x9D', '\x88', /* ᝐ ᝈ */ + '\0', + '\xE1', '\x9D', '\x85', ' ', '\xE1', '\x9D', '\x8A', ' ', '\xE1', '\x9D', '\x8E', /* ᝅ ᝊ ᝎ */ + '\0', + '\xE1', '\x9D', '\x82', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8C', /* ᝂ ᝃ ᝉ ᝌ */ + '\0', + '\xE1', '\x9D', '\x80', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x86', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8B', ' ', '\xE1', '\x9D', '\x8F', ' ', '\xE1', '\x9D', '\x91', /* ᝀ ᝃ ᝆ ᝉ ᝋ ᝏ ᝑ */ + '\0', + '\xE1', '\x97', '\x9C', ' ', '\xE1', '\x96', '\xB4', ' ', '\xE1', '\x90', '\x81', ' ', '\xE1', '\x92', '\xA3', ' ', '\xE1', '\x91', '\xAB', ' ', '\xE1', '\x91', '\x8E', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xB0', /* ᗜ ᖴ ᐁ ᒣ ᑫ ᑎ ᔑ ᗰ */ + '\0', + '\xE1', '\x97', '\xB6', ' ', '\xE1', '\x96', '\xB5', ' ', '\xE1', '\x92', '\xA7', ' ', '\xE1', '\x90', '\x83', ' ', '\xE1', '\x91', '\x8C', ' ', '\xE1', '\x92', '\x8D', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xA2', /* ᗶ ᖵ ᒧ ᐃ ᑌ ᒍ ᔑ ᗢ */ + '\0', + '\xE1', '\x93', '\x93', ' ', '\xE1', '\x93', '\x95', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x84', ' ', '\xE1', '\x95', '\x84', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* ᓓ ᓕ ᓀ ᓂ ᓄ ᕄ ᕆ ᘣ */ + '\0', + '\xE1', '\x95', '\x83', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x95', '\x82', ' ', '\xE1', '\x93', '\x97', ' ', '\xE1', '\x93', '\x9A', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* ᕃ ᓂ ᓀ ᕂ ᓗ ᓚ ᕆ ᘣ */ + '\0', + '\xE1', '\x90', '\xAA', ' ', '\xE1', '\x99', '\x86', ' ', '\xE1', '\xA3', '\x98', ' ', '\xE1', '\x90', '\xA2', ' ', '\xE1', '\x92', '\xBE', ' ', '\xE1', '\xA3', '\x97', ' ', '\xE1', '\x94', '\x86', /* ᐪ ᙆ ᣘ ᐢ ᒾ ᣗ ᔆ */ + '\0', + '\xE1', '\x99', '\x86', ' ', '\xE1', '\x97', '\xAE', ' ', '\xE1', '\x92', '\xBB', ' ', '\xE1', '\x90', '\x9E', ' ', '\xE1', '\x94', '\x86', ' ', '\xE1', '\x92', '\xA1', ' ', '\xE1', '\x92', '\xA2', ' ', '\xE1', '\x93', '\x91', /* ᙆ ᗮ ᒻ ᐞ ᔆ ᒡ ᒢ ᓑ */ + '\0', + '\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xAC', ' ', '\xF0', '\x90', '\x8A', '\xAD', ' ', '\xF0', '\x90', '\x8A', '\xB1', ' ', '\xF0', '\x90', '\x8A', '\xBA', ' ', '\xF0', '\x90', '\x8A', '\xBC', ' ', '\xF0', '\x90', '\x8A', '\xBF', /* 𐊧 𐊫 𐊬 𐊭 𐊱 𐊺 𐊼 𐊿 */ + '\0', + '\xF0', '\x90', '\x8A', '\xA3', ' ', '\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xB7', ' ', '\xF0', '\x90', '\x8B', '\x80', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xB8', ' ', '\xF0', '\x90', '\x8B', '\x89', /* 𐊣 𐊧 𐊷 𐋀 𐊫 𐊸 𐋉 */ + '\0', + '\xF0', '\x91', '\x84', '\x83', ' ', '\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x89', ' ', '\xF0', '\x91', '\x84', '\x99', ' ', '\xF0', '\x91', '\x84', '\x97', /* 𑄃 𑄅 𑄉 𑄙 𑄗 */ + '\0', + '\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x9B', ' ', '\xF0', '\x91', '\x84', '\x9D', ' ', '\xF0', '\x91', '\x84', '\x97', ' ', '\xF0', '\x91', '\x84', '\x93', /* 𑄅 𑄛 𑄝 𑄗 𑄓 */ + '\0', + '\xF0', '\x91', '\x84', '\x96', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x98', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x99', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA4', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA5', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', /* 𑄖𑄳𑄢 𑄘𑄳𑄢 𑄙𑄳𑄢 𑄤𑄳𑄢 𑄥𑄳𑄢 */ + '\0', + '\xE1', '\x8F', '\x86', ' ', '\xE1', '\x8E', '\xBB', ' ', '\xE1', '\x8E', '\xAC', ' ', '\xE1', '\x8F', '\x83', ' ', '\xE1', '\x8E', '\xA4', ' ', '\xE1', '\x8F', '\xA3', ' ', '\xE1', '\x8E', '\xA6', ' ', '\xE1', '\x8F', '\x95', /* Ꮖ Ꮋ Ꭼ Ꮓ Ꭴ Ꮳ Ꭶ Ꮥ */ + '\0', + '\xEA', '\xAE', '\x92', ' ', '\xEA', '\xAE', '\xA4', ' ', '\xEA', '\xAE', '\xB6', ' ', '\xEA', '\xAD', '\xB4', ' ', '\xEA', '\xAD', '\xBE', ' ', '\xEA', '\xAE', '\x97', ' ', '\xEA', '\xAE', '\x9D', ' ', '\xEA', '\xAE', '\xBF', /* ꮒ ꮤ ꮶ ꭴ ꭾ ꮗ ꮝ ꮿ */ + '\0', + '\xEA', '\xAE', '\x96', ' ', '\xEA', '\xAD', '\xBC', ' ', '\xEA', '\xAE', '\x93', ' ', '\xEA', '\xAE', '\xA0', ' ', '\xEA', '\xAE', '\xB3', ' ', '\xEA', '\xAD', '\xB6', ' ', '\xEA', '\xAE', '\xA5', ' ', '\xEA', '\xAE', '\xBB', /* ꮖ ꭼ ꮓ ꮠ ꮳ ꭶ ꮥ ꮻ */ + '\0', + '\xE1', '\x8F', '\xB8', ' ', '\xEA', '\xAE', '\x90', ' ', '\xEA', '\xAD', '\xB9', ' ', '\xEA', '\xAD', '\xBB', /* ᏸ ꮐ ꭹ ꭻ */ + '\0', + '\xE2', '\xB2', '\x8C', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\xA0', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB2', '\xA4', ' ', '\xE2', '\xB3', '\x8A', /* Ⲍ Ⲏ Ⲡ Ⳟ Ⲟ Ⲑ Ⲥ Ⳋ */ + '\0', + '\xE2', '\xB3', '\x90', ' ', '\xE2', '\xB3', '\x98', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB3', '\x9C', ' ', '\xE2', '\xB2', '\xB0', /* Ⳑ Ⳙ Ⳟ Ⲏ Ⲟ Ⲑ Ⳝ Ⲱ */ + '\0', + '\xE2', '\xB2', '\x8D', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\xA1', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB2', '\xA5', ' ', '\xE2', '\xB3', '\x8B', /* ⲍ ⲏ ⲡ ⳟ ⲟ ⲑ ⲥ ⳋ */ + '\0', + '\xE2', '\xB3', '\x91', ' ', '\xE2', '\xB3', '\x99', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB3', '\x9D', ' ', '\xE2', '\xB3', '\x92', /* ⳑ ⳙ ⳟ ⲏ ⲟ ⲑ ⳝ Ⳓ */ + '\0', + '\xF0', '\x90', '\xA0', '\x8D', ' ', '\xF0', '\x90', '\xA0', '\x99', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB1', ' ', '\xF0', '\x90', '\xA0', '\x85', ' ', '\xF0', '\x90', '\xA0', '\x93', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xA6', /* 𐠍 𐠙 𐠳 𐠱 𐠅 𐠓 𐠣 𐠦 */ + '\0', + '\xF0', '\x90', '\xA0', '\x83', ' ', '\xF0', '\x90', '\xA0', '\x8A', ' ', '\xF0', '\x90', '\xA0', '\x9B', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB5', ' ', '\xF0', '\x90', '\xA0', '\x90', /* 𐠃 𐠊 𐠛 𐠣 𐠳 𐠵 𐠐 */ + '\0', + '\xF0', '\x90', '\xA0', '\x88', ' ', '\xF0', '\x90', '\xA0', '\x8F', ' ', '\xF0', '\x90', '\xA0', '\x96', /* 𐠈 𐠏 𐠖 */ + '\0', + '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\x9F', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б В Е П З О С Э */ + '\0', + '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\xA8', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б В Е Ш З О С Э */ + '\0', + '\xD1', '\x85', ' ', '\xD0', '\xBF', ' ', '\xD0', '\xBD', ' ', '\xD1', '\x88', ' ', '\xD0', '\xB5', ' ', '\xD0', '\xB7', ' ', '\xD0', '\xBE', ' ', '\xD1', '\x81', /* х п н ш е з о с */ + '\0', + '\xD1', '\x80', ' ', '\xD1', '\x83', ' ', '\xD1', '\x84', /* р у ф */ + '\0', + '\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x8B', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x91', /* 𐐂 𐐄 𐐋 𐐗 𐐑 */ + '\0', + '\xF0', '\x90', '\x90', '\x80', ' ', '\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x9B', /* 𐐀 𐐂 𐐄 𐐗 𐐛 */ + '\0', + '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xB3', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x90', '\xB9', /* 𐐪 𐐬 𐐳 𐐿 𐐹 */ + '\0', + '\xF0', '\x90', '\x90', '\xA8', ' ', '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x91', '\x83', /* 𐐨 𐐪 𐐬 𐐿 𐑃 */ + '\0', + '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xA8', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x89', ' ', '\xE0', '\xA4', '\x9B', ' ', '\xE0', '\xA4', '\x9F', ' ', '\xE0', '\xA4', '\xA0', ' ', '\xE0', '\xA4', '\xA1', /* क न म उ छ ट ठ ड */ + '\0', + '\xE0', '\xA4', '\x88', ' ', '\xE0', '\xA4', '\x90', ' ', '\xE0', '\xA4', '\x93', ' ', '\xE0', '\xA4', '\x94', ' ', '\xE0', '\xA4', '\xBF', ' ', '\xE0', '\xA5', '\x80', ' ', '\xE0', '\xA5', '\x8B', ' ', '\xE0', '\xA5', '\x8C', /* ई ऐ ओ औ ि ी ो ौ */ + '\0', + '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6', /* क म अ आ थ ध भ श */ + '\0', + '\xE0', '\xA5', '\x81', ' ', '\xE0', '\xA5', '\x83', /* ु ृ */ + '\0', + '\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\x83', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x8D', '\x90', ' ', '\xE1', '\x88', '\x9B', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x8B', ' ', '\xE1', '\x8B', '\x90', /* ሀ ሃ ዘ ፐ ማ በ ዋ ዐ */ + '\0', + '\xE1', '\x88', '\x88', ' ', '\xE1', '\x88', '\x90', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\xAA', ' ', '\xE1', '\x8B', '\x90', ' ', '\xE1', '\x8C', '\xA8', /* ለ ሐ በ ዘ ሀ ሪ ዐ ጨ */ + '\0', + '\xE1', '\x83', '\x92', ' ', '\xE1', '\x83', '\x93', ' ', '\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x97', ' ', '\xE1', '\x83', '\x98', ' ', '\xE1', '\x83', '\x9D', ' ', '\xE1', '\x83', '\xA6', /* გ დ ე ვ თ ი ო ღ */ + '\0', + '\xE1', '\x83', '\x90', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xAB', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\x9E', /* ა ზ მ ს შ ძ ხ პ */ + '\0', + '\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xA9', ' ', '\xE1', '\x83', '\xAC', /* ს ხ ქ ზ მ შ ჩ წ */ + '\0', + '\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x9F', ' ', '\xE1', '\x83', '\xA2', ' ', '\xE1', '\x83', '\xA3', ' ', '\xE1', '\x83', '\xA4', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\xA7', /* ე ვ ჟ ტ უ ფ ქ ყ */ + '\0', + '\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xB9', ' ', '\xE1', '\x82', '\xBC', ' ', '\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xB3', ' ', '\xE1', '\x82', '\xBA', /* Ⴑ Ⴇ Ⴙ Ⴜ Ⴄ Ⴅ Ⴓ Ⴚ */ + '\0', + '\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xA8', ' ', '\xE1', '\x82', '\xA6', ' ', '\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xAA', ' ', '\xE1', '\x82', '\xAB', /* Ⴄ Ⴅ Ⴇ Ⴈ Ⴆ Ⴑ Ⴊ Ⴋ */ + '\0', + '\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x97', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x87', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x96', /* ⴁ ⴗ ⴂ ⴄ ⴅ ⴇ ⴔ ⴖ */ + '\0', + '\xE2', '\xB4', '\x88', ' ', '\xE2', '\xB4', '\x8C', ' ', '\xE2', '\xB4', '\x96', ' ', '\xE2', '\xB4', '\x8E', ' ', '\xE2', '\xB4', '\x83', ' ', '\xE2', '\xB4', '\x86', ' ', '\xE2', '\xB4', '\x8B', ' ', '\xE2', '\xB4', '\xA2', /* ⴈ ⴌ ⴖ ⴎ ⴃ ⴆ ⴋ ⴢ */ + '\0', + '\xE2', '\xB4', '\x90', ' ', '\xE2', '\xB4', '\x91', ' ', '\xE2', '\xB4', '\x93', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x99', ' ', '\xE2', '\xB4', '\x9B', ' ', '\xE2', '\xB4', '\xA1', ' ', '\xE2', '\xB4', '\xA3', /* ⴐ ⴑ ⴓ ⴕ ⴙ ⴛ ⴡ ⴣ */ + '\0', + '\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x98', ' ', '\xE2', '\xB4', '\x9D', /* ⴄ ⴅ ⴔ ⴕ ⴁ ⴂ ⴘ ⴝ */ + '\0', + '\xE1', '\xB2', '\x9C', ' ', '\xE1', '\xB2', '\x9F', ' ', '\xE1', '\xB2', '\xB3', ' ', '\xE1', '\xB2', '\xB8', ' ', '\xE1', '\xB2', '\x92', ' ', '\xE1', '\xB2', '\x94', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xB4', /* Ნ Ჟ Ჳ Ჸ Გ Ე Ო Ჴ */ + '\0', + '\xE1', '\xB2', '\x98', ' ', '\xE1', '\xB2', '\xB2', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xA9', ' ', '\xE1', '\xB2', '\x9B', ' ', '\xE1', '\xB2', '\xA8', ' ', '\xE1', '\xB2', '\xAF', ' ', '\xE1', '\xB2', '\xBD', /* Ი Ჲ Ო Ჩ Მ Შ Ჯ Ჽ */ + '\0', + '\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x94', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\xAB', ' ', '\xE2', '\xB0', '\x8B', /* Ⰵ Ⱄ Ⱚ Ⰴ Ⰲ Ⰺ Ⱛ Ⰻ */ + '\0', + '\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x9E', ' ', '\xE2', '\xB0', '\xA1', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\x94', /* Ⰵ Ⰴ Ⰲ Ⱚ Ⱎ Ⱑ Ⰺ Ⱄ */ + '\0', + '\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB1', '\x84', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x9B', ' ', '\xE2', '\xB0', '\xBB', /* ⰵ ⱄ ⱚ ⰴ ⰲ ⰺ ⱛ ⰻ */ + '\0', + '\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB1', '\x8E', ' ', '\xE2', '\xB1', '\x91', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x84', /* ⰵ ⰴ ⰲ ⱚ ⱎ ⱑ ⰺ ⱄ */ + '\0', + '\xF0', '\x90', '\x8C', '\xB2', ' ', '\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8D', '\x80', ' ', '\xF0', '\x90', '\x8D', '\x84', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', ' ', '\xF0', '\x90', '\x8C', '\xBE', /* 𐌲 𐌶 𐍀 𐍄 𐌴 𐍃 𐍈 𐌾 */ + '\0', + '\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', /* 𐌶 𐌴 𐍃 𐍈 */ + '\0', + '\xCE', '\x93', ' ', '\xCE', '\x92', ' ', '\xCE', '\x95', ' ', '\xCE', '\x96', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', ' ', '\xCE', '\xA9', /* Γ Β Ε Ζ Θ Ο Ω */ + '\0', + '\xCE', '\x92', ' ', '\xCE', '\x94', ' ', '\xCE', '\x96', ' ', '\xCE', '\x9E', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', /* Β Δ Ζ Ξ Θ Ο */ + '\0', + '\xCE', '\xB2', ' ', '\xCE', '\xB8', ' ', '\xCE', '\xB4', ' ', '\xCE', '\xB6', ' ', '\xCE', '\xBB', ' ', '\xCE', '\xBE', /* β θ δ ζ λ ξ */ + '\0', + '\xCE', '\xB1', ' ', '\xCE', '\xB5', ' ', '\xCE', '\xB9', ' ', '\xCE', '\xBF', ' ', '\xCF', '\x80', ' ', '\xCF', '\x83', ' ', '\xCF', '\x84', ' ', '\xCF', '\x89', /* α ε ι ο π σ τ ω */ + '\0', + '\xCE', '\xB2', ' ', '\xCE', '\xB3', ' ', '\xCE', '\xB7', ' ', '\xCE', '\xBC', ' ', '\xCF', '\x81', ' ', '\xCF', '\x86', ' ', '\xCF', '\x87', ' ', '\xCF', '\x88', /* β γ η μ ρ φ χ ψ */ + '\0', + '\xE0', '\xAA', '\xA4', ' ', '\xE0', '\xAA', '\xA8', ' ', '\xE0', '\xAA', '\x8B', ' ', '\xE0', '\xAA', '\x8C', ' ', '\xE0', '\xAA', '\x9B', ' ', '\xE0', '\xAA', '\x9F', ' ', '\xE0', '\xAA', '\xB0', ' ', '\xE0', '\xAB', '\xA6', /* ત ન ઋ ઌ છ ટ ર ૦ */ + '\0', + '\xE0', '\xAA', '\x96', ' ', '\xE0', '\xAA', '\x97', ' ', '\xE0', '\xAA', '\x98', ' ', '\xE0', '\xAA', '\x9E', ' ', '\xE0', '\xAA', '\x87', ' ', '\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\xA0', ' ', '\xE0', '\xAA', '\x9C', /* ખ ગ ઘ ઞ ઇ ઈ ઠ જ */ + '\0', + '\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\x8A', ' ', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB2', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB6', '\xE0', '\xAB', '\x8D', '\xE0', '\xAA', '\x9A', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\x9C', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\xB8', '\xE0', '\xAB', '\x80', /* ઈ ઊ િ ી લી શ્ચિ જિ સી */ + '\0', + '\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAB', '\x84', ' ', '\xE0', '\xAA', '\x96', '\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x84', /* ુ ૃ ૄ ખુ છૃ છૄ */ + '\0', + '\xE0', '\xAB', '\xA6', ' ', '\xE0', '\xAB', '\xA7', ' ', '\xE0', '\xAB', '\xA8', ' ', '\xE0', '\xAB', '\xA9', ' ', '\xE0', '\xAB', '\xAD', /* ૦ ૧ ૨ ૩ ૭ */ + '\0', + '\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */ + '\0', + '\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */ + '\0', + '\xE0', '\xA8', '\x87', ' ', '\xE0', '\xA8', '\x88', ' ', '\xE0', '\xA8', '\x89', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA9', '\xB3', ' ', '\xE0', '\xA8', '\xBF', ' ', '\xE0', '\xA9', '\x80', /* ਇ ਈ ਉ ਏ ਓ ੳ ਿ ੀ */ + '\0', + '\xE0', '\xA8', '\x85', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA0', ' ', '\xE0', '\xA8', '\xB0', ' ', '\xE0', '\xA8', '\xB8', /* ਅ ਏ ਓ ਗ ਜ ਠ ਰ ਸ */ + '\0', + '\xE0', '\xA9', '\xA6', ' ', '\xE0', '\xA9', '\xA7', ' ', '\xE0', '\xA9', '\xA8', ' ', '\xE0', '\xA9', '\xA9', ' ', '\xE0', '\xA9', '\xAD', /* ੦ ੧ ੨ ੩ ੭ */ + '\0', + '\xD7', '\x91', ' ', '\xD7', '\x93', ' ', '\xD7', '\x94', ' ', '\xD7', '\x97', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', /* ב ד ה ח ך כ ם ס */ + '\0', + '\xD7', '\x91', ' ', '\xD7', '\x98', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', ' ', '\xD7', '\xA6', /* ב ט כ ם ס צ */ + '\0', + '\xD7', '\xA7', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9F', ' ', '\xD7', '\xA3', ' ', '\xD7', '\xA5', /* ק ך ן ף ץ */ + '\0', + '\xE0', '\xB2', '\x87', ' ', '\xE0', '\xB2', '\x8A', ' ', '\xE0', '\xB2', '\x90', ' ', '\xE0', '\xB2', '\xA3', ' ', '\xE0', '\xB2', '\xB8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA6', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xB0', '\xE0', '\xB2', '\xBE', /* ಇ ಊ ಐ ಣ ಸಾ ನಾ ದಾ ರಾ */ + '\0', + '\xE0', '\xB2', '\x85', ' ', '\xE0', '\xB2', '\x89', ' ', '\xE0', '\xB2', '\x8E', ' ', '\xE0', '\xB2', '\xB2', ' ', '\xE0', '\xB3', '\xA6', ' ', '\xE0', '\xB3', '\xA8', ' ', '\xE0', '\xB3', '\xAC', ' ', '\xE0', '\xB3', '\xAD', /* ಅ ಉ ಎ ಲ ೦ ೨ ೬ ೭ */ + '\0', + '\xEA', '\xA4', '\x85', ' ', '\xEA', '\xA4', '\x8F', ' ', '\xEA', '\xA4', '\x81', ' ', '\xEA', '\xA4', '\x8B', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', /* ꤅ ꤏ ꤁ ꤋ ꤀ ꤍ */ + '\0', + '\xEA', '\xA4', '\x88', ' ', '\xEA', '\xA4', '\x98', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', ' ', '\xEA', '\xA4', '\xA2', /* ꤈ ꤘ ꤀ ꤍ ꤢ */ + '\0', + '\xEA', '\xA4', '\x96', ' ', '\xEA', '\xA4', '\xA1', /* ꤖ ꤡ */ + '\0', + '\xEA', '\xA4', '\x91', ' ', '\xEA', '\xA4', '\x9C', ' ', '\xEA', '\xA4', '\x9E', /* ꤑ ꤜ ꤞ */ + '\0', + '\xEA', '\xA4', '\x91', '\xEA', '\xA4', '\xAC', ' ', '\xEA', '\xA4', '\x9C', '\xEA', '\xA4', '\xAD', ' ', '\xEA', '\xA4', '\x94', '\xEA', '\xA4', '\xAC', /* ꤑ꤬ ꤜ꤭ ꤔ꤬ */ + '\0', + '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x91', ' ', '\xE1', '\x9E', '\x93', ' ', '\xE1', '\x9E', '\xA7', ' ', '\xE1', '\x9E', '\xA9', ' ', '\xE1', '\x9E', '\xB6', /* ខ ទ ន ឧ ឩ ា */ + '\0', + '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x80', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x82', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x90', /* ក្ក ក្ខ ក្គ ក្ថ */ + '\0', + '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x83', ' ', '\xE1', '\x9E', '\x85', ' ', '\xE1', '\x9E', '\x8B', ' ', '\xE1', '\x9E', '\x94', ' ', '\xE1', '\x9E', '\x98', ' ', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xB2', /* ខ ឃ ច ឋ ប ម យ ឲ */ + '\0', + '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', ' ', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\xB2', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xA2', '\xE1', '\x9E', '\xBF', /* ត្រ រៀ ឲ្យ អឿ */ + '\0', + '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x83', ' ', '\xE1', '\x9E', '\x84', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x85', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9E', '\xBF', ' ', '\xE1', '\x9E', '\x9B', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9E', '\xBF', /* ន្ត្រៃ ង្ខ្យ ក្បៀ ច្រៀ ន្តឿ ល្បឿ */ + '\0', + '\xE1', '\xA7', '\xA0', ' ', '\xE1', '\xA7', '\xA1', /* ᧠ ᧡ */ + '\0', + '\xE1', '\xA7', '\xB6', ' ', '\xE1', '\xA7', '\xB9', /* ᧶ ᧹ */ + '\0', + '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\x94', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\xA1', ' ', '\xE0', '\xBA', '\xA5', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\x87', /* າ ດ ອ ມ ລ ວ ຣ ງ */ + '\0', + '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\x9A', ' ', '\xE0', '\xBA', '\x8D', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\xAE', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA2', /* າ ອ ບ ຍ ຣ ຮ ວ ຢ */ + '\0', + '\xE0', '\xBA', '\x9B', ' ', '\xE0', '\xBA', '\xA2', ' ', '\xE0', '\xBA', '\x9F', ' ', '\xE0', '\xBA', '\x9D', /* ປ ຢ ຟ ຝ */ + '\0', + '\xE0', '\xBB', '\x82', ' ', '\xE0', '\xBB', '\x84', ' ', '\xE0', '\xBB', '\x83', /* ໂ ໄ ໃ */ + '\0', + '\xE0', '\xBA', '\x87', ' ', '\xE0', '\xBA', '\x8A', ' ', '\xE0', '\xBA', '\x96', ' ', '\xE0', '\xBA', '\xBD', ' ', '\xE0', '\xBB', '\x86', ' ', '\xE0', '\xBA', '\xAF', /* ງ ຊ ຖ ຽ ໆ ຯ */ + '\0', + 'T', ' ', 'H', ' ', 'E', ' ', 'Z', ' ', 'O', ' ', 'C', ' ', 'Q', ' ', 'S', /* T H E Z O C Q S */ + '\0', + 'H', ' ', 'E', ' ', 'Z', ' ', 'L', ' ', 'O', ' ', 'C', ' ', 'U', ' ', 'S', /* H E Z L O C U S */ + '\0', + 'f', ' ', 'i', ' ', 'j', ' ', 'k', ' ', 'd', ' ', 'b', ' ', 'h', /* f i j k d b h */ + '\0', + 'u', ' ', 'v', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* u v x z o e s c */ + '\0', + 'n', ' ', 'r', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* n r x z o e s c */ + '\0', + 'p', ' ', 'q', ' ', 'g', ' ', 'j', ' ', 'y', /* p q g j y */ + '\0', + '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x85', ' ', '\xE2', '\x82', '\x87', ' ', '\xE2', '\x82', '\x88', /* ₀ ₃ ₅ ₇ ₈ */ + '\0', + '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x81', ' ', '\xE2', '\x82', '\x82', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x88', /* ₀ ₁ ₂ ₃ ₈ */ + '\0', + '\xE1', '\xB5', '\xA2', ' ', '\xE2', '\xB1', '\xBC', ' ', '\xE2', '\x82', '\x95', ' ', '\xE2', '\x82', '\x96', ' ', '\xE2', '\x82', '\x97', /* ᵢ ⱼ ₕ ₖ ₗ */ + '\0', + '\xE2', '\x82', '\x90', ' ', '\xE2', '\x82', '\x91', ' ', '\xE2', '\x82', '\x92', ' ', '\xE2', '\x82', '\x93', ' ', '\xE2', '\x82', '\x99', ' ', '\xE2', '\x82', '\x9B', ' ', '\xE1', '\xB5', '\xA5', ' ', '\xE1', '\xB5', '\xA4', ' ', '\xE1', '\xB5', '\xA3', /* ₐ ₑ ₒ ₓ ₙ ₛ ᵥ ᵤ ᵣ */ + '\0', + '\xE1', '\xB5', '\xA6', ' ', '\xE1', '\xB5', '\xA7', ' ', '\xE1', '\xB5', '\xA8', ' ', '\xE1', '\xB5', '\xA9', ' ', '\xE2', '\x82', '\x9A', /* ᵦ ᵧ ᵨ ᵩ ₚ */ + '\0', + '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB3', ' ', '\xE2', '\x81', '\xB5', ' ', '\xE2', '\x81', '\xB7', ' ', '\xE1', '\xB5', '\x80', ' ', '\xE1', '\xB4', '\xB4', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xBC', /* ⁰ ³ ⁵ ⁷ ᵀ ᴴ ᴱ ᴼ */ + '\0', + '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB9', ' ', '\xC2', '\xB2', ' ', '\xC2', '\xB3', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xB8', ' ', '\xE1', '\xB4', '\xBC', ' ', '\xE1', '\xB5', '\x81', /* ⁰ ¹ ² ³ ᴱ ᴸ ᴼ ᵁ */ + '\0', + '\xE1', '\xB5', '\x87', ' ', '\xE1', '\xB5', '\x88', ' ', '\xE1', '\xB5', '\x8F', ' ', '\xCA', '\xB0', ' ', '\xCA', '\xB2', ' ', '\xE1', '\xB6', '\xA0', ' ', '\xE2', '\x81', '\xB1', /* ᵇ ᵈ ᵏ ʰ ʲ ᶠ ⁱ */ + '\0', + '\xE1', '\xB5', '\x89', ' ', '\xE1', '\xB5', '\x92', ' ', '\xCA', '\xB3', ' ', '\xCB', '\xA2', ' ', '\xCB', '\xA3', ' ', '\xE1', '\xB6', '\x9C', ' ', '\xE1', '\xB6', '\xBB', /* ᵉ ᵒ ʳ ˢ ˣ ᶜ ᶻ */ + '\0', + '\xE1', '\xB5', '\x96', ' ', '\xCA', '\xB8', ' ', '\xE1', '\xB5', '\x8D', /* ᵖ ʸ ᵍ */ + '\0', + '\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\xA7', ' ', '\xEA', '\x93', '\xB1', ' ', '\xEA', '\x93', '\xB6', ' ', '\xEA', '\x93', '\xA9', ' ', '\xEA', '\x93', '\x9A', ' ', '\xEA', '\x93', '\xB5', ' ', '\xEA', '\x93', '\xB3', /* ꓡ ꓧ ꓱ ꓶ ꓩ ꓚ ꓵ ꓳ */ + '\0', + '\xEA', '\x93', '\x95', ' ', '\xEA', '\x93', '\x9C', ' ', '\xEA', '\x93', '\x9E', ' ', '\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\x9B', ' ', '\xEA', '\x93', '\xA2', ' ', '\xEA', '\x93', '\xB3', ' ', '\xEA', '\x93', '\xB4', /* ꓕ ꓜ ꓞ ꓡ ꓛ ꓢ ꓳ ꓴ */ + '\0', + '\xE0', '\xB4', '\x92', ' ', '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xB1', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', ' ', '\xE0', '\xB4', '\x9A', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\xAA', /* ഒ ട ഠ റ ച പ ച്ച പ്പ */ + '\0', + '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xA7', ' ', '\xE0', '\xB4', '\xB6', ' ', '\xE0', '\xB4', '\x98', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xA5', ' ', '\xE0', '\xB4', '\xB2', /* ട ഠ ധ ശ ഘ ച ഥ ല */ + '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x9F', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹟 */ + '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x92', ' ', '\xF0', '\x96', '\xB9', '\x93', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹒 𖹓 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA4', ' ', '\xF0', '\x96', '\xB9', '\xAC', ' ', '\xF0', '\x96', '\xB9', '\xA7', ' ', '\xF0', '\x96', '\xB9', '\xB4', ' ', '\xF0', '\x96', '\xB9', '\xB6', ' ', '\xF0', '\x96', '\xB9', '\xBE', /* 𖹤 𖹬 𖹧 𖹴 𖹶 𖹾 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB9', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAE', /* 𖹠 𖹡 𖹢 𖹹 𖹳 𖹮 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAD', ' ', '\xF0', '\x96', '\xB9', '\xBD', /* 𖹠 𖹡 𖹢 𖹳 𖹭 𖹽 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA5', ' ', '\xF0', '\x96', '\xB9', '\xA8', ' ', '\xF0', '\x96', '\xB9', '\xA9', /* 𖹥 𖹨 𖹩 */ + '\0', + '\xF0', '\x96', '\xBA', '\x80', ' ', '\xF0', '\x96', '\xBA', '\x85', ' ', '\xF0', '\x96', '\xBA', '\x88', ' ', '\xF0', '\x96', '\xBA', '\x84', ' ', '\xF0', '\x96', '\xBA', '\x8D', /* 𖺀 𖺅 𖺈 𖺄 𖺍 */ + '\0', + '\xE1', '\xA0', '\xB3', ' ', '\xE1', '\xA0', '\xB4', ' ', '\xE1', '\xA0', '\xB6', ' ', '\xE1', '\xA0', '\xBD', ' ', '\xE1', '\xA1', '\x82', ' ', '\xE1', '\xA1', '\x8A', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xA1', '\xE2', '\x80', '\x8D', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xB3', '\xE2', '\x80', '\x8D', /* ᠳ ᠴ ᠶ ᠽ ᡂ ᡊ ‍ᡡ‍ ‍ᡳ‍ */ + '\0', + '\xE1', '\xA1', '\x83', /* ᡃ */ + '\0', + '\xE1', '\x80', '\x81', ' ', '\xE1', '\x80', '\x82', ' ', '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\xA5', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* ခ ဂ င ဒ ဝ ၥ ၊ ။ */ + '\0', + '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x8E', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x95', ' ', '\xE1', '\x80', '\x97', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* င ဎ ဒ ပ ဗ ဝ ၊ ။ */ + '\0', + '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xBC', ' ', '\xE1', '\x81', '\x8D', ' ', '\xE1', '\x81', '\x8F', ' ', '\xE1', '\x81', '\x86', ' ', '\xE1', '\x80', '\xAB', ' ', '\xE1', '\x80', '\xAD', /* ဩ ြ ၍ ၏ ၆ ါ ိ */ + '\0', + '\xE1', '\x80', '\x89', ' ', '\xE1', '\x80', '\x8A', ' ', '\xE1', '\x80', '\xA5', ' ', '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xA8', ' ', '\xE1', '\x81', '\x82', ' ', '\xE1', '\x81', '\x85', ' ', '\xE1', '\x81', '\x89', /* ဉ ည ဥ ဩ ဨ ၂ ၅ ၉ */ + '\0', + '\xDF', '\x90', ' ', '\xDF', '\x89', ' ', '\xDF', '\x92', ' ', '\xDF', '\x9F', ' ', '\xDF', '\x96', ' ', '\xDF', '\x9C', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ߐ ߉ ߒ ߟ ߖ ߜ ߠ ߥ */ + '\0', + '\xDF', '\x80', ' ', '\xDF', '\x98', ' ', '\xDF', '\xA1', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ߀ ߘ ߡ ߠ ߥ */ + '\0', + '\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ߏ ߛ ߋ */ + '\0', + '\xDF', '\x8E', ' ', '\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ߎ ߏ ߛ ߋ */ + '\0', + '\xE1', '\xB1', '\x9B', ' ', '\xE1', '\xB1', '\x9C', ' ', '\xE1', '\xB1', '\x9D', ' ', '\xE1', '\xB1', '\xA1', ' ', '\xE1', '\xB1', '\xA2', ' ', '\xE1', '\xB1', '\xA5', /* ᱛ ᱜ ᱝ ᱡ ᱢ ᱥ */ + '\0', + '\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\x98', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* 𐰗 𐰘 𐰧 */ + '\0', + '\xF0', '\x90', '\xB0', '\x89', ' ', '\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\xA6', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* 𐰉 𐰗 𐰦 𐰧 */ + '\0', + '\xF0', '\x90', '\x92', '\xBE', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x92', ' ', '\xF0', '\x90', '\x93', '\x93', ' ', '\xF0', '\x90', '\x92', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xB5', ' ', '\xF0', '\x90', '\x93', '\x86', /* 𐒾 𐓍 𐓒 𐓓 𐒻 𐓂 𐒵 𐓆 */ + '\0', + '\xF0', '\x90', '\x92', '\xB0', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xBF', ' ', '\xF0', '\x90', '\x93', '\x8E', ' ', '\xF0', '\x90', '\x92', '\xB9', /* 𐒰 𐓍 𐓂 𐒿 𐓎 𐒹 */ + '\0', + '\xF0', '\x90', '\x92', '\xBC', ' ', '\xF0', '\x90', '\x92', '\xBD', ' ', '\xF0', '\x90', '\x92', '\xBE', /* 𐒼 𐒽 𐒾 */ + '\0', + '\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xB6', ' ', '\xF0', '\x90', '\x93', '\xBA', ' ', '\xF0', '\x90', '\x93', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x9D', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xAE', /* 𐓵 𐓶 𐓺 𐓻 𐓝 𐓣 𐓪 𐓮 */ + '\0', + '\xF0', '\x90', '\x93', '\x98', ' ', '\xF0', '\x90', '\x93', '\x9A', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xA1', ' ', '\xF0', '\x90', '\x93', '\xA7', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xB6', /* 𐓘 𐓚 𐓣 𐓵 𐓡 𐓧 𐓪 𐓶 */ + '\0', + '\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA6', ' ', '\xF0', '\x90', '\x93', '\xB8', ' ', '\xF0', '\x90', '\x93', '\xB9', ' ', '\xF0', '\x90', '\x93', '\x9B', /* 𐓤 𐓦 𐓸 𐓹 𐓛 */ + '\0', + '\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA5', ' ', '\xF0', '\x90', '\x93', '\xA6', /* 𐓤 𐓥 𐓦 */ + '\0', + '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x89', ' ', '\xF0', '\x90', '\x92', '\x90', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\x98', ' ', '\xF0', '\x90', '\x92', '\x9B', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA3', /* 𐒆 𐒉 𐒐 𐒒 𐒘 𐒛 𐒠 𐒣 */ + '\0', + '\xF0', '\x90', '\x92', '\x80', ' ', '\xF0', '\x90', '\x92', '\x82', ' ', '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x88', ' ', '\xF0', '\x90', '\x92', '\x8A', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA9', /* 𐒀 𐒂 𐒆 𐒈 𐒊 𐒒 𐒠 𐒩 */ + '\0', + '\xF0', '\x90', '\xB4', '\x83', ' ', '\xF0', '\x90', '\xB4', '\x80', ' ', '\xF0', '\x90', '\xB4', '\x86', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', /* 𐴃 𐴀 𐴆 𐴖 𐴕 */ + '\0', + '\xF0', '\x90', '\xB4', '\x94', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', ' ', '\xF0', '\x90', '\xB4', '\x91', ' ', '\xF0', '\x90', '\xB4', '\x90', /* 𐴔 𐴖 𐴕 𐴑 𐴐 */ + '\0', + '\xD9', '\x80', /* ـ */ + '\0', + '\xEA', '\xA2', '\x9C', ' ', '\xEA', '\xA2', '\x9E', ' ', '\xEA', '\xA2', '\xB3', ' ', '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\x96', ' ', '\xEA', '\xA2', '\x92', ' ', '\xEA', '\xA2', '\x9D', ' ', '\xEA', '\xA2', '\x9B', /* ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ꢝ ꢛ */ + '\0', + '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\xA8', ' ', '\xEA', '\xA2', '\xBA', ' ', '\xEA', '\xA2', '\xA4', ' ', '\xEA', '\xA2', '\x8E', /* ꢂ ꢨ ꢺ ꢤ ꢎ */ + '\0', + '\xF0', '\x90', '\x91', '\x95', ' ', '\xF0', '\x90', '\x91', '\x99', /* 𐑕 𐑙 */ + '\0', + '\xF0', '\x90', '\x91', '\x94', ' ', '\xF0', '\x90', '\x91', '\x96', ' ', '\xF0', '\x90', '\x91', '\x97', ' ', '\xF0', '\x90', '\x91', '\xB9', ' ', '\xF0', '\x90', '\x91', '\xBB', /* 𐑔 𐑖 𐑗 𐑹 𐑻 */ + '\0', + '\xF0', '\x90', '\x91', '\x9F', ' ', '\xF0', '\x90', '\x91', '\xA3', /* 𐑟 𐑣 */ + '\0', + '\xF0', '\x90', '\x91', '\xB1', ' ', '\xF0', '\x90', '\x91', '\xB2', ' ', '\xF0', '\x90', '\x91', '\xB3', ' ', '\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xB8', ' ', '\xF0', '\x90', '\x91', '\xBA', ' ', '\xF0', '\x90', '\x91', '\xBC', /* 𐑱 𐑲 𐑳 𐑴 𐑸 𐑺 𐑼 */ + '\0', + '\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xBB', ' ', '\xF0', '\x90', '\x91', '\xB9', /* 𐑴 𐑻 𐑹 */ + '\0', + '\xE0', '\xB6', '\x89', ' ', '\xE0', '\xB6', '\x9A', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\xB4', ' ', '\xE0', '\xB6', '\xBA', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB7', '\x86', /* ඉ ක ඝ ඳ ප ය ල ෆ */ + '\0', + '\xE0', '\xB6', '\x91', ' ', '\xE0', '\xB6', '\x94', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xA2', ' ', '\xE0', '\xB6', '\xA7', ' ', '\xE0', '\xB6', '\xAE', ' ', '\xE0', '\xB6', '\xB0', ' ', '\xE0', '\xB6', '\xBB', /* එ ඔ ඝ ජ ට ථ ධ ර */ + '\0', + '\xE0', '\xB6', '\xAF', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\x8B', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x96', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xB6', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xAF', '\xE0', '\xB7', '\x94', /* ද ඳ උ ල තූ තු බු දු */ + '\0', + '\xE1', '\xAE', '\x8B', ' ', '\xE1', '\xAE', '\x9E', ' ', '\xE1', '\xAE', '\xAE', ' ', '\xE1', '\xAE', '\xBD', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x88', /* ᮋ ᮞ ᮮ ᮽ ᮰ ᮈ */ + '\0', + '\xE1', '\xAE', '\x84', ' ', '\xE1', '\xAE', '\x94', ' ', '\xE1', '\xAE', '\x95', ' ', '\xE1', '\xAE', '\x97', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x86', ' ', '\xE1', '\xAE', '\x88', ' ', '\xE1', '\xAE', '\x89', /* ᮄ ᮔ ᮕ ᮗ ᮰ ᮆ ᮈ ᮉ */ + '\0', + '\xE1', '\xAE', '\xBC', ' ', '\xE1', '\xB3', '\x84', /* ᮼ ᳄ */ + '\0', + '\xEA', '\xAA', '\x86', ' ', '\xEA', '\xAA', '\x94', ' ', '\xEA', '\xAA', '\x92', ' ', '\xEA', '\xAA', '\x96', ' ', '\xEA', '\xAA', '\xAB', /* ꪆ ꪔ ꪒ ꪖ ꪫ */ + '\0', + '\xEA', '\xAA', '\x89', ' ', '\xEA', '\xAA', '\xAB', ' ', '\xEA', '\xAA', '\xAE', /* ꪉ ꪫ ꪮ */ + '\0', + '\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x92', ' ', '\xE0', '\xAE', '\x93', ' ', '\xE0', '\xAE', '\xB1', ' ', '\xE0', '\xAE', '\x88', ' ', '\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9A', /* உ ஒ ஓ ற ஈ க ங ச */ + '\0', + '\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x9A', ' ', '\xE0', '\xAE', '\xB2', ' ', '\xE0', '\xAE', '\xB6', ' ', '\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9F', ' ', '\xE0', '\xAE', '\xAA', /* க ச ல ஶ உ ங ட ப */ + '\0', + '\xE0', '\xB0', '\x87', ' ', '\xE0', '\xB0', '\x8C', ' ', '\xE0', '\xB0', '\x99', ' ', '\xE0', '\xB0', '\x9E', ' ', '\xE0', '\xB0', '\xA3', ' ', '\xE0', '\xB0', '\xB1', ' ', '\xE0', '\xB1', '\xAF', /* ఇ ఌ ఙ ఞ ణ ఱ ౯ */ + '\0', + '\xE0', '\xB0', '\x85', ' ', '\xE0', '\xB0', '\x95', ' ', '\xE0', '\xB0', '\x9A', ' ', '\xE0', '\xB0', '\xB0', ' ', '\xE0', '\xB0', '\xBD', ' ', '\xE0', '\xB1', '\xA8', ' ', '\xE0', '\xB1', '\xAC', /* అ క చ ర ఽ ౨ ౬ */ + '\0', + '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB9', '\x80', ' ', '\xE0', '\xB9', '\x81', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\x81', ' ', '\xE0', '\xB8', '\xB2', /* บ เ แ อ ก า */ + '\0', + '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\xA9', ' ', '\xE0', '\xB8', '\xAF', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\xA2', ' ', '\xE0', '\xB8', '\xAE', /* บ ป ษ ฯ อ ย ฮ */ + '\0', + '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\x9D', ' ', '\xE0', '\xB8', '\x9F', /* ป ฝ ฟ */ + '\0', + '\xE0', '\xB9', '\x82', ' ', '\xE0', '\xB9', '\x83', ' ', '\xE0', '\xB9', '\x84', /* โ ใ ไ */ + '\0', + '\xE0', '\xB8', '\x8E', ' ', '\xE0', '\xB8', '\x8F', ' ', '\xE0', '\xB8', '\xA4', ' ', '\xE0', '\xB8', '\xA6', /* ฎ ฏ ฤ ฦ */ + '\0', + '\xE0', '\xB8', '\x8D', ' ', '\xE0', '\xB8', '\x90', /* ญ ฐ */ + '\0', + '\xE0', '\xB9', '\x90', ' ', '\xE0', '\xB9', '\x91', ' ', '\xE0', '\xB9', '\x93', /* ๐ ๑ ๓ */ + '\0', + '\xE2', '\xB5', '\x94', ' ', '\xE2', '\xB5', '\x99', ' ', '\xE2', '\xB5', '\x9B', ' ', '\xE2', '\xB5', '\x9E', ' ', '\xE2', '\xB4', '\xB5', ' ', '\xE2', '\xB4', '\xBC', ' ', '\xE2', '\xB4', '\xB9', ' ', '\xE2', '\xB5', '\x8E', /* ⵔ ⵙ ⵛ ⵞ ⴵ ⴼ ⴹ ⵎ */ + '\0', + '\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x98', '\x9C', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x96', '\x9D', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', /* ꗍ ꘖ ꘙ ꘜ ꖜ ꖝ ꔅ ꕢ */ + '\0', + '\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x97', '\x9E', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x94', '\x86', /* ꗍ ꘖ ꘙ ꗞ ꔅ ꕢ ꖜ ꔆ */ +#ifdef AF_CONFIG_OPTION_CJK + '\0', + '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* 他 们 你 來 們 到 和 地 */ + ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB8', '\xAD', ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x83', /* 对 對 就 席 我 时 時 會 */ + ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\x88', '\xB0', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* 来 為 能 舰 說 说 这 這 */ + ' ', '\xE9', '\xBD', '\x8A', ' ', '|', /* 齊 | */ + ' ', '\xE5', '\x86', '\x9B', ' ', '\xE5', '\x90', '\x8C', ' ', '\xE5', '\xB7', '\xB2', ' ', '\xE6', '\x84', '\xBF', ' ', '\xE6', '\x97', '\xA2', ' ', '\xE6', '\x98', '\x9F', ' ', '\xE6', '\x98', '\xAF', ' ', '\xE6', '\x99', '\xAF', /* 军 同 已 愿 既 星 是 景 */ + ' ', '\xE6', '\xB0', '\x91', ' ', '\xE7', '\x85', '\xA7', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\xA8', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\xA6', '\x81', /* 民 照 现 現 理 用 置 要 */ + ' ', '\xE8', '\xBB', '\x8D', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x85', '\x8D', ' ', '\xE9', '\x87', '\x8C', ' ', '\xE9', '\x96', '\x8B', ' ', '\xE9', '\x9B', '\xB7', ' ', '\xE9', '\x9C', '\xB2', ' ', '\xE9', '\x9D', '\xA2', /* 軍 那 配 里 開 雷 露 面 */ + ' ', '\xE9', '\xA1', '\xBE', /* 顾 */ + '\0', + '\xE4', '\xB8', '\xAA', ' ', '\xE4', '\xB8', '\xBA', ' ', '\xE4', '\xBA', '\xBA', ' ', '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xA5', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', /* 个 为 人 他 以 们 你 來 */ + ' ', '\xE5', '\x80', '\x8B', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\xA4', '\xA7', ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', /* 個 們 到 和 大 对 對 就 */ + ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x89', ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\xA6', '\x81', ' ', '\xE8', '\xAA', '\xAA', /* 我 时 時 有 来 為 要 說 */ + ' ', '\xE8', '\xAF', '\xB4', ' ', '|', /* 说 | */ + ' ', '\xE4', '\xB8', '\xBB', ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE5', '\x9B', '\xA0', ' ', '\xE5', '\xAE', '\x83', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x84', '\x8F', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\x9F', /* 主 些 因 它 想 意 理 生 */ + ' ', '\xE7', '\x95', '\xB6', ' ', '\xE7', '\x9C', '\x8B', ' ', '\xE7', '\x9D', '\x80', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\x80', '\x85', ' ', '\xE8', '\x87', '\xAA', ' ', '\xE8', '\x91', '\x97', ' ', '\xE8', '\xA3', '\xA1', /* 當 看 着 置 者 自 著 裡 */ + ' ', '\xE8', '\xBF', '\x87', ' ', '\xE8', '\xBF', '\x98', ' ', '\xE8', '\xBF', '\x9B', ' ', '\xE9', '\x80', '\xB2', ' ', '\xE9', '\x81', '\x8E', ' ', '\xE9', '\x81', '\x93', ' ', '\xE9', '\x82', '\x84', ' ', '\xE9', '\x87', '\x8C', /* 过 还 进 進 過 道 還 里 */ + ' ', '\xE9', '\x9D', '\xA2', /* 面 */ +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + '\0', + ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* 些 们 你 來 們 到 和 地 */ + ' ', '\xE5', '\xA5', '\xB9', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB9', '\xB4', ' ', '\xE5', '\xBE', '\x97', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x9C', '\x80', /* 她 将 將 就 年 得 情 最 */ + ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE7', '\x90', '\x86', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* 样 樣 理 能 說 说 这 這 */ + ' ', '\xE9', '\x80', '\x9A', ' ', '|', /* 通 | */ + ' ', '\xE5', '\x8D', '\xB3', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x90', '\xA7', ' ', '\xE5', '\x90', '\xAC', ' ', '\xE5', '\x91', '\xA2', ' ', '\xE5', '\x93', '\x81', ' ', '\xE5', '\x93', '\x8D', ' ', '\xE5', '\x97', '\x8E', /* 即 吗 吧 听 呢 品 响 嗎 */ + ' ', '\xE5', '\xB8', '\x88', ' ', '\xE5', '\xB8', '\xAB', ' ', '\xE6', '\x94', '\xB6', ' ', '\xE6', '\x96', '\xAD', ' ', '\xE6', '\x96', '\xB7', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE7', '\x9C', '\xBC', ' ', '\xE9', '\x96', '\x93', /* 师 師 收 断 斷 明 眼 間 */ + ' ', '\xE9', '\x97', '\xB4', ' ', '\xE9', '\x99', '\x85', ' ', '\xE9', '\x99', '\x88', ' ', '\xE9', '\x99', '\x90', ' ', '\xE9', '\x99', '\xA4', ' ', '\xE9', '\x99', '\xB3', ' ', '\xE9', '\x9A', '\x8F', ' ', '\xE9', '\x9A', '\x9B', /* 间 际 陈 限 除 陳 随 際 */ + ' ', '\xE9', '\x9A', '\xA8', /* 隨 */ + '\0', + '\xE4', '\xBA', '\x8B', ' ', '\xE5', '\x89', '\x8D', ' ', '\xE5', '\xAD', '\xB8', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x88', '\x96', /* 事 前 學 将 將 情 想 或 */ + ' ', '\xE6', '\x94', '\xBF', ' ', '\xE6', '\x96', '\xAF', ' ', '\xE6', '\x96', '\xB0', ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE6', '\xB0', '\x91', ' ', '\xE6', '\xB2', '\x92', ' ', '\xE6', '\xB2', '\xA1', /* 政 斯 新 样 樣 民 沒 没 */ + ' ', '\xE7', '\x84', '\xB6', ' ', '\xE7', '\x89', '\xB9', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x83', ' ', '\xE7', '\xAC', '\xAC', ' ', '\xE7', '\xB6', '\x93', ' ', '\xE8', '\xB0', '\x81', /* 然 特 现 現 球 第 經 谁 */ + ' ', '\xE8', '\xB5', '\xB7', ' ', '|', /* 起 | */ + ' ', '\xE4', '\xBE', '\x8B', ' ', '\xE5', '\x88', '\xA5', ' ', '\xE5', '\x88', '\xAB', ' ', '\xE5', '\x88', '\xB6', ' ', '\xE5', '\x8A', '\xA8', ' ', '\xE5', '\x8B', '\x95', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x97', '\x8E', /* 例 別 别 制 动 動 吗 嗎 */ + ' ', '\xE5', '\xA2', '\x9E', ' ', '\xE6', '\x8C', '\x87', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE6', '\x9C', '\x9D', ' ', '\xE6', '\x9C', '\x9F', ' ', '\xE6', '\x9E', '\x84', ' ', '\xE7', '\x89', '\xA9', ' ', '\xE7', '\xA1', '\xAE', /* 增 指 明 朝 期 构 物 确 */ + ' ', '\xE7', '\xA7', '\x8D', ' ', '\xE8', '\xAA', '\xBF', ' ', '\xE8', '\xB0', '\x83', ' ', '\xE8', '\xB2', '\xBB', ' ', '\xE8', '\xB4', '\xB9', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x83', '\xBD', ' ', '\xE9', '\x96', '\x93', /* 种 調 调 費 费 那 都 間 */ + ' ', '\xE9', '\x97', '\xB4', /* 间 */ +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ +#endif /* AF_CONFIG_OPTION_CJK */ + '\0', + + }; + + + /* stringsets are specific to styles */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARABIC_BOTTOM, 0 }, + { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BAMUM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BAMUM_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BENGALI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BENGALI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BENGALI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_BENGALI_BASE, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_BUHID_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BUHID_LARGE, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_BUHID_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_BUHID_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CHAKMA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 }, + { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CARIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CHEROKEE_CAPITAL, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHEROKEE_CAPITAL, 0 }, + { AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CHEROKEE_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CHEROKEE_SMALL, 0 }, + { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 }, + { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYPRIOT_SMALL, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DEVANAGARI_BASE, 0 }, + { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER, 0 }, + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM, 0 }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GREEK_SMALL, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 }, + { AF_BLUE_STRING_GUJARATI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GUJARATI_DESCENDER, 0 }, + { AF_BLUE_STRING_GUJARATI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_GURMUKHI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GURMUKHI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GURMUKHI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GURMUKHI_BOTTOM, 0 }, + { AF_BLUE_STRING_GURMUKHI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG }, + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 }, + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 }, + { AF_BLUE_STRING_KAYAH_LI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_KAYAH_LI_DESCENDER, 0 }, + { AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KHMER_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP, AF_BLUE_PROPERTY_LATIN_SUB_TOP }, + { AF_BLUE_STRING_KHMER_BOTTOM, 0 }, + { AF_BLUE_STRING_KHMER_DESCENDER, 0 }, + { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LAO_BOTTOM, 0 }, + { AF_BLUE_STRING_LAO_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LAO_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LISU_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MYANMAR_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MYANMAR_BOTTOM, 0 }, + { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_NKO_BOTTOM, 0 }, + { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OL_CHIKI, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 }, + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, + { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SINHALA_BOTTOM, 0 }, + { AF_BLUE_STRING_SINHALA_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_SUNDANESE_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SUNDANESE_BOTTOM, 0 }, + { AF_BLUE_STRING_SUNDANESE_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TAMIL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TAMIL_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TAI_VIET_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TAI_VIET_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TELUGU_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_THAI_BOTTOM, 0 }, + { AF_BLUE_STRING_THAI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_THAI_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_THAI_DESCENDER, 0 }, + { AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 }, + { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TIFINAGH, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_VAI_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, +#ifdef AF_CONFIG_OPTION_CJK + { AF_BLUE_STRING_CJK_TOP, AF_BLUE_PROPERTY_CJK_TOP }, + { AF_BLUE_STRING_CJK_BOTTOM, 0 }, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT, AF_BLUE_PROPERTY_CJK_HORIZ }, + { AF_BLUE_STRING_CJK_RIGHT, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT }, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 }, +#endif /* AF_CONFIG_OPTION_CJK */ + + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afblue.cin b/Dependencies/freetype/freetype/src/autofit/afblue.cin new file mode 100644 index 00000000..d2270fac --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afblue.cin @@ -0,0 +1,39 @@ +/**************************************************************************** + * + * afblue.c + * + * Auto-fitter data for blue strings (body). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" + + + FT_LOCAL_ARRAY_DEF( char ) + af_blue_strings[] = + { + /* */ +@AF_BLUE_STRINGS_ARRAY@ + }; + + + /* stringsets are specific to styles */ + FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec ) + af_blue_stringsets[] = + { + /* */ +@AF_BLUE_STRINGSETS_ARRAY@ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afblue.dat b/Dependencies/freetype/freetype/src/autofit/afblue.dat new file mode 100644 index 00000000..88bab263 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afblue.dat @@ -0,0 +1,1121 @@ +// afblue.dat +// +// Auto-fitter data for blue strings. +// +// Copyright (C) 2013-2024 by +// David Turner, Robert Wilhelm, and Werner Lemberg. +// +// This file is part of the FreeType project, and may only be used, +// modified, and distributed under the terms of the FreeType project +// license, LICENSE.TXT. By continuing to use, modify, or distribute +// this file you indicate that you have read the license and +// understand and accept it fully. + + +// This file contains data specific to blue zones. It gets processed by +// a script to simulate `jagged arrays', with enumeration values holding +// offsets into the arrays. +// +// The format of the file is rather simple: A section starts with three +// labels separated by whitespace and followed by a colon (everything in a +// single line); the first label gives the name of the enumeration template, +// the second the name of the array template, and the third the name of the +// `maximum' template. The script then fills the corresponding templates +// (indicated by `@' characters around the name). +// +// A section contains one or more data records. Each data record consists +// of two or more lines. The first line holds the enumeration name, and the +// remaining lines the corresponding array data. +// +// There are two possible representations for array data. +// +// - A string of characters or character clusters (for example, representing +// Aksharas, Devanagari syllables) in UTF-8 encoding enclosed in double +// quotes, using C syntax, where the elements are separated by spaces. +// There can be only one string per line, thus the starting and ending +// double quote must be the first and last character in the line, +// respectively, ignoring whitespace before and after the string. If +// there are multiple strings (in multiple lines), they are concatenated +// to a single string. In the output, a string gets represented as a +// series of singles bytes, followed by a zero byte. The enumeration +// values simply hold byte offsets to the start of the corresponding +// strings. +// +// For strings, the `maximum' template holds the maximum number of +// non-space characters in all strings. +// +// - Data blocks enclosed in balanced braces, which get copied verbatim and +// which can span multiple lines. The opening brace of a block must be +// the first character of a line (ignoring whitespace), and the closing +// brace the last (ignoring whitespace also). The script appends a comma +// character after each block and counts the number of blocks to set the +// enumeration values. +// +// For data blocks, the `maximum' template holds the maximum number of +// array elements. +// +// A section can contain either strings only or data blocks only. +// +// A comment line starts with `//'; it gets removed. A preprocessor +// directive line (using the standard syntax of `cpp') starts with `#' and +// gets copied verbatim to both the enumeration and the array. Whitespace +// outside of a string is insignificant. +// +// Preprocessor directives are ignored while the script computes maximum +// values; this essentially means that the maximum values can easily be too +// large. Given that the purpose of those values is to create local +// fixed-size arrays at compile time for further processing of the blue zone +// data, this isn't a problem. Note the final zero byte of a string is not +// counted. Note also that the count holds the number of UTF-8 encoded +// characters, not bytes. + + +// The blue zone string data, to be used in the blue stringsets below. + +AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: + + AF_BLUE_STRING_ADLAM_CAPITAL_TOP + "𞤌 𞤅 𞤈 𞤏 𞤔 𞤚" + AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM + "𞤂 𞤖" + AF_BLUE_STRING_ADLAM_SMALL_TOP + "𞤬 𞤮 𞤻 𞤼 𞤾" + AF_BLUE_STRING_ADLAM_SMALL_BOTTOM + "𞤤 𞤨 𞤩 𞤭 𞤴 𞤸 𞤺 𞥀" + + AF_BLUE_STRING_ARABIC_TOP + "ا إ ل ك ط ظ" + AF_BLUE_STRING_ARABIC_BOTTOM + "ت ث ط ظ ك" + // We don't necessarily have access to medial forms via Unicode in case + // Arabic presentational forms are missing. The only character that is + // guaranteed to have the same vertical position with joining (that is, + // non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both + // round and flat curves. + AF_BLUE_STRING_ARABIC_JOIN + "ـ" + + AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP + "Ա Մ Ւ Ս Բ Գ Դ Օ" + AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM + "Ւ Ո Դ Ճ Շ Ս Տ Օ" + AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER + "ե է ի մ վ ֆ ճ" + AF_BLUE_STRING_ARMENIAN_SMALL_TOP + "ա յ ւ ս գ շ ր օ" + AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM + "հ ո ճ ա ե ծ ս օ" + AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER + "բ ը ի լ ղ պ փ ց" + + AF_BLUE_STRING_AVESTAN_TOP + "𐬀 𐬁 𐬐 𐬛" + AF_BLUE_STRING_AVESTAN_BOTTOM + "𐬀 𐬁" + + AF_BLUE_STRING_BAMUM_TOP + "ꚧ ꚨ ꛛ ꛉ ꛁ ꛈ ꛫ ꛯ" + AF_BLUE_STRING_BAMUM_BOTTOM + "ꚭ ꚳ ꚶ ꛬ ꚢ ꚽ ꛯ ꛲" + + AF_BLUE_STRING_BENGALI_BASE + "অ ড ত ন ব ভ ল ক" + AF_BLUE_STRING_BENGALI_TOP + "ই ট ঠ ি ী ৈ ৗ" + AF_BLUE_STRING_BENGALI_HEAD + "ও এ ড ত ন ব ল ক" + + AF_BLUE_STRING_BUHID_TOP + "ᝐ ᝈ" + AF_BLUE_STRING_BUHID_LARGE + "ᝅ ᝊ ᝎ" + AF_BLUE_STRING_BUHID_SMALL + "ᝂ ᝃ ᝉ ᝌ" + AF_BLUE_STRING_BUHID_BOTTOM + "ᝀ ᝃ ᝆ ᝉ ᝋ ᝏ ᝑ" + + AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP + "ᗜ ᖴ ᐁ ᒣ ᑫ ᑎ ᔑ ᗰ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM + "ᗶ ᖵ ᒧ ᐃ ᑌ ᒍ ᔑ ᗢ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP + "ᓓ ᓕ ᓀ ᓂ ᓄ ᕄ ᕆ ᘣ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM + "ᕃ ᓂ ᓀ ᕂ ᓗ ᓚ ᕆ ᘣ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP + "ᐪ ᙆ ᣘ ᐢ ᒾ ᣗ ᔆ" + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM + "ᙆ ᗮ ᒻ ᐞ ᔆ ᒡ ᒢ ᓑ" + + AF_BLUE_STRING_CARIAN_TOP + "𐊧 𐊫 𐊬 𐊭 𐊱 𐊺 𐊼 𐊿" + AF_BLUE_STRING_CARIAN_BOTTOM + "𐊣 𐊧 𐊷 𐋀 𐊫 𐊸 𐋉" + + AF_BLUE_STRING_CHAKMA_TOP + "𑄃 𑄅 𑄉 𑄙 𑄗" + AF_BLUE_STRING_CHAKMA_BOTTOM + "𑄅 𑄛 𑄝 𑄗 𑄓" + AF_BLUE_STRING_CHAKMA_DESCENDER + "𑄖𑄳𑄢 𑄘𑄳𑄢 𑄙𑄳𑄢 𑄤𑄳𑄢 𑄥𑄳𑄢" + + AF_BLUE_STRING_CHEROKEE_CAPITAL + "Ꮖ Ꮋ Ꭼ Ꮓ Ꭴ Ꮳ Ꭶ Ꮥ" + AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER + "ꮒ ꮤ ꮶ ꭴ ꭾ ꮗ ꮝ ꮿ" + AF_BLUE_STRING_CHEROKEE_SMALL + "ꮖ ꭼ ꮓ ꮠ ꮳ ꭶ ꮥ ꮻ" + AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER + "ᏸ ꮐ ꭹ ꭻ" + + AF_BLUE_STRING_COPTIC_CAPITAL_TOP + "Ⲍ Ⲏ Ⲡ Ⳟ Ⲟ Ⲑ Ⲥ Ⳋ" + AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM + "Ⳑ Ⳙ Ⳟ Ⲏ Ⲟ Ⲑ Ⳝ Ⲱ" + AF_BLUE_STRING_COPTIC_SMALL_TOP + "ⲍ ⲏ ⲡ ⳟ ⲟ ⲑ ⲥ ⳋ" + AF_BLUE_STRING_COPTIC_SMALL_BOTTOM + "ⳑ ⳙ ⳟ ⲏ ⲟ ⲑ ⳝ Ⳓ" + + AF_BLUE_STRING_CYPRIOT_TOP + "𐠍 𐠙 𐠳 𐠱 𐠅 𐠓 𐠣 𐠦" + AF_BLUE_STRING_CYPRIOT_BOTTOM + "𐠃 𐠊 𐠛 𐠣 𐠳 𐠵 𐠐" + AF_BLUE_STRING_CYPRIOT_SMALL + "𐠈 𐠏 𐠖" + + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP + "Б В Е П З О С Э" + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM + "Б В Е Ш З О С Э" + AF_BLUE_STRING_CYRILLIC_SMALL + "х п н ш е з о с" + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER + "р у ф" + + AF_BLUE_STRING_DESERET_CAPITAL_TOP + "𐐂 𐐄 𐐋 𐐗 𐐑" + AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM + "𐐀 𐐂 𐐄 𐐗 𐐛" + AF_BLUE_STRING_DESERET_SMALL_TOP + "𐐪 𐐬 𐐳 𐐿 𐐹" + AF_BLUE_STRING_DESERET_SMALL_BOTTOM + "𐐨 𐐪 𐐬 𐐿 𐑃" + + AF_BLUE_STRING_DEVANAGARI_BASE + "क न म उ छ ट ठ ड" + AF_BLUE_STRING_DEVANAGARI_TOP + "ई ऐ ओ औ ि ी ो ौ" + // note that some fonts have extreme variation in the height of the + // round head elements; for this reason we also define the `base' + // blue zone, which must be always present + AF_BLUE_STRING_DEVANAGARI_HEAD + "क म अ आ थ ध भ श" + AF_BLUE_STRING_DEVANAGARI_BOTTOM + "ु ृ" + + AF_BLUE_STRING_ETHIOPIC_TOP + "ሀ ሃ ዘ ፐ ማ በ ዋ ዐ" + AF_BLUE_STRING_ETHIOPIC_BOTTOM + "ለ ሐ በ ዘ ሀ ሪ ዐ ጨ" + + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP + "გ დ ე ვ თ ი ო ღ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM + "ა ზ მ ს შ ძ ხ პ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER + "ს ხ ქ ზ მ შ ჩ წ" + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER + "ე ვ ჟ ტ უ ფ ქ ყ" + + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP + "Ⴑ Ⴇ Ⴙ Ⴜ Ⴄ Ⴅ Ⴓ Ⴚ" + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM + "Ⴄ Ⴅ Ⴇ Ⴈ Ⴆ Ⴑ Ⴊ Ⴋ" + + AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP + "ⴁ ⴗ ⴂ ⴄ ⴅ ⴇ ⴔ ⴖ" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM + "ⴈ ⴌ ⴖ ⴎ ⴃ ⴆ ⴋ ⴢ" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER + "ⴐ ⴑ ⴓ ⴕ ⴙ ⴛ ⴡ ⴣ" + AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER + "ⴄ ⴅ ⴔ ⴕ ⴁ ⴂ ⴘ ⴝ" + + AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP + "Ნ Ჟ Ჳ Ჸ Გ Ე Ო Ჴ" + AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM + "Ი Ჲ Ო Ჩ Მ Შ Ჯ Ჽ" + + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP + "Ⰵ Ⱄ Ⱚ Ⰴ Ⰲ Ⰺ Ⱛ Ⰻ" + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM + "Ⰵ Ⰴ Ⰲ Ⱚ Ⱎ Ⱑ Ⰺ Ⱄ" + AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP + "ⰵ ⱄ ⱚ ⰴ ⰲ ⰺ ⱛ ⰻ" + AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM + "ⰵ ⰴ ⰲ ⱚ ⱎ ⱑ ⰺ ⱄ" + + AF_BLUE_STRING_GOTHIC_TOP + "𐌲 𐌶 𐍀 𐍄 𐌴 𐍃 𐍈 𐌾" + AF_BLUE_STRING_GOTHIC_BOTTOM + "𐌶 𐌴 𐍃 𐍈" + + AF_BLUE_STRING_GREEK_CAPITAL_TOP + "Γ Β Ε Ζ Θ Ο Ω" + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM + "Β Δ Ζ Ξ Θ Ο" + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP + "β θ δ ζ λ ξ" + AF_BLUE_STRING_GREEK_SMALL + "α ε ι ο π σ τ ω" + AF_BLUE_STRING_GREEK_SMALL_DESCENDER + "β γ η μ ρ φ χ ψ" + + AF_BLUE_STRING_GUJARATI_TOP + "ત ન ઋ ઌ છ ટ ર ૦" + AF_BLUE_STRING_GUJARATI_BOTTOM + "ખ ગ ઘ ઞ ઇ ઈ ઠ જ" + AF_BLUE_STRING_GUJARATI_ASCENDER + "ઈ ઊ િ ી લી શ્ચિ જિ સી" + AF_BLUE_STRING_GUJARATI_DESCENDER + "ુ ૃ ૄ ખુ છૃ છૄ" + AF_BLUE_STRING_GUJARATI_DIGIT_TOP + "૦ ૧ ૨ ૩ ૭" + + AF_BLUE_STRING_GURMUKHI_BASE + "ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ" + AF_BLUE_STRING_GURMUKHI_HEAD + "ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ" + AF_BLUE_STRING_GURMUKHI_TOP + "ਇ ਈ ਉ ਏ ਓ ੳ ਿ ੀ" + AF_BLUE_STRING_GURMUKHI_BOTTOM + "ਅ ਏ ਓ ਗ ਜ ਠ ਰ ਸ" + AF_BLUE_STRING_GURMUKHI_DIGIT_TOP + "੦ ੧ ੨ ੩ ੭" + + AF_BLUE_STRING_HEBREW_TOP + "ב ד ה ח ך כ ם ס" + AF_BLUE_STRING_HEBREW_BOTTOM + "ב ט כ ם ס צ" + AF_BLUE_STRING_HEBREW_DESCENDER + "ק ך ן ף ץ" + + AF_BLUE_STRING_KANNADA_TOP + "ಇ ಊ ಐ ಣ ಸಾ ನಾ ದಾ ರಾ" + AF_BLUE_STRING_KANNADA_BOTTOM + "ಅ ಉ ಎ ಲ ೦ ೨ ೬ ೭" + + AF_BLUE_STRING_KAYAH_LI_TOP + "꤅ ꤏ ꤁ ꤋ ꤀ ꤍ" + AF_BLUE_STRING_KAYAH_LI_BOTTOM + "꤈ ꤘ ꤀ ꤍ ꤢ" + AF_BLUE_STRING_KAYAH_LI_ASCENDER + "ꤖ ꤡ" + AF_BLUE_STRING_KAYAH_LI_DESCENDER + "ꤑ ꤜ ꤞ" + AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER + "ꤑ꤬ ꤜ꤭ ꤔ꤬" + + AF_BLUE_STRING_KHMER_TOP + "ខ ទ ន ឧ ឩ ា" + AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP + "ក្ក ក្ខ ក្គ ក្ថ" + AF_BLUE_STRING_KHMER_BOTTOM + "ខ ឃ ច ឋ ប ម យ ឲ" + AF_BLUE_STRING_KHMER_DESCENDER + "ត្រ រៀ ឲ្យ អឿ" + AF_BLUE_STRING_KHMER_LARGE_DESCENDER + "ន្ត្រៃ ង្ខ្យ ក្បៀ ច្រៀ ន្តឿ ល្បឿ" + + AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP + "᧠ ᧡" + AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM + "᧶ ᧹" + + AF_BLUE_STRING_LAO_TOP + "າ ດ ອ ມ ລ ວ ຣ ງ" + AF_BLUE_STRING_LAO_BOTTOM + "າ ອ ບ ຍ ຣ ຮ ວ ຢ" + AF_BLUE_STRING_LAO_ASCENDER + "ປ ຢ ຟ ຝ" + AF_BLUE_STRING_LAO_LARGE_ASCENDER + "ໂ ໄ ໃ" + AF_BLUE_STRING_LAO_DESCENDER + "ງ ຊ ຖ ຽ ໆ ຯ" + + AF_BLUE_STRING_LATIN_CAPITAL_TOP + "T H E Z O C Q S" + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM + "H E Z L O C U S" + AF_BLUE_STRING_LATIN_SMALL_F_TOP + "f i j k d b h" + AF_BLUE_STRING_LATIN_SMALL_TOP + "u v x z o e s c" + AF_BLUE_STRING_LATIN_SMALL_BOTTOM + "n r x z o e s c" + AF_BLUE_STRING_LATIN_SMALL_DESCENDER + "p q g j y" + + // we assume that both the subscript and superscript ranges + // don't contain oldstyle digits (actually, most fonts probably + // have digits only in those ranges) + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP + "₀ ₃ ₅ ₇ ₈" + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM + "₀ ₁ ₂ ₃ ₈" + AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP + "ᵢ ⱼ ₕ ₖ ₗ" + AF_BLUE_STRING_LATIN_SUBS_SMALL + "ₐ ₑ ₒ ₓ ₙ ₛ ᵥ ᵤ ᵣ" + AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER + "ᵦ ᵧ ᵨ ᵩ ₚ" + + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP + "⁰ ³ ⁵ ⁷ ᵀ ᴴ ᴱ ᴼ" + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM + "⁰ ¹ ² ³ ᴱ ᴸ ᴼ ᵁ" + AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP + "ᵇ ᵈ ᵏ ʰ ʲ ᶠ ⁱ" + AF_BLUE_STRING_LATIN_SUPS_SMALL + "ᵉ ᵒ ʳ ˢ ˣ ᶜ ᶻ" + AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER + "ᵖ ʸ ᵍ" + + AF_BLUE_STRING_LISU_TOP + "ꓡ ꓧ ꓱ ꓶ ꓩ ꓚ ꓵ ꓳ" + AF_BLUE_STRING_LISU_BOTTOM + "ꓕ ꓜ ꓞ ꓡ ꓛ ꓢ ꓳ ꓴ" + + AF_BLUE_STRING_MALAYALAM_TOP + "ഒ ട ഠ റ ച പ ച്ച പ്പ" + AF_BLUE_STRING_MALAYALAM_BOTTOM + "ട ഠ ധ ശ ഘ ച ഥ ല" + + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP + "𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹟" + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM + "𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹒 𖹓" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP + "𖹤 𖹬 𖹧 𖹴 𖹶 𖹾" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP + "𖹠 𖹡 𖹢 𖹹 𖹳 𖹮" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM + "𖹠 𖹡 𖹢 𖹳 𖹭 𖹽" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER + "𖹥 𖹨 𖹩" + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP + "𖺀 𖺅 𖺈 𖺄 𖺍" + + AF_BLUE_STRING_MONGOLIAN_TOP_BASE + "ᠳ ᠴ ᠶ ᠽ ᡂ ᡊ ‍ᡡ‍ ‍ᡳ‍" + AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE + "ᡃ" + + AF_BLUE_STRING_MYANMAR_TOP + "ခ ဂ င ဒ ဝ ၥ ၊ ။" + AF_BLUE_STRING_MYANMAR_BOTTOM + "င ဎ ဒ ပ ဗ ဝ ၊ ။" + AF_BLUE_STRING_MYANMAR_ASCENDER + "ဩ ြ ၍ ၏ ၆ ါ ိ" + AF_BLUE_STRING_MYANMAR_DESCENDER + "ဉ ည ဥ ဩ ဨ ၂ ၅ ၉" + + AF_BLUE_STRING_NKO_TOP + "ߐ ߉ ߒ ߟ ߖ ߜ ߠ ߥ" + AF_BLUE_STRING_NKO_BOTTOM + "߀ ߘ ߡ ߠ ߥ" + AF_BLUE_STRING_NKO_SMALL_TOP + "ߏ ߛ ߋ" + AF_BLUE_STRING_NKO_SMALL_BOTTOM + "ߎ ߏ ߛ ߋ" + + AF_BLUE_STRING_OL_CHIKI + "ᱛ ᱜ ᱝ ᱡ ᱢ ᱥ" + + AF_BLUE_STRING_OLD_TURKIC_TOP + "𐰗 𐰘 𐰧" + AF_BLUE_STRING_OLD_TURKIC_BOTTOM + "𐰉 𐰗 𐰦 𐰧" + + AF_BLUE_STRING_OSAGE_CAPITAL_TOP + "𐒾 𐓍 𐓒 𐓓 𐒻 𐓂 𐒵 𐓆" + AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM + "𐒰 𐓍 𐓂 𐒿 𐓎 𐒹" + AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER + "𐒼 𐒽 𐒾" + AF_BLUE_STRING_OSAGE_SMALL_TOP + "𐓵 𐓶 𐓺 𐓻 𐓝 𐓣 𐓪 𐓮" + AF_BLUE_STRING_OSAGE_SMALL_BOTTOM + "𐓘 𐓚 𐓣 𐓵 𐓡 𐓧 𐓪 𐓶" + AF_BLUE_STRING_OSAGE_SMALL_ASCENDER + "𐓤 𐓦 𐓸 𐓹 𐓛" + AF_BLUE_STRING_OSAGE_SMALL_DESCENDER + "𐓤 𐓥 𐓦" + + AF_BLUE_STRING_OSMANYA_TOP + "𐒆 𐒉 𐒐 𐒒 𐒘 𐒛 𐒠 𐒣" + AF_BLUE_STRING_OSMANYA_BOTTOM + "𐒀 𐒂 𐒆 𐒈 𐒊 𐒒 𐒠 𐒩" + + AF_BLUE_STRING_ROHINGYA_TOP + "𐴃 𐴀 𐴆 𐴖 𐴕" + AF_BLUE_STRING_ROHINGYA_BOTTOM + "𐴔 𐴖 𐴕 𐴑 𐴐" + AF_BLUE_STRING_ROHINGYA_JOIN + "ـ" + + AF_BLUE_STRING_SAURASHTRA_TOP + "ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ꢝ ꢛ" + AF_BLUE_STRING_SAURASHTRA_BOTTOM + "ꢂ ꢨ ꢺ ꢤ ꢎ" + + AF_BLUE_STRING_SHAVIAN_TOP + "𐑕 𐑙" + AF_BLUE_STRING_SHAVIAN_BOTTOM + "𐑔 𐑖 𐑗 𐑹 𐑻" + AF_BLUE_STRING_SHAVIAN_DESCENDER + "𐑟 𐑣" + AF_BLUE_STRING_SHAVIAN_SMALL_TOP + "𐑱 𐑲 𐑳 𐑴 𐑸 𐑺 𐑼" + AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM + "𐑴 𐑻 𐑹" + + AF_BLUE_STRING_SINHALA_TOP + "ඉ ක ඝ ඳ ප ය ල ෆ" + AF_BLUE_STRING_SINHALA_BOTTOM + "එ ඔ ඝ ජ ට ථ ධ ර" + AF_BLUE_STRING_SINHALA_DESCENDER + "ද ඳ උ ල තූ තු බු දු" + + AF_BLUE_STRING_SUNDANESE_TOP + "ᮋ ᮞ ᮮ ᮽ ᮰ ᮈ" + AF_BLUE_STRING_SUNDANESE_BOTTOM + "ᮄ ᮔ ᮕ ᮗ ᮰ ᮆ ᮈ ᮉ" + AF_BLUE_STRING_SUNDANESE_DESCENDER + "ᮼ ᳄" + + AF_BLUE_STRING_TAI_VIET_TOP + "ꪆ ꪔ ꪒ ꪖ ꪫ" + AF_BLUE_STRING_TAI_VIET_BOTTOM + "ꪉ ꪫ ꪮ" + + AF_BLUE_STRING_TAMIL_TOP + "உ ஒ ஓ ற ஈ க ங ச" + AF_BLUE_STRING_TAMIL_BOTTOM + "க ச ல ஶ உ ங ட ப" + + AF_BLUE_STRING_TELUGU_TOP + "ఇ ఌ ఙ ఞ ణ ఱ ౯" + AF_BLUE_STRING_TELUGU_BOTTOM + "అ క చ ర ఽ ౨ ౬" + + AF_BLUE_STRING_THAI_TOP + "บ เ แ อ ก า" + AF_BLUE_STRING_THAI_BOTTOM + "บ ป ษ ฯ อ ย ฮ" + AF_BLUE_STRING_THAI_ASCENDER + "ป ฝ ฟ" + AF_BLUE_STRING_THAI_LARGE_ASCENDER + "โ ใ ไ" + AF_BLUE_STRING_THAI_DESCENDER + "ฎ ฏ ฤ ฦ" + AF_BLUE_STRING_THAI_LARGE_DESCENDER + "ญ ฐ" + AF_BLUE_STRING_THAI_DIGIT_TOP + "๐ ๑ ๓" + + AF_BLUE_STRING_TIFINAGH + "ⵔ ⵙ ⵛ ⵞ ⴵ ⴼ ⴹ ⵎ" + + AF_BLUE_STRING_VAI_TOP + "ꗍ ꘖ ꘙ ꘜ ꖜ ꖝ ꔅ ꕢ" + AF_BLUE_STRING_VAI_BOTTOM + "ꗍ ꘖ ꘙ ꗞ ꔅ ꕢ ꖜ ꔆ" + + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRING_CJK_TOP + "他 们 你 來 們 到 和 地" + " 对 對 就 席 我 时 時 會" + " 来 為 能 舰 說 说 这 這" + " 齊 |" + " 军 同 已 愿 既 星 是 景" + " 民 照 现 現 理 用 置 要" + " 軍 那 配 里 開 雷 露 面" + " 顾" + AF_BLUE_STRING_CJK_BOTTOM + "个 为 人 他 以 们 你 來" + " 個 們 到 和 大 对 對 就" + " 我 时 時 有 来 為 要 說" + " 说 |" + " 主 些 因 它 想 意 理 生" + " 當 看 着 置 者 自 著 裡" + " 过 还 进 進 過 道 還 里" + " 面" + +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + + AF_BLUE_STRING_CJK_LEFT + " 些 们 你 來 們 到 和 地" + " 她 将 將 就 年 得 情 最" + " 样 樣 理 能 說 说 这 這" + " 通 |" + " 即 吗 吧 听 呢 品 响 嗎" + " 师 師 收 断 斷 明 眼 間" + " 间 际 陈 限 除 陳 随 際" + " 隨" + AF_BLUE_STRING_CJK_RIGHT + "事 前 學 将 將 情 想 或" + " 政 斯 新 样 樣 民 沒 没" + " 然 特 现 現 球 第 經 谁" + " 起 |" + " 例 別 别 制 动 動 吗 嗎" + " 增 指 明 朝 期 构 物 确" + " 种 調 调 費 费 那 都 間" + " 间" + +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + +#endif /* AF_CONFIG_OPTION_CJK */ + + +// The blue zone stringsets, as used in the script styles, cf. `afstyles.h'. +// +// The AF_BLUE_PROPERTY_XXX flags are defined in `afblue.h'; here some +// explanations. +// +// A blue zone in general is defined by a reference and an overshoot line. +// During the hinting process, all coordinate values between those two lines +// are set equal to the reference value, provided that the blue zone is not +// wider than 0.75 pixels (otherwise the blue zone gets ignored). All +// entries must have `AF_BLUE_STRING_MAX' as the final line. +// +// During the glyph analysis, edges are sorted from bottom to top, and then +// sequentially checked, edge by edge, against the blue zones in the order +// given below. +// +// +// latin auto-hinter +// ----------------- +// +// Characters in a blue string are automatically classified as having a flat +// (reference) or a round (overshoot) extremum. The blue zone is then set +// up by the mean values of all flat extrema and all round extrema, +// respectively. Only horizontal blue zones (i.e., adjusting vertical +// coordinate values) are supported. +// +// Some scripts like Khmer need character composition to get all necessary +// blue zones, since Unicode only provides an abstract data model that +// doesn't represent all possible glyph shapes. For such character +// clusters, the HarfBuzz library is used to convert them into the +// corresponding glyphs. The largest glyph element (where `largest' can be +// either `largest ascender' or `largest descender') then defines the +// corresponding flat or round extremum. +// +// For the latin auto-hinter, the overshoot should be larger than the +// reference for top zones, and vice versa for bottom zones. +// +// LATIN_TOP +// Take the maximum flat and round coordinate values of the blue string +// characters for computing the blue zone's reference and overshoot +// values. +// +// If not set, take the minimum values. +// +// Mutually exclusive with `LATIN_SUB_TOP'. +// +// LATIN_SUB_TOP +// For all glyphs of a character cluster, compute the maximum flat +// and round coordinate values of each component, then take the +// smallest of the maximum values. The idea is to get the top of +// subscript glyphs, as used in Khmer, for example. Note that +// this mechanism doesn't work for ordinary ligatures. +// +// This flags indicates a secondary blue zone: It gets removed if +// there is a non-LATIN_SUB_TOP blue zone at the same coordinate +// value (after scaling). +// +// Mutually exclusive with `LATIN_TOP'. +// +// LATIN_NEUTRAL +// Ignore round extrema and define the blue zone with flat values only. +// Both top and bottom of contours can match. This is useful for +// scripts like Devanagari where vowel signs attach to the base +// character and are implemented as components of composite glyphs. +// +// If not set, both round and flat extrema are taken into account. +// Additionally, only the top or the bottom of a contour can match, +// depending on the LATIN_TOP flag. +// +// Neutral blue zones should always follow non-neutral blue zones. +// +// LATIN_X_HEIGHT +// Scale all glyphs vertically from the corresponding script to make the +// reference line of this blue zone align on the grid. The scaling +// takes place before all other blue zones get aligned to the grid. +// Only one blue character string of a script style can have this flag. +// +// LATIN_LONG +// Apply an additional constraint for blue zone values: Don't +// necessarily use the extremum as-is but a segment of the topmost (or +// bottommost) contour that is longer than a heuristic threshold, and +// which is not too far away vertically from the real extremum. This +// ensures that small bumps in the outline are ignored (for example, the +// `vertical serifs' found in many Hebrew glyph designs). +// +// The segment must be at least EM/25 font units long, and the distance +// to the extremum must be smaller than EM/4. +// +// +// cjk auto-hinter +// --------------- +// +// Characters in a blue string are *not* automatically classified. Instead, +// first come the characters used for the overshoot value, then the +// character `|', then the characters used for the reference value +// (everything separated by space characters). The blue zone is then set up +// by the mean values of all reference values and all overshoot values, +// respectively. Both horizontal and vertical blue zones (i.e., adjusting +// vertical and horizontal coordinate values, respectively) are supported. +// +// For the cjk auto-hinter, the overshoot should be smaller than the +// reference for top zones, and vice versa for bottom zones. +// +// CJK_TOP +// Take the maximum flat and round coordinate values of the blue string +// characters. If not set, take the minimum values. +// +// CJK_RIGHT +// A synonym for CJK_TOP. If CJK_HORIZ is set, this flag indicates the +// right blue zone, taking horizontal maximum values. +// +// CJK_HORIZ +// Define a blue zone for horizontal hinting (i.e., vertical blue +// zones). If not set, this is a blue zone for vertical hinting. + + +AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: + + AF_BLUE_STRINGSET_ADLM + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ARAB + { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARABIC_BOTTOM, 0 } + { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ARMN + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_AVST + { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BAMU + { AF_BLUE_STRING_BAMUM_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BAMUM_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BENG + { AF_BLUE_STRING_BENGALI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BENGALI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BENGALI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_BENGALI_BASE, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_BUHD + { AF_BLUE_STRING_BUHID_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BUHID_LARGE, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_BUHID_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_BUHID_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CAKM + { AF_BLUE_STRING_CHAKMA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 } + { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CANS + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CARI + { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CARIAN_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CHER + { AF_BLUE_STRING_CHEROKEE_CAPITAL, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHEROKEE_CAPITAL, 0 } + { AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CHEROKEE_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CHEROKEE_SMALL, 0 } + { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_COPT + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CPRT + { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 } + { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYPRIOT_SMALL, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_CYRL + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_DEVA + { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DEVANAGARI_BASE, 0 } + { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_DSRT + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ETHI + { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GEOR + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER, 0 } + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GEOK + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM, 0 } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GLAG + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GOTH + { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GREK + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GREEK_SMALL, 0 } + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GUJR + { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 } + { AF_BLUE_STRING_GUJARATI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GUJARATI_DESCENDER, 0 } + { AF_BLUE_STRING_GUJARATI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_GURU + { AF_BLUE_STRING_GURMUKHI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GURMUKHI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GURMUKHI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_NEUTRAL | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GURMUKHI_BOTTOM, 0 } + { AF_BLUE_STRING_GURMUKHI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_HEBR + { AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_LONG } + { AF_BLUE_STRING_HEBREW_BOTTOM, 0 } + { AF_BLUE_STRING_HEBREW_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KNDA + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KALI + { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 } + { AF_BLUE_STRING_KAYAH_LI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_KAYAH_LI_DESCENDER, 0 } + { AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KHMR + { AF_BLUE_STRING_KHMER_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP, AF_BLUE_PROPERTY_LATIN_SUB_TOP } + { AF_BLUE_STRING_KHMER_BOTTOM, 0 } + { AF_BLUE_STRING_KHMER_DESCENDER, 0 } + { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_KHMS + { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LAO + { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LAO_BOTTOM, 0 } + { AF_BLUE_STRING_LAO_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LAO_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATN + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATB + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LATP + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_LISU + { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LISU_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MLYM + { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MEDF + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MONG + { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_MYMR + { AF_BLUE_STRING_MYANMAR_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MYANMAR_BOTTOM, 0 } + { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_NKOO + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_NKO_BOTTOM, 0 } + { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_NONE + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OLCK + { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OL_CHIKI, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ORKH + { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OSGE + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_OSMA + { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_ROHG + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 } + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SAUR + { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SHAW + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } + { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SINH + { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SINHALA_BOTTOM, 0 } + { AF_BLUE_STRING_SINHALA_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_SUND + { AF_BLUE_STRING_SUNDANESE_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SUNDANESE_BOTTOM, 0 } + { AF_BLUE_STRING_SUNDANESE_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TAML + { AF_BLUE_STRING_TAMIL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TAMIL_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TAVT + { AF_BLUE_STRING_TAI_VIET_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TAI_VIET_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TELU + { AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TELUGU_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_THAI + { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_THAI_BOTTOM, 0 } + { AF_BLUE_STRING_THAI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_THAI_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_THAI_DESCENDER, 0 } + { AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 } + { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_TFNG + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TIFINAGH, 0 } + { AF_BLUE_STRING_MAX, 0 } + + AF_BLUE_STRINGSET_VAII + { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_VAI_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + +#ifdef AF_CONFIG_OPTION_CJK + + AF_BLUE_STRINGSET_HANI + { AF_BLUE_STRING_CJK_TOP, AF_BLUE_PROPERTY_CJK_TOP } + { AF_BLUE_STRING_CJK_BOTTOM, 0 } +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { AF_BLUE_STRING_CJK_LEFT, AF_BLUE_PROPERTY_CJK_HORIZ } + { AF_BLUE_STRING_CJK_RIGHT, AF_BLUE_PROPERTY_CJK_HORIZ | + AF_BLUE_PROPERTY_CJK_RIGHT } +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + { AF_BLUE_STRING_MAX, 0 } + +#endif /* AF_CONFIG_OPTION_CJK */ + + +// END diff --git a/Dependencies/freetype/freetype/src/autofit/afblue.h b/Dependencies/freetype/freetype/src/autofit/afblue.h new file mode 100644 index 00000000..2aa9d098 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afblue.h @@ -0,0 +1,429 @@ +/* This file has been generated by the Perl script `afblue.pl', */ +/* using data from file `afblue.dat'. */ + +/**************************************************************************** + * + * afblue.h + * + * Auto-fitter data for blue strings (specification). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFBLUE_H_ +#define AFBLUE_H_ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + do \ + { \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len_; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len_ = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len_ = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len_ = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len_ > 0; len_-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } \ + } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN 51 + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { + AF_BLUE_STRING_ADLAM_CAPITAL_TOP = 0, + AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM = 30, + AF_BLUE_STRING_ADLAM_SMALL_TOP = 40, + AF_BLUE_STRING_ADLAM_SMALL_BOTTOM = 65, + AF_BLUE_STRING_ARABIC_TOP = 105, + AF_BLUE_STRING_ARABIC_BOTTOM = 123, + AF_BLUE_STRING_ARABIC_JOIN = 138, + AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP = 141, + AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM = 165, + AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER = 189, + AF_BLUE_STRING_ARMENIAN_SMALL_TOP = 210, + AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM = 234, + AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER = 258, + AF_BLUE_STRING_AVESTAN_TOP = 282, + AF_BLUE_STRING_AVESTAN_BOTTOM = 302, + AF_BLUE_STRING_BAMUM_TOP = 312, + AF_BLUE_STRING_BAMUM_BOTTOM = 344, + AF_BLUE_STRING_BENGALI_BASE = 376, + AF_BLUE_STRING_BENGALI_TOP = 408, + AF_BLUE_STRING_BENGALI_HEAD = 436, + AF_BLUE_STRING_BUHID_TOP = 468, + AF_BLUE_STRING_BUHID_LARGE = 476, + AF_BLUE_STRING_BUHID_SMALL = 488, + AF_BLUE_STRING_BUHID_BOTTOM = 504, + AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP = 532, + AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM = 564, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP = 596, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM = 628, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP = 660, + AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM = 688, + AF_BLUE_STRING_CARIAN_TOP = 720, + AF_BLUE_STRING_CARIAN_BOTTOM = 760, + AF_BLUE_STRING_CHAKMA_TOP = 795, + AF_BLUE_STRING_CHAKMA_BOTTOM = 820, + AF_BLUE_STRING_CHAKMA_DESCENDER = 845, + AF_BLUE_STRING_CHEROKEE_CAPITAL = 910, + AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER = 942, + AF_BLUE_STRING_CHEROKEE_SMALL = 974, + AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER = 1006, + AF_BLUE_STRING_COPTIC_CAPITAL_TOP = 1022, + AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM = 1054, + AF_BLUE_STRING_COPTIC_SMALL_TOP = 1086, + AF_BLUE_STRING_COPTIC_SMALL_BOTTOM = 1118, + AF_BLUE_STRING_CYPRIOT_TOP = 1150, + AF_BLUE_STRING_CYPRIOT_BOTTOM = 1190, + AF_BLUE_STRING_CYPRIOT_SMALL = 1225, + AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 1240, + AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 1264, + AF_BLUE_STRING_CYRILLIC_SMALL = 1288, + AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 1312, + AF_BLUE_STRING_DESERET_CAPITAL_TOP = 1321, + AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM = 1346, + AF_BLUE_STRING_DESERET_SMALL_TOP = 1371, + AF_BLUE_STRING_DESERET_SMALL_BOTTOM = 1396, + AF_BLUE_STRING_DEVANAGARI_BASE = 1421, + AF_BLUE_STRING_DEVANAGARI_TOP = 1453, + AF_BLUE_STRING_DEVANAGARI_HEAD = 1485, + AF_BLUE_STRING_DEVANAGARI_BOTTOM = 1517, + AF_BLUE_STRING_ETHIOPIC_TOP = 1525, + AF_BLUE_STRING_ETHIOPIC_BOTTOM = 1557, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP = 1589, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM = 1621, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER = 1653, + AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER = 1685, + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP = 1717, + AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM = 1749, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP = 1781, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM = 1813, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER = 1845, + AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER = 1877, + AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP = 1909, + AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM = 1941, + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP = 1973, + AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM = 2005, + AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP = 2037, + AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM = 2069, + AF_BLUE_STRING_GOTHIC_TOP = 2101, + AF_BLUE_STRING_GOTHIC_BOTTOM = 2141, + AF_BLUE_STRING_GREEK_CAPITAL_TOP = 2161, + AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 2182, + AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 2200, + AF_BLUE_STRING_GREEK_SMALL = 2218, + AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 2242, + AF_BLUE_STRING_GUJARATI_TOP = 2266, + AF_BLUE_STRING_GUJARATI_BOTTOM = 2298, + AF_BLUE_STRING_GUJARATI_ASCENDER = 2330, + AF_BLUE_STRING_GUJARATI_DESCENDER = 2380, + AF_BLUE_STRING_GUJARATI_DIGIT_TOP = 2413, + AF_BLUE_STRING_GURMUKHI_BASE = 2433, + AF_BLUE_STRING_GURMUKHI_HEAD = 2465, + AF_BLUE_STRING_GURMUKHI_TOP = 2497, + AF_BLUE_STRING_GURMUKHI_BOTTOM = 2529, + AF_BLUE_STRING_GURMUKHI_DIGIT_TOP = 2561, + AF_BLUE_STRING_HEBREW_TOP = 2581, + AF_BLUE_STRING_HEBREW_BOTTOM = 2605, + AF_BLUE_STRING_HEBREW_DESCENDER = 2623, + AF_BLUE_STRING_KANNADA_TOP = 2638, + AF_BLUE_STRING_KANNADA_BOTTOM = 2682, + AF_BLUE_STRING_KAYAH_LI_TOP = 2714, + AF_BLUE_STRING_KAYAH_LI_BOTTOM = 2738, + AF_BLUE_STRING_KAYAH_LI_ASCENDER = 2758, + AF_BLUE_STRING_KAYAH_LI_DESCENDER = 2766, + AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER = 2778, + AF_BLUE_STRING_KHMER_TOP = 2799, + AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP = 2823, + AF_BLUE_STRING_KHMER_BOTTOM = 2863, + AF_BLUE_STRING_KHMER_DESCENDER = 2895, + AF_BLUE_STRING_KHMER_LARGE_DESCENDER = 2929, + AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP = 3016, + AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM = 3024, + AF_BLUE_STRING_LAO_TOP = 3032, + AF_BLUE_STRING_LAO_BOTTOM = 3064, + AF_BLUE_STRING_LAO_ASCENDER = 3096, + AF_BLUE_STRING_LAO_LARGE_ASCENDER = 3112, + AF_BLUE_STRING_LAO_DESCENDER = 3124, + AF_BLUE_STRING_LATIN_CAPITAL_TOP = 3148, + AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 3164, + AF_BLUE_STRING_LATIN_SMALL_F_TOP = 3180, + AF_BLUE_STRING_LATIN_SMALL_TOP = 3194, + AF_BLUE_STRING_LATIN_SMALL_BOTTOM = 3210, + AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 3226, + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP = 3236, + AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM = 3256, + AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP = 3276, + AF_BLUE_STRING_LATIN_SUBS_SMALL = 3296, + AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER = 3332, + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP = 3352, + AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM = 3383, + AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP = 3412, + AF_BLUE_STRING_LATIN_SUPS_SMALL = 3438, + AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER = 3463, + AF_BLUE_STRING_LISU_TOP = 3474, + AF_BLUE_STRING_LISU_BOTTOM = 3506, + AF_BLUE_STRING_MALAYALAM_TOP = 3538, + AF_BLUE_STRING_MALAYALAM_BOTTOM = 3582, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP = 3614, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM = 3649, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP = 3689, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP = 3719, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM = 3749, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER = 3779, + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP = 3794, + AF_BLUE_STRING_MONGOLIAN_TOP_BASE = 3819, + AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE = 3863, + AF_BLUE_STRING_MYANMAR_TOP = 3867, + AF_BLUE_STRING_MYANMAR_BOTTOM = 3899, + AF_BLUE_STRING_MYANMAR_ASCENDER = 3931, + AF_BLUE_STRING_MYANMAR_DESCENDER = 3959, + AF_BLUE_STRING_NKO_TOP = 3991, + AF_BLUE_STRING_NKO_BOTTOM = 4015, + AF_BLUE_STRING_NKO_SMALL_TOP = 4030, + AF_BLUE_STRING_NKO_SMALL_BOTTOM = 4039, + AF_BLUE_STRING_OL_CHIKI = 4051, + AF_BLUE_STRING_OLD_TURKIC_TOP = 4075, + AF_BLUE_STRING_OLD_TURKIC_BOTTOM = 4090, + AF_BLUE_STRING_OSAGE_CAPITAL_TOP = 4110, + AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM = 4150, + AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER = 4180, + AF_BLUE_STRING_OSAGE_SMALL_TOP = 4195, + AF_BLUE_STRING_OSAGE_SMALL_BOTTOM = 4235, + AF_BLUE_STRING_OSAGE_SMALL_ASCENDER = 4275, + AF_BLUE_STRING_OSAGE_SMALL_DESCENDER = 4300, + AF_BLUE_STRING_OSMANYA_TOP = 4315, + AF_BLUE_STRING_OSMANYA_BOTTOM = 4355, + AF_BLUE_STRING_ROHINGYA_TOP = 4395, + AF_BLUE_STRING_ROHINGYA_BOTTOM = 4420, + AF_BLUE_STRING_ROHINGYA_JOIN = 4445, + AF_BLUE_STRING_SAURASHTRA_TOP = 4448, + AF_BLUE_STRING_SAURASHTRA_BOTTOM = 4480, + AF_BLUE_STRING_SHAVIAN_TOP = 4500, + AF_BLUE_STRING_SHAVIAN_BOTTOM = 4510, + AF_BLUE_STRING_SHAVIAN_DESCENDER = 4535, + AF_BLUE_STRING_SHAVIAN_SMALL_TOP = 4545, + AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM = 4580, + AF_BLUE_STRING_SINHALA_TOP = 4595, + AF_BLUE_STRING_SINHALA_BOTTOM = 4627, + AF_BLUE_STRING_SINHALA_DESCENDER = 4659, + AF_BLUE_STRING_SUNDANESE_TOP = 4703, + AF_BLUE_STRING_SUNDANESE_BOTTOM = 4727, + AF_BLUE_STRING_SUNDANESE_DESCENDER = 4759, + AF_BLUE_STRING_TAI_VIET_TOP = 4767, + AF_BLUE_STRING_TAI_VIET_BOTTOM = 4787, + AF_BLUE_STRING_TAMIL_TOP = 4799, + AF_BLUE_STRING_TAMIL_BOTTOM = 4831, + AF_BLUE_STRING_TELUGU_TOP = 4863, + AF_BLUE_STRING_TELUGU_BOTTOM = 4891, + AF_BLUE_STRING_THAI_TOP = 4919, + AF_BLUE_STRING_THAI_BOTTOM = 4943, + AF_BLUE_STRING_THAI_ASCENDER = 4971, + AF_BLUE_STRING_THAI_LARGE_ASCENDER = 4983, + AF_BLUE_STRING_THAI_DESCENDER = 4995, + AF_BLUE_STRING_THAI_LARGE_DESCENDER = 5011, + AF_BLUE_STRING_THAI_DIGIT_TOP = 5019, + AF_BLUE_STRING_TIFINAGH = 5031, + AF_BLUE_STRING_VAI_TOP = 5063, + AF_BLUE_STRING_VAI_BOTTOM = 5095, + af_blue_1_1 = 5126, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRING_CJK_TOP = af_blue_1_1 + 1, + AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 203, + af_blue_1_1_1 = af_blue_1_1 + 404, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + AF_BLUE_STRING_CJK_LEFT = af_blue_1_1_1 + 1, + AF_BLUE_STRING_CJK_RIGHT = af_blue_1_1_1 + 204, + af_blue_1_1_2 = af_blue_1_1_1 + 405, +#else + af_blue_1_1_2 = af_blue_1_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_1_2 = af_blue_1_1_2 + 0, +#else + af_blue_1_2 = af_blue_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into style-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) +#define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN 8 + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { + AF_BLUE_STRINGSET_ADLM = 0, + AF_BLUE_STRINGSET_ARAB = 5, + AF_BLUE_STRINGSET_ARMN = 9, + AF_BLUE_STRINGSET_AVST = 16, + AF_BLUE_STRINGSET_BAMU = 19, + AF_BLUE_STRINGSET_BENG = 22, + AF_BLUE_STRINGSET_BUHD = 27, + AF_BLUE_STRINGSET_CAKM = 32, + AF_BLUE_STRINGSET_CANS = 36, + AF_BLUE_STRINGSET_CARI = 43, + AF_BLUE_STRINGSET_CHER = 46, + AF_BLUE_STRINGSET_COPT = 53, + AF_BLUE_STRINGSET_CPRT = 58, + AF_BLUE_STRINGSET_CYRL = 63, + AF_BLUE_STRINGSET_DEVA = 69, + AF_BLUE_STRINGSET_DSRT = 75, + AF_BLUE_STRINGSET_ETHI = 80, + AF_BLUE_STRINGSET_GEOR = 83, + AF_BLUE_STRINGSET_GEOK = 90, + AF_BLUE_STRINGSET_GLAG = 97, + AF_BLUE_STRINGSET_GOTH = 102, + AF_BLUE_STRINGSET_GREK = 105, + AF_BLUE_STRINGSET_GUJR = 112, + AF_BLUE_STRINGSET_GURU = 118, + AF_BLUE_STRINGSET_HEBR = 124, + AF_BLUE_STRINGSET_KNDA = 128, + AF_BLUE_STRINGSET_KALI = 131, + AF_BLUE_STRINGSET_KHMR = 137, + AF_BLUE_STRINGSET_KHMS = 143, + AF_BLUE_STRINGSET_LAO = 146, + AF_BLUE_STRINGSET_LATN = 152, + AF_BLUE_STRINGSET_LATB = 159, + AF_BLUE_STRINGSET_LATP = 166, + AF_BLUE_STRINGSET_LISU = 173, + AF_BLUE_STRINGSET_MLYM = 176, + AF_BLUE_STRINGSET_MEDF = 179, + AF_BLUE_STRINGSET_MONG = 187, + AF_BLUE_STRINGSET_MYMR = 190, + AF_BLUE_STRINGSET_NKOO = 195, + AF_BLUE_STRINGSET_NONE = 200, + AF_BLUE_STRINGSET_OLCK = 201, + AF_BLUE_STRINGSET_ORKH = 204, + AF_BLUE_STRINGSET_OSGE = 207, + AF_BLUE_STRINGSET_OSMA = 215, + AF_BLUE_STRINGSET_ROHG = 218, + AF_BLUE_STRINGSET_SAUR = 222, + AF_BLUE_STRINGSET_SHAW = 225, + AF_BLUE_STRINGSET_SINH = 231, + AF_BLUE_STRINGSET_SUND = 235, + AF_BLUE_STRINGSET_TAML = 239, + AF_BLUE_STRINGSET_TAVT = 242, + AF_BLUE_STRINGSET_TELU = 245, + AF_BLUE_STRINGSET_THAI = 248, + AF_BLUE_STRINGSET_TFNG = 256, + AF_BLUE_STRINGSET_VAII = 259, + af_blue_2_1 = 262, +#ifdef AF_CONFIG_OPTION_CJK + AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0, + af_blue_2_1_1 = af_blue_2_1 + 2, +#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + af_blue_2_1_2 = af_blue_2_1_1 + 2, +#else + af_blue_2_1_2 = af_blue_2_1_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + af_blue_2_2 = af_blue_2_1_2 + 1, +#else + af_blue_2_2 = af_blue_2_1 + 0, +#endif /* AF_CONFIG_OPTION_CJK */ + + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* AFBLUE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afblue.hin b/Dependencies/freetype/freetype/src/autofit/afblue.hin new file mode 100644 index 00000000..38031505 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afblue.hin @@ -0,0 +1,146 @@ +/**************************************************************************** + * + * afblue.h + * + * Auto-fitter data for blue strings (specification). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFBLUE_H_ +#define AFBLUE_H_ + + +FT_BEGIN_HEADER + + + /* an auxiliary macro to decode a UTF-8 character -- since we only use */ + /* hard-coded, self-converted data, no error checking is performed */ +#define GET_UTF8_CHAR( ch, p ) \ + do \ + { \ + ch = (unsigned char)*p++; \ + if ( ch >= 0x80 ) \ + { \ + FT_UInt len_; \ + \ + \ + if ( ch < 0xE0 ) \ + { \ + len_ = 1; \ + ch &= 0x1F; \ + } \ + else if ( ch < 0xF0 ) \ + { \ + len_ = 2; \ + ch &= 0x0F; \ + } \ + else \ + { \ + len_ = 3; \ + ch &= 0x07; \ + } \ + \ + for ( ; len_ > 0; len_-- ) \ + ch = ( ch << 6 ) | ( *p++ & 0x3F ); \ + } \ + } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* At the bottommost level, we define strings for finding blue zones. */ + + +#define AF_BLUE_STRING_MAX_LEN @AF_BLUE_STRING_MAX_LEN@ + + /* The AF_Blue_String enumeration values are offsets into the */ + /* `af_blue_strings' array. */ + + typedef enum AF_Blue_String_ + { +@AF_BLUE_STRING_ENUM@ + + AF_BLUE_STRING_MAX /* do not remove */ + + } AF_Blue_String; + + + FT_LOCAL_ARRAY( char ) + af_blue_strings[]; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** B L U E S T R I N G S E T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* The next level is to group blue strings into style-specific sets. */ + + + /* Properties are specific to a writing system. We assume that a given */ + /* blue string can't be used in more than a single writing system, which */ + /* is a safe bet. */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) +#define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) +#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) +#define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP + + +#define AF_BLUE_STRINGSET_MAX_LEN @AF_BLUE_STRINGSET_MAX_LEN@ + + /* The AF_Blue_Stringset enumeration values are offsets into the */ + /* `af_blue_stringsets' array. */ + + typedef enum AF_Blue_Stringset_ + { +@AF_BLUE_STRINGSET_ENUM@ + + AF_BLUE_STRINGSET_MAX /* do not remove */ + + } AF_Blue_Stringset; + + + typedef struct AF_Blue_StringRec_ + { + AF_Blue_String string; + FT_UShort properties; + + } AF_Blue_StringRec; + + + FT_LOCAL_ARRAY( AF_Blue_StringRec ) + af_blue_stringsets[]; + +/* */ + +FT_END_HEADER + + +#endif /* AFBLUE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afcjk.c b/Dependencies/freetype/freetype/src/autofit/afcjk.c new file mode 100644 index 00000000..869b6048 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afcjk.c @@ -0,0 +1,2383 @@ +/**************************************************************************** + * + * afcjk.c + * + * Auto-fitter hinting routines for CJK writing system (body). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* + * The algorithm is based on akito's autohint patch, archived at + * + * https://web.archive.org/web/20051219160454/http://www.kde.gr.jp:80/~akito/patch/freetype2/2.1.7/ + * + */ + +#include +#include + +#include "afglobal.h" +#include "aflatin.h" +#include "afcjk.h" + + +#ifdef AF_CONFIG_OPTION_CJK + +#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + +#include "aferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afcjk + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Basically the Latin version with AF_CJKMetrics */ + /* to replace AF_LatinMetrics. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face ) + { + /* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + + + FT_TRACE5(( "\n" )); + FT_TRACE5(( "cjk standard widths computation (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "===================================================\n" )); + FT_TRACE5(( "\n" )); + + af_glyph_hints_init( hints, face->memory ); + + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + + { + FT_Error error; + FT_ULong glyph_index; + int dim; + AF_CJKMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + + AF_StyleClass style_class = metrics->root.style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + const char* p; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong ch = 0; +#endif + + p = script_class->standard_charstring; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + /* We check a list of standard characters. The first match wins. */ + + glyph_index = 0; + while ( *p ) + { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index ) + break; + } + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + goto Exit; + + if ( !glyph_index ) + goto Exit; + + FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + ch, glyph_index )); + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + + FT_ZERO( dummy ); + + dummy->units_per_em = metrics->units_per_em; + + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); + + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + + + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + + /* + * We assume that the glyphs selected for the stem width + * computation are `featureless' enough so that the linking + * algorithm works fine without adjustments of its scoring + * function. + */ + af_latin_hints_link_segments( hints, + 0, + NULL, + (AF_Dimension)dim ); + + seg = axhints->segments; + limit = seg + axhints->num_segments; + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < AF_CJK_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + + /* this also replaces multiple almost identical stem widths */ + /* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + + + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); + + /* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE5(( "%s widths:\n", + dim == AF_DIMENSION_VERT ? "horizontal" + : "vertical" )); + + FT_TRACE5(( " %ld (standard)", axis->standard_width )); + for ( i = 1; i < axis->width_count; i++ ) + FT_TRACE5(( " %ld", axis->widths[i].org )); + + FT_TRACE5(( "\n" )); + } +#endif + } + } + + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } + + + /* Find all blue zones. */ + + static void + af_cjk_metrics_init_blues( AF_CJKMetrics metrics, + FT_Face face ) + { + FT_Pos fills[AF_BLUE_STRING_MAX_LEN]; + FT_Pos flats[AF_BLUE_STRING_MAX_LEN]; + + FT_UInt num_fills; + FT_UInt num_flats; + + FT_Bool fill; + + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_Outline outline; + + AF_StyleClass sc = metrics->root.style_class; + + AF_Blue_Stringset bss = sc->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + + /* we walk over the blue character strings as specified in the */ + /* style's entry in the `af_blue_stringset' array, computing its */ + /* extremum points (depending on the string properties) */ + + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "==========================\n" )); + FT_TRACE5(( "\n" )); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + + + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + axis = &metrics->axis[AF_DIMENSION_HORZ]; + else + axis = &metrics->axis[AF_DIMENSION_VERT]; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_String* cjk_blue_name[4] = + { + (FT_String*)"bottom", /* -- , -- */ + (FT_String*)"top", /* -- , TOP */ + (FT_String*)"left", /* HORIZ, -- */ + (FT_String*)"right" /* HORIZ, TOP */ + }; + + + FT_TRACE5(( "blue zone %d (%s):\n", + axis->blue_count, + cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | + AF_CJK_IS_TOP_BLUE( bs ) ] )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + num_fills = 0; + num_flats = 0; + + fill = 1; /* start with characters that define fill values */ + FT_TRACE5(( " [overshoot values]\n" )); + + while ( *p ) + { + FT_ULong glyph_index; + FT_Pos best_pos; /* same as points.y or points.x, resp. */ + FT_Int best_point; + FT_Vector* points; + + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* switch to characters that define flat values */ + if ( *p == '|' ) + { + fill = 0; + FT_TRACE5(( " [reference values]\n" )); + p++; + continue; + } + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + if ( error || outline.n_points <= 2 ) + { + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); + continue; + } + + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_pos = 0; /* make compiler happy */ + + { + FT_Int nn; + FT_Int pp, first, last; + + + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) + { + first = last + 1; + last = outline.contours[nn]; + + /* Avoid single-point contours since they are never rasterized. */ + /* In some fonts, they correspond to mark attachment points */ + /* which are way outside of the glyph's real outline. */ + if ( last <= first ) + continue; + + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + { + if ( AF_CJK_IS_RIGHT_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x > best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x < best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + } + } + else + { + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + } + } + } + + FT_TRACE5(( " U+%04lX: best_pos = %5ld\n", ch, best_pos )); + } + + if ( fill ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; + + } /* end while loop */ + + if ( num_flats == 0 && num_fills == 0 ) + { + /* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } + + /* we have computed the contents of the `fill' and `flats' tables, */ + /* now determine the reference and overshoot position of the blue -- */ + /* we simply take the median value after a simple sort */ + af_sort_pos( num_fills, fills ); + af_sort_pos( num_flats, flats ); + + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; + + axis->blue_count++; + + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = fills[num_fills / 2]; + } + else if ( num_fills == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = flats[num_flats / 2]; + } + + /* make sure blue_ref >= blue_shoot for top/right or */ + /* vice versa for bottom/left */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool under_ref = FT_BOOL( shoot < ref ); + + + /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */ + if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [reference smaller than overshoot," + " taking mean value]\n" )); + } + } + + blue->flags = 0; + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_CJK_BLUE_TOP; + + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); + + FT_TRACE5(( "\n" )); + + return; + } + + + /* Basically the Latin version with type AF_CJKMetrics for metrics. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ) + { + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + while ( *p ) + { + FT_ULong glyph_index; + unsigned int num_idx; + + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) + continue; + + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + + af_shaper_buf_destroy( face, shaper_buf ); + + metrics->root.digits_have_same_width = same_width; + } + + + /* Initialize global metrics. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + { + af_cjk_metrics_init_widths( metrics, face ); + af_cjk_metrics_init_blues( metrics, face ); + af_cjk_metrics_check_digits( metrics, face ); + } + + face->charmap = oldmap; + return FT_Err_Ok; + } + + + /* Adjust scaling value, then scale and shift widths */ + /* and blue zones (if applicable) for given dimension. */ + + static void + af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_CJKAxis axis; + FT_UInt nn; + + + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + + axis = &metrics->axis[dim]; + + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + + axis->org_scale = scale; + axis->org_delta = delta; + + axis->scale = scale; + axis->delta = delta; + + /* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_CJKBlue blue = &axis->blues[nn]; + FT_Pos dist; + + + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_CJK_BLUE_ACTIVE; + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { + FT_Pos delta1, delta2; + + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + + /* shoot is under shoot for cjk */ + delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + + delta2 = FT_MulFix( delta2, scale ); + + FT_TRACE5(( "delta: %ld", delta1 )); + if ( delta2 < 32 ) + delta2 = 0; +#if 0 + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); +#endif + else + delta2 = FT_PIX_ROUND( delta2 ); + FT_TRACE5(( "/%ld\n", delta2 )); + + if ( delta1 < 0 ) + delta2 = -delta2; + + blue->shoot.fit = blue->ref.fit - delta2; + + FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n", + ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', + nn, blue->ref.org, blue->shoot.org )); + FT_TRACE5(( " ref: cur=%.2f fit=%.2f\n", + (double)blue->ref.cur / 64, + (double)blue->ref.fit / 64 )); + FT_TRACE5(( " shoot: cur=%.2f fit=%.2f\n", + (double)blue->shoot.cur / 64, + (double)blue->shoot.fit / 64 )); + + blue->flags |= AF_CJK_BLUE_ACTIVE; + } + } + } + + + /* Scale global values in both directions. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_scale( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + AF_Scaler scaler ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + /* we copy the whole structure since the x and y scaling values */ + /* are not modified, contrary to e.g. the `latin' auto-hinter */ + metrics->root.scaler = *scaler; + + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + FT_CALLBACK_DEF( void ) + af_cjk_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Walk over all contours and compute its segments. */ + + static FT_Error + af_cjk_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + FT_Error error; + AF_Segment seg; + + + error = af_latin_hints_compute_segments( hints, dim ); + if ( error ) + return error; + + /* a segment is round if it doesn't have successive */ + /* on-curve points. */ + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Point pt = seg->first; + AF_Point last = seg->last; + FT_UInt f0 = pt->flags & AF_FLAG_CONTROL; + FT_UInt f1; + + + seg->flags &= ~AF_EDGE_ROUND; + + for ( ; pt != last; f0 = f1 ) + { + pt = pt->next; + f1 = pt->flags & AF_FLAG_CONTROL; + + if ( !f0 && !f1 ) + break; + + if ( pt == last ) + seg->flags |= AF_EDGE_ROUND; + } + } + + return FT_Err_Ok; + } + + + static void + af_cjk_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Direction major_dir = axis->major_dir; + AF_Segment seg1, seg2; + FT_Pos len_threshold; + FT_Pos dist_threshold; + + + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + + dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + dist_threshold = FT_DivFix( 64 * 3, dist_threshold ); + + /* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + if ( seg1->dir != major_dir ) + continue; + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 ) + { + FT_Pos dist = seg2->pos - seg1->pos; + + + if ( dist < 0 ) + continue; + + { + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len; + + + if ( min < seg2->min_coord ) + min = seg2->min_coord; + + if ( max > seg2->max_coord ) + max = seg2->max_coord; + + len = max - min; + if ( len >= len_threshold ) + { + if ( dist * 8 < seg1->score * 9 && + ( dist * 8 < seg1->score * 7 || seg1->len < len ) ) + { + seg1->score = dist; + seg1->len = len; + seg1->link = seg2; + } + + if ( dist * 8 < seg2->score * 9 && + ( dist * 8 < seg2->score * 7 || seg2->len < len ) ) + { + seg2->score = dist; + seg2->len = len; + seg2->link = seg1; + } + } + } + } + } + + /* + * now compute the `serif' segments + * + * In Hanzi, some strokes are wider on one or both of the ends. + * We either identify the stems on the ends as serifs or remove + * the linkage, depending on the length of the stems. + * + */ + + { + AF_Segment link1, link2; + + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + link1 = seg1->link; + if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos ) + continue; + + if ( seg1->score >= dist_threshold ) + continue; + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + if ( seg2->pos > seg1->pos || seg1 == seg2 ) + continue; + + link2 = seg2->link; + if ( !link2 || link2->link != seg2 || link2->pos < link1->pos ) + continue; + + if ( seg1->pos == seg2->pos && link1->pos == link2->pos ) + continue; + + if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score ) + continue; + + /* seg2 < seg1 < link1 < link2 */ + + if ( seg1->len >= seg2->len * 3 ) + { + AF_Segment seg; + + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Segment link = seg->link; + + + if ( link == seg2 ) + { + seg->link = NULL; + seg->serif = link1; + } + else if ( link == link2 ) + { + seg->link = NULL; + seg->serif = seg1; + } + } + } + else + { + seg1->link = link1->link = NULL; + + break; + } + } + } + } + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = NULL; + + if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 ) + seg1->serif = seg2->link; + } + } + } + } + + + static FT_Error + af_cjk_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = FT_Err_Ok; + FT_Memory memory = hints->memory; + AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; + + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + + FT_Fixed scale; + FT_Pos edge_distance_threshold; + + + axis->num_edges = 0; + + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + + /********************************************************************** + * + * We begin by generating a sorted table of edges for the current + * direction. To do so, we simply scan each segment and try to find + * an edge in our table that corresponds to its position. + * + * If no edge is found, we create and insert a new edge in the + * sorted table. Otherwise, we simply add the segment to the edge's + * list which is then processed in the second step to compute the + * edge's properties. + * + * Note that the edges table is sorted along the segment/edge + * position. + * + */ + + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = FT_DivFix( 64 / 4, scale ); + else + edge_distance_threshold = laxis->edge_distance_threshold; + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_Pos best = 0xFFFFU; + FT_UInt ee; + + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + if ( edge->dir != seg->dir ) + continue; + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold && dist < best ) + { + AF_Segment link = seg->link; + + + /* check whether all linked segments of the candidate edge */ + /* can make a single edge. */ + if ( link ) + { + AF_Segment seg1 = edge->first; + FT_Pos dist2 = 0; + + + do + { + AF_Segment link1 = seg1->link; + + + if ( link1 ) + { + dist2 = AF_SEGMENT_DIST( link, link1 ); + if ( dist2 >= edge_distance_threshold ) + break; + } + + } while ( ( seg1 = seg1->edge_next ) != edge->first ); + + if ( dist2 >= edge_distance_threshold ) + continue; + } + + best = dist; + found = edge; + } + } + + if ( !found ) + { + AF_Edge edge; + + + /* insert a new edge in the list and */ + /* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, 0, + memory, &edge ); + if ( error ) + goto Exit; + + /* add the segment to the new edge's list */ + FT_ZERO( edge ); + + edge->first = seg; + edge->last = seg; + edge->dir = seg->dir; + edge->fpos = seg->pos; + edge->opos = FT_MulFix( seg->pos, scale ); + edge->pos = edge->opos; + seg->edge_next = seg; + } + else + { + /* if an edge was found, simply add the segment to the edge's */ + /* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + /******************************************************************* + * + * Good, we now compute each edge's properties according to the + * segments found on its position. Basically, these are + * + * - the edge's main direction + * - stem edge, serif edge or both (which defaults to stem then) + * - rounded edge, straight or both (which defaults to straight) + * - link for edge + * + */ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + + /* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + /* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Int is_round = 0; /* does it contain round segments? */ + FT_Int is_straight = 0; /* does it contain straight segments? */ + + + seg = edge->first; + if ( !seg ) + goto Skip_Loop; + + do + { + FT_Bool is_serif; + + + /* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; + + /* check for links -- if seg->serif is set, then seg->link must */ + /* be ignored */ + is_serif = FT_BOOL( seg->serif && seg->serif->edge != edge ); + + if ( seg->link || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + + + edge2 = edge->link; + seg2 = seg->link; + + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = AF_SEGMENT_DIST( seg, seg2 ); + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + + Skip_Loop: + /* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; + + /* get rid of serifs if link is set */ + /* XXX: This gets rid of many unpleasant artefacts! */ + /* Example: the `c' in cour.pfa at size 13 */ + + if ( edge->serif && edge->link ) + edge->serif = NULL; + } + } + + Exit: + return error; + } + + + /* Detect segments and edges for given dimension. */ + + static FT_Error + af_cjk_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ) + { + FT_Error error; + + + error = af_cjk_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_cjk_hints_link_segments( hints, dim ); + + error = af_cjk_hints_compute_edges( hints, dim ); + } + return error; + } + + + /* Compute all edges which lie within blue zones. */ + + static void + af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, + AF_CJKMetrics metrics, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); + AF_CJKAxis cjk = &metrics->axis[dim]; + FT_Fixed scale = cjk->scale; + FT_Pos best_dist0; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); + + if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */ + best_dist0 = 64 / 2; + + /* compute which blue zones are active, i.e. have their scaled */ + /* size < 3/4 pixels */ + + /* If the distant between an edge and a blue zone is shorter than */ + /* best_dist0, set the blue zone for the edge. Then search for */ + /* the blue zone with the smallest best_dist to the edge. */ + + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Pos best_dist = best_dist0; + + + for ( bb = 0; bb < cjk->blue_count; bb++ ) + { + AF_CJKBlue blue = cjk->blues + bb; + FT_Bool is_top_right_blue, is_major_dir; + + + /* skip inactive blue zones (i.e., those that are too small) */ + if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) ) + continue; + + /* if it is a top zone, check for right edges -- if it is a bottom */ + /* zone, check for left edges */ + /* */ + /* of course, that's for TrueType */ + is_top_right_blue = + (FT_Byte)( ( blue->flags & AF_CJK_BLUE_TOP ) != 0 ); + is_major_dir = + FT_BOOL( edge->dir == axis->major_dir ); + + /* if it is a top zone, the edge must be against the major */ + /* direction; if it is a bottom zone, it must be in the major */ + /* direction */ + if ( is_top_right_blue ^ is_major_dir ) + { + FT_Pos dist; + AF_Width compare; + + + /* Compare the edge to the closest blue zone type */ + if ( FT_ABS( edge->fpos - blue->ref.org ) > + FT_ABS( edge->fpos - blue->shoot.org ) ) + compare = &blue->shoot; + else + compare = &blue->ref; + + dist = edge->fpos - compare->org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = compare; + } + } + } + + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + + + /* Initalize hinting engine. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); + + /* + * correct x_scale and y_scale when needed, since they may have + * been modified af_cjk_scale_dim above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; + + /* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; + + scaler_flags = hints->scaler_flags; + other_flags = 0; + + /* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; + + /* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; + + /* + * We adjust stems to full pixels unless in `light' or `lcd' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; + + scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; + + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L Y P H G R I D - F I T T I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Snap a given width in scaled coordinates to one of the */ + /* current standard widths. */ + + static FT_Pos + af_cjk_snap_width( AF_Width widths, + FT_UInt count, + FT_Pos width ) + { + FT_UInt n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + + + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + scaled = FT_PIX_ROUND( reference ); + + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + + return width; + } + + + /* Compute the snapped width of a given stem. */ + /* There is a lot of voodoo in this function; changing the hard-coded */ + /* parameters influence the whole hinting process. */ + + static FT_Pos + af_cjk_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + FT_UInt base_flags, + FT_UInt stem_flags ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics; + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT ); + + FT_UNUSED( base_flags ); + FT_UNUSED( stem_flags ); + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + return width; + + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { + /* smooth hinting process: very lightly quantize the stem width */ + + if ( axis->width_count > 0 ) + { + if ( FT_ABS( dist - axis->widths[0].cur ) < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } + } + + if ( dist < 54 ) + dist += ( 54 - dist ) / 2; + else if ( dist < 3 * 64 ) + { + FT_Pos delta; + + + delta = dist & 63; + dist &= -64; + + if ( delta < 10 ) + dist += delta; + else if ( delta < 22 ) + dist += 10; + else if ( delta < 42 ) + dist += delta; + else if ( delta < 54 ) + dist += 54; + else + dist += delta; + } + } + else + { + /* strong hinting process: snap the stem width to integer pixels */ + + dist = af_cjk_snap_width( axis->widths, axis->width_count, dist ); + + if ( vertical ) + { + /* in the case of vertical hinting, always round */ + /* the stem heights to integer pixels */ + + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { + /* monochrome horizontal hinting: snap widths to integer pixels */ + /* with a different threshold */ + + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { + /* for horizontal anti-aliased hinting, we adopt a more subtle */ + /* approach: we strengthen small stems, round stems whose size */ + /* is between 1 and 2 pixels to an integer, otherwise nothing */ + + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + + else if ( dist < 128 ) + dist = ( dist + 22 ) & ~63; + else + /* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + + Done_Width: + if ( sign ) + dist = -dist; + + return dist; + } + + + /* Align one stem edge relative to the previous stem edge. */ + + static void + af_cjk_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + + FT_Pos fitted_width = af_cjk_compute_stem_width( hints, dim, dist, + base_edge->flags, + stem_edge->flags ); + + + stem_edge->pos = base_edge->pos + fitted_width; + + FT_TRACE5(( " CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f," + " dist was %.2f, now %.2f\n", + stem_edge - hints->axis[dim].edges, stem_edge->fpos, + (double)stem_edge->opos / 64, + (double)stem_edge->pos / 64, + (double)dist / 64, + (double)fitted_width / 64 )); + } + + + /* Shift the coordinates of the `serif' edge by the same amount */ + /* as the corresponding `base' edge has been moved already. */ + + static void + af_cjk_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + + serif->pos = base->pos + ( serif->opos - base->opos ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define AF_LIGHT_MODE_MAX_HORZ_GAP 9 +#define AF_LIGHT_MODE_MAX_VERT_GAP 15 +#define AF_LIGHT_MODE_MAX_DELTA_ABS 14 + + + static FT_Pos + af_hint_normal_stem( AF_GlyphHints hints, + AF_Edge edge, + AF_Edge edge2, + FT_Pos anchor, + AF_Dimension dim ) + { + FT_Pos org_len, cur_len, org_center; + FT_Pos cur_pos1, cur_pos2; + FT_Pos d_off1, u_off1, d_off2, u_off2, delta; + FT_Pos offset; + FT_Pos threshold = 64; + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( ( edge->flags & AF_EDGE_ROUND ) && + ( edge2->flags & AF_EDGE_ROUND ) ) + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP; + } + else + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3; + } + } + + org_len = edge2->opos - edge->opos; + cur_len = af_cjk_compute_stem_width( hints, dim, org_len, + edge->flags, + edge2->flags ); + + org_center = ( edge->opos + edge2->opos ) / 2 + anchor; + cur_pos1 = org_center - cur_len / 2; + cur_pos2 = cur_pos1 + cur_len; + d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 ); + d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 ); + u_off1 = 64 - d_off1; + u_off2 = 64 - d_off2; + delta = 0; + + + if ( d_off1 == 0 || d_off2 == 0 ) + goto Exit; + + if ( cur_len <= threshold ) + { + if ( d_off2 < cur_len ) + { + if ( u_off1 <= d_off2 ) + delta = u_off1; + else + delta = -d_off2; + } + + goto Exit; + } + + if ( threshold < 64 ) + { + if ( d_off1 >= threshold || u_off1 >= threshold || + d_off2 >= threshold || u_off2 >= threshold ) + goto Exit; + } + + offset = cur_len & 63; + + if ( offset < 32 ) + { + if ( u_off1 <= offset || d_off2 <= offset ) + goto Exit; + } + else + offset = 64 - threshold; + + d_off1 = threshold - u_off1; + u_off1 = u_off1 - offset; + u_off2 = threshold - d_off2; + d_off2 = d_off2 - offset; + + if ( d_off1 <= u_off1 ) + u_off1 = -d_off1; + + if ( d_off2 <= u_off2 ) + u_off2 = -d_off2; + + if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) ) + delta = u_off1; + else + delta = u_off2; + + Exit: + +#if 1 + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = AF_LIGHT_MODE_MAX_DELTA_ABS; + else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = -AF_LIGHT_MODE_MAX_DELTA_ABS; + } +#endif + + cur_pos1 += delta; + + if ( edge->opos < edge2->opos ) + { + edge->pos = cur_pos1; + edge2->pos = cur_pos1 + cur_len; + } + else + { + edge->pos = cur_pos1 + cur_len; + edge2->pos = cur_pos1; + } + + return delta; + } + + + /* The main grid-fitting routine. */ + + static void + af_cjk_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = NULL; + FT_Pos delta = 0; + FT_Int skipped = 0; + FT_Bool has_last_stem = FALSE; + FT_Pos last_stem_pos = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "cjk %s edge hinting (style `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_style_names[hints->metrics->style_class->style] )); + + /* we begin by aligning all stems relative to the blue zone */ + + if ( AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + + if ( blue ) + { + edge1 = edge; + } + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + if ( !edge1 ) + continue; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, edge1->fpos, (double)edge1->opos / 64, + (double)blue->fit / 64, (double)edge1->pos / 64 )); + + num_actions++; +#endif + + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + + if ( edge2 && !edge2->blue_edge ) + { + af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + } + + if ( !anchor ) + anchor = edge; + } + } + + /* now we align all stem edges. */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + /* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + skipped++; + continue; + } + + /* Some CJK characters have so many stems that + * the hinter is likely to merge two adjacent ones. + * To solve this problem, if either edge of a stem + * is too close to the previous one, we avoid + * aligning the two edges, but rather interpolate + * their locations at the end of this function in + * order to preserve the space between the stems. + */ + if ( has_last_stem && + ( edge->pos < last_stem_pos + 64 || + edge2->pos < last_stem_pos + 64 ) ) + { + skipped++; + continue; + } + + /* now align the stem */ + + /* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( "ASSERTION FAILED for edge %td\n", edge2 - edges )); + + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + continue; + } + + if ( edge2 < edge ) + { + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + /* We rarely reaches here it seems; + * usually the two edges belonging + * to one stem are marked as DONE together + */ + has_last_stem = TRUE; + last_stem_pos = edge->pos; + continue; + } + + if ( dim != AF_DIMENSION_VERT && !anchor ) + { + +#if 0 + if ( fixedpitch ) + { + AF_Edge left = edge; + AF_Edge right = edge_limit - 1; + AF_EdgeRec left1, left2, right1, right2; + FT_Pos target, center1, center2; + FT_Pos delta1, delta2, d1, d2; + + + while ( right > left && !right->link ) + right--; + + left1 = *left; + left2 = *left->link; + right1 = *right->link; + right2 = *right; + + delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; + target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; + + delta1 = delta; + delta1 += af_hint_normal_stem( hints, left, left->link, + delta1, 0 ); + + if ( left->link != right ) + af_hint_normal_stem( hints, right->link, right, delta1, 0 ); + + center1 = left->pos + ( right->pos - left->pos ) / 2; + + if ( center1 >= target ) + delta2 = delta - 32; + else + delta2 = delta + 32; + + delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); + + if ( delta1 != delta2 ) + { + if ( left->link != right ) + af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); + + center2 = left1.pos + ( right2.pos - left1.pos ) / 2; + + d1 = center1 - target; + d2 = center2 - target; + + if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) + { + left->pos = left1.pos; + left->link->pos = left2.pos; + + if ( left->link != right ) + { + right->link->pos = right1.pos; + right->pos = right2.pos; + } + + delta1 = delta2; + } + } + + delta = delta1; + right->link->flags |= AF_EDGE_DONE; + right->flags |= AF_EDGE_DONE; + } + else + +#endif /* 0 */ + + delta = af_hint_normal_stem( hints, edge, edge2, 0, + AF_DIMENSION_HORZ ); + } + else + af_hint_normal_stem( hints, edge, edge2, delta, dim ); + +#if 0 + printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n", + edge - edges, edge2 - edges, + (double)( edge->pos - edge->opos ) / 64, + (double)( edge2->pos - edge2->opos ) / 64 ); +#endif + + anchor = edge; + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + has_last_stem = TRUE; + last_stem_pos = edge2->pos; + } + + /* make sure that lowercase m's maintain their symmetry */ + + /* In general, lowercase m's have six vertical edges if they are sans */ + /* serif, or twelve if they are with serifs. This implementation is */ + /* based on that assumption, and seems to work very well with most */ + /* faces. However, if for a certain face this assumption is not */ + /* true, the m is just rendered like before. In addition, any stem */ + /* correction will only be applied to symmetrical glyphs (even if the */ + /* glyph is not an m), so the potential for unwanted distortion is */ + /* relatively low. */ + + /* We don't handle horizontal edges since we can't easily assure that */ + /* the third (lowest) stem aligns with the base line; it might end up */ + /* one pixel higher or lower. */ + + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span; + + + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + + if ( edge1->link == edge1 + 1 && + edge2->link == edge2 + 1 && + edge3->link == edge3 + 1 && span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; + + /* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + + if ( !skipped ) + goto Exit; + + /* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + if ( edge->flags & AF_EDGE_DONE ) + continue; + + if ( edge->serif ) + { + af_cjk_align_serif_edge( hints, edge->serif, edge ); + edge->flags |= AF_EDGE_DONE; + skipped--; + } + } + + if ( !skipped ) + goto Exit; + + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge before, after; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + before = after = edge; + + while ( --before >= edges ) + if ( before->flags & AF_EDGE_DONE ) + break; + + while ( ++after < edge_limit ) + if ( after->flags & AF_EDGE_DONE ) + break; + + if ( before >= edges || after < edge_limit ) + { + if ( before < edges ) + af_cjk_align_serif_edge( hints, after, edge ); + else if ( after >= edge_limit ) + af_cjk_align_serif_edge( hints, before, edge ); + else + { + if ( after->fpos == before->fpos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->fpos - before->fpos, + after->pos - before->pos, + after->fpos - before->fpos ); + } + } + } + + Exit: + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + + return; + } + + + static void + af_cjk_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + FT_Bool snapping; + + + snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ && + AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) || + ( dim == AF_DIMENSION_VERT && + AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ); + + for ( edge = edges; edge < edge_limit; edge++ ) + { + /* move the points of each segment */ + /* in each edge to the edge's position */ + AF_Segment seg = edge->first; + + + if ( snapping ) + { + do + { + AF_Point point = seg->first; + + + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + else + { + FT_Pos delta = edge->pos - edge->opos; + + + do + { + AF_Point point = seg->first; + + + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x += delta; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y += delta; + point->flags |= AF_FLAG_TOUCH_Y; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + } + } + + + /* Apply the complete hinting algorithm to a CJK glyph. */ + + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + FT_Error error; + int dim; + + FT_UNUSED( metrics ); + FT_UNUSED( glyph_index ); + + + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; + + /* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ ); + } + + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT ); + } + + /* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_cjk_hint_edges( hints, (AF_Dimension)dim ); + af_cjk_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + + af_glyph_hints_save( hints, outline ); + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_cjk_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_cjk_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_cjk_hints_apply /* style_hints_apply */ + ) + + +#else /* !AF_CONFIG_OPTION_CJK */ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, + + AF_WRITING_SYSTEM_CJK, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) NULL, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) NULL /* style_hints_apply */ + ) + + +#endif /* !AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afcjk.h b/Dependencies/freetype/freetype/src/autofit/afcjk.h new file mode 100644 index 00000000..bc5aaf12 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afcjk.h @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * afcjk.h + * + * Auto-fitter hinting routines for CJK writing system (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFCJK_H_ +#define AFCJK_H_ + +#include "afhints.h" +#include "aflatin.h" + + +FT_BEGIN_HEADER + + + /* the CJK-specific writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C J K G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * CJK glyphs tend to fill the square. So we have both vertical and + * horizontal blue zones. But some glyphs have flat bounding strokes that + * leave some space between neighbour glyphs. + */ + +#define AF_CJK_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_TOP ) +#define AF_CJK_IS_HORIZ_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_CJK_HORIZ ) +#define AF_CJK_IS_RIGHT_BLUE AF_CJK_IS_TOP_BLUE + +#define AF_CJK_MAX_WIDTHS 16 + + +#define AF_CJK_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_CJK_BLUE_TOP ( 1U << 1 ) /* result of AF_CJK_IS_TOP_BLUE */ +#define AF_CJK_BLUE_ADJUSTMENT ( 1U << 2 ) /* used for scale adjustment */ + /* optimization */ + + + typedef struct AF_CJKBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; /* undershoot */ + FT_UInt flags; + + } AF_CJKBlueRec, *AF_CJKBlue; + + + typedef struct AF_CJKAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ + + /* used for horizontal metrics too for CJK */ + FT_Bool control_overshoot; + FT_UInt blue_count; + AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; + + FT_Fixed org_scale; + FT_Pos org_delta; + + } AF_CJKAxisRec, *AF_CJKAxis; + + + typedef struct AF_CJKMetricsRec_ + { + AF_StyleMetricsRec root; + FT_UInt units_per_em; + AF_CJKAxisRec axis[AF_DIMENSION_MAX]; + + } AF_CJKMetricsRec, *AF_CJKMetrics; + + +#ifdef AF_CONFIG_OPTION_CJK + FT_LOCAL( FT_Error ) + af_cjk_metrics_init( AF_StyleMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_cjk_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + FT_LOCAL( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + FT_LOCAL( FT_Error ) + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); + + /* shared; called from afindic.c */ + FT_LOCAL( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face ); +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* */ + +FT_END_HEADER + +#endif /* AFCJK_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afcover.h b/Dependencies/freetype/freetype/src/autofit/afcover.h new file mode 100644 index 00000000..7980cf2e --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afcover.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * + * afcover.h + * + * Auto-fitter coverages (specification only). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* This header file can be included multiple times. */ + /* Define `COVERAGE' as needed. */ + + + /* Add new coverages here. The first and second arguments are the */ + /* coverage name in lowercase and uppercase, respectively, followed */ + /* by a description string. The last four arguments are the four */ + /* characters defining the corresponding OpenType feature. */ + +#if 0 + /* XXX: It's not possible to define blue zone characters in advance. */ + COVERAGE( alternative_fractions, ALTERNATIVE_FRACTIONS, + "alternative fractions", + 'a', 'f', 'r', 'c' ) +#endif + + COVERAGE( petite_capitals_from_capitals, PETITE_CAPITALS_FROM_CAPITALS, + "petite capitals from capitals", + 'c', '2', 'c', 'p' ) + + COVERAGE( small_capitals_from_capitals, SMALL_CAPITALS_FROM_CAPITALS, + "small capitals from capitals", + 'c', '2', 's', 'c' ) + +#if 0 + /* XXX: Only digits are in this coverage, however, both normal style */ + /* and oldstyle representation forms are possible. */ + COVERAGE( denominators, DENOMINATORS, + "denominators", + 'd', 'n', 'o', 'm' ) +#endif + +#if 0 + /* XXX: It's not possible to define blue zone characters in advance. */ + COVERAGE( fractions, FRACTIONS, + "fractions", + 'f', 'r', 'a', 'c' ) +#endif + +#if 0 + /* XXX: Only digits are in this coverage, however, both normal style */ + /* and oldstyle representation forms are possible. */ + COVERAGE( numerators, NUMERATORS, + "numerators", + 'n', 'u', 'm', 'r' ) +#endif + + COVERAGE( ordinals, ORDINALS, + "ordinals", + 'o', 'r', 'd', 'n' ) + + COVERAGE( petite_capitals, PETITE_CAPITALS, + "petite capitals", + 'p', 'c', 'a', 'p' ) + + COVERAGE( ruby, RUBY, + "ruby", + 'r', 'u', 'b', 'y' ) + + COVERAGE( scientific_inferiors, SCIENTIFIC_INFERIORS, + "scientific inferiors", + 's', 'i', 'n', 'f' ) + + COVERAGE( small_capitals, SMALL_CAPITALS, + "small capitals", + 's', 'm', 'c', 'p' ) + + COVERAGE( subscript, SUBSCRIPT, + "subscript", + 's', 'u', 'b', 's' ) + + COVERAGE( superscript, SUPERSCRIPT, + "superscript", + 's', 'u', 'p', 's' ) + + COVERAGE( titling, TITLING, + "titling", + 't', 'i', 't', 'l' ) + +#if 0 + /* to be always excluded */ + COVERAGE(nalt, 'n', 'a', 'l', 't'); /* Alternate Annotation Forms (?) */ + COVERAGE(ornm, 'o', 'r', 'n', 'm'); /* Ornaments (?) */ +#endif + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afdummy.c b/Dependencies/freetype/freetype/src/autofit/afdummy.c new file mode 100644 index 00000000..ad667d2e --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afdummy.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * afdummy.c + * + * Auto-fitter dummy routines to be used if no hinting should be + * performed (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afdummy.h" +#include "afhints.h" +#include "aferrors.h" + + + static FT_Error + af_dummy_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + af_glyph_hints_rescale( hints, metrics ); + + hints->x_scale = metrics->scaler.x_scale; + hints->y_scale = metrics->scaler.y_scale; + hints->x_delta = metrics->scaler.x_delta; + hints->y_delta = metrics->scaler.y_delta; + + return FT_Err_Ok; + } + + + static FT_Error + af_dummy_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ) + { + FT_Error error; + + FT_UNUSED( glyph_index ); + FT_UNUSED( metrics ); + + + error = af_glyph_hints_reload( hints, outline ); + if ( !error ) + af_glyph_hints_save( hints, outline ); + + return error; + } + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_dummy_writing_system_class, + + AF_WRITING_SYSTEM_DUMMY, + + sizeof ( AF_StyleMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_dummy_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_dummy_hints_apply /* style_hints_apply */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afdummy.h b/Dependencies/freetype/freetype/src/autofit/afdummy.h new file mode 100644 index 00000000..613c2f88 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afdummy.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * afdummy.h + * + * Auto-fitter dummy routines to be used if no hinting should be + * performed (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFDUMMY_H_ +#define AFDUMMY_H_ + +#include "aftypes.h" + + +FT_BEGIN_HEADER + + /* A dummy writing system used when no hinting should be performed. */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_dummy_writing_system_class ) + +/* */ + +FT_END_HEADER + + +#endif /* AFDUMMY_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/aferrors.h b/Dependencies/freetype/freetype/src/autofit/aferrors.h new file mode 100644 index 00000000..ae584ff0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/aferrors.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * aferrors.h + * + * Autofitter error codes (specification only). + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Autofitter error enumeration + * constants. + * + */ + +#ifndef AFERRORS_H_ +#define AFERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX AF_Err_ +#define FT_ERR_BASE FT_Mod_Err_Autofit + +#include + +#endif /* AFERRORS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afglobal.c b/Dependencies/freetype/freetype/src/autofit/afglobal.c new file mode 100644 index 00000000..b7403fa6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afglobal.c @@ -0,0 +1,513 @@ +/**************************************************************************** + * + * afglobal.c + * + * Auto-fitter routines to compute global hinting values (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afranges.h" +#include "afshaper.h" +#include "afws-decl.h" +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afglobal + + +#include "aferrors.h" + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_DEFINE_SCRIPT_CLASS( \ + af_ ## s ## _script_class, \ + AF_SCRIPT_ ## S, \ + af_ ## s ## _uniranges, \ + af_ ## s ## _nonbase_uniranges, \ + AF_ ## H, \ + ss ) + +#include "afscript.h" + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_DEFINE_STYLE_CLASS( \ + af_ ## s ## _style_class, \ + AF_STYLE_ ## S, \ + ws, \ + sc, \ + ss, \ + c ) + +#include "afstyles.h" + + +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + &af_ ## ws ## _writing_system_class, + + FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) + af_writing_system_classes[] = + { + +#include "afws-iter.h" + + NULL /* do not remove */ + }; + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + &af_ ## s ## _script_class, + + FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) + af_script_classes[] = + { + +#include "afscript.h" + + NULL /* do not remove */ + }; + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + &af_ ## s ## _style_class, + + FT_LOCAL_ARRAY_DEF( AF_StyleClass ) + af_style_classes[] = + { + +#include "afstyles.h" + + NULL /* do not remove */ + }; + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) #s, + + FT_LOCAL_ARRAY_DEF( char* ) + af_style_names[] = + { + +#include "afstyles.h" + + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /* Compute the style index of each glyph within a given face. */ + + static FT_Error + af_face_globals_compute_style_coverage( AF_FaceGlobals globals ) + { + FT_Error error; + FT_Face face = globals->face; + FT_CharMap old_charmap = face->charmap; + FT_UShort* gstyles = globals->glyph_styles; + FT_UShort ss; + FT_UShort dflt = 0xFFFFU; /* a non-valid value */ + FT_UInt i; + + + /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ + for ( i = 0; i < globals->glyph_count; i++ ) + gstyles[i] = AF_STYLE_UNASSIGNED; + + error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); + if ( error ) + { + /* + * Ignore this error; we simply use the fallback style. + * XXX: Shouldn't we rather disable hinting? + */ + error = FT_Err_Ok; + goto Exit; + } + + /* scan each style in a Unicode charmap */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = + af_style_classes[ss]; + AF_ScriptClass script_class = + af_script_classes[style_class->script]; + AF_Script_UniRange range; + + + if ( !script_class->script_uni_ranges ) + continue; + + /* + * Scan all Unicode points in the range and set the corresponding + * glyph style index. + */ + if ( style_class->coverage == AF_COVERAGE_DEFAULT ) + { + if ( style_class->script == globals->module->default_script ) + dflt = ss; + + for ( range = script_class->script_uni_ranges; + range->first != 0; + range++ ) + { + FT_ULong charcode = range->first; + FT_UInt gindex; + + + gindex = FT_Get_Char_Index( face, charcode ); + + if ( gindex != 0 && + gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + gstyles[gindex] = ss; + + for (;;) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + + if ( gindex == 0 || charcode > range->last ) + break; + + if ( gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + gstyles[gindex] = ss; + } + } + + /* do the same for the script's non-base characters */ + for ( range = script_class->script_uni_nonbase_ranges; + range->first != 0; + range++ ) + { + FT_ULong charcode = range->first; + FT_UInt gindex; + + + gindex = FT_Get_Char_Index( face, charcode ); + + if ( gindex != 0 && + gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) + gstyles[gindex] |= AF_NONBASE; + + for (;;) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + + if ( gindex == 0 || charcode > range->last ) + break; + + if ( gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) + gstyles[gindex] |= AF_NONBASE; + } + } + } + else + { + /* get glyphs not directly addressable by cmap */ + af_shaper_get_coverage( globals, style_class, gstyles, 0 ); + } + } + + /* handle the remaining default OpenType features ... */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + + + if ( style_class->coverage == AF_COVERAGE_DEFAULT ) + af_shaper_get_coverage( globals, style_class, gstyles, 0 ); + } + + /* ... and finally the default OpenType features of the default script */ + af_shaper_get_coverage( globals, af_style_classes[dflt], gstyles, 1 ); + + /* mark ASCII digits */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt gindex = FT_Get_Char_Index( face, i ); + + + if ( gindex != 0 && gindex < globals->glyph_count ) + gstyles[gindex] |= AF_DIGIT; + } + + Exit: + /* + * By default, all uncovered glyphs are set to the fallback style. + * XXX: Shouldn't we disable hinting or do something similar? + */ + if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) + { + FT_UInt nn; + + + for ( nn = 0; nn < globals->glyph_count; nn++ ) + { + if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) + { + gstyles[nn] &= ~AF_STYLE_MASK; + gstyles[nn] |= globals->module->fallback_style; + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + + FT_TRACE4(( "\n" )); + FT_TRACE4(( "style coverage\n" )); + FT_TRACE4(( "==============\n" )); + FT_TRACE4(( "\n" )); + + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + FT_UInt count = 0; + FT_UInt idx; + + + FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); + + for ( idx = 0; idx < globals->glyph_count; idx++ ) + { + if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style ) + { + if ( !( count % 10 ) ) + FT_TRACE4(( " " )); + + FT_TRACE4(( " %d", idx )); + count++; + + if ( !( count % 10 ) ) + FT_TRACE4(( "\n" )); + } + } + + if ( !count ) + FT_TRACE4(( " (none)\n" )); + if ( count % 10 ) + FT_TRACE4(( "\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + face->charmap = old_charmap; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + af_face_globals_new( FT_Face face, + AF_FaceGlobals *aglobals, + AF_Module module ) + { + FT_Error error; + FT_Memory memory; + AF_FaceGlobals globals = NULL; + + + memory = face->memory; + + /* we allocate an AF_FaceGlobals structure together */ + /* with the glyph_styles array */ + if ( FT_QALLOC( globals, + sizeof ( *globals ) + + (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) + goto Exit; + + FT_ZERO( &globals->metrics ); + + globals->face = face; + globals->glyph_count = (FT_UInt)face->num_glyphs; + /* right after the globals structure come the glyph styles */ + globals->glyph_styles = (FT_UShort*)( globals + 1 ); + globals->module = module; + globals->stem_darkening_for_ppem = 0; + globals->darken_x = 0; + globals->darken_y = 0; + globals->standard_vertical_width = 0; + globals->standard_horizontal_width = 0; + globals->scale_down_factor = 0; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + globals->hb_font = hb_ft_font_create_( face, NULL ); + globals->hb_buf = hb_buffer_create(); +#endif + + error = af_face_globals_compute_style_coverage( globals ); + if ( error ) + { + af_face_globals_free( globals ); + globals = NULL; + } + else + globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; + + Exit: + *aglobals = globals; + return error; + } + + + FT_LOCAL_DEF( void ) + af_face_globals_free( void* globals_ ) + { + AF_FaceGlobals globals = (AF_FaceGlobals)globals_; + + + if ( globals ) + { + FT_Memory memory = globals->face->memory; + FT_UInt nn; + + + for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) + { + if ( globals->metrics[nn] ) + { + AF_StyleClass style_class = + af_style_classes[nn]; + AF_WritingSystemClass writing_system_class = + af_writing_system_classes[style_class->writing_system]; + + + if ( writing_system_class->style_metrics_done ) + writing_system_class->style_metrics_done( globals->metrics[nn] ); + + FT_FREE( globals->metrics[nn] ); + } + } + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + hb_font_destroy( globals->hb_font ); + hb_buffer_destroy( globals->hb_buf ); +#endif + + /* no need to free `globals->glyph_styles'; */ + /* it is part of the `globals' array */ + FT_FREE( globals ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + af_face_globals_get_metrics( AF_FaceGlobals globals, + FT_UInt gindex, + FT_UInt options, + AF_StyleMetrics *ametrics ) + { + AF_StyleMetrics metrics = NULL; + + AF_Style style = (AF_Style)options; + AF_WritingSystemClass writing_system_class; + AF_StyleClass style_class; + + FT_Error error = FT_Err_Ok; + + + if ( gindex >= globals->glyph_count ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if we have a forced style (via `options'), use it, */ + /* otherwise look into `glyph_styles' array */ + if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) + style = (AF_Style)( globals->glyph_styles[gindex] & + AF_STYLE_UNASSIGNED ); + + Again: + style_class = af_style_classes[style]; + writing_system_class = af_writing_system_classes + [style_class->writing_system]; + + metrics = globals->metrics[style]; + if ( !metrics ) + { + /* create the global metrics object if necessary */ + FT_Memory memory = globals->face->memory; + + + if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) + goto Exit; + + metrics->style_class = style_class; + metrics->globals = globals; + + if ( writing_system_class->style_metrics_init ) + { + error = writing_system_class->style_metrics_init( metrics, + globals->face ); + if ( error ) + { + if ( writing_system_class->style_metrics_done ) + writing_system_class->style_metrics_done( metrics ); + + FT_FREE( metrics ); + + /* internal error code -1 indicates */ + /* that no blue zones have been found */ + if ( error == -1 ) + { + style = (AF_Style)( globals->glyph_styles[gindex] & + AF_STYLE_UNASSIGNED ); + /* IMPORTANT: Clear the error code, see + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063 + */ + error = FT_Err_Ok; + goto Again; + } + + goto Exit; + } + } + + globals->metrics[style] = metrics; + } + + Exit: + *ametrics = metrics; + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ) + { + if ( gindex < globals->glyph_count ) + return FT_BOOL( globals->glyph_styles[gindex] & AF_DIGIT ); + + return FT_BOOL( 0 ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afglobal.h b/Dependencies/freetype/freetype/src/autofit/afglobal.h new file mode 100644 index 00000000..ddb54c89 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afglobal.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * afglobal.h + * + * Auto-fitter routines to compute global hinting values + * (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFGLOBAL_H_ +#define AFGLOBAL_H_ + + +#include "aftypes.h" +#include "afmodule.h" +#include "afshaper.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL_ARRAY( AF_WritingSystemClass ) + af_writing_system_classes[]; + + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class ) + +#include "afscript.h" + + FT_LOCAL_ARRAY( AF_ScriptClass ) + af_script_classes[]; + + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_DECLARE_STYLE_CLASS( af_ ## s ## _style_class ) + +#include "afstyles.h" + + FT_LOCAL_ARRAY( AF_StyleClass ) + af_style_classes[]; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_LOCAL_ARRAY( char* ) + af_style_names[]; +#endif + + + /* + * Default values and flags for both autofitter globals (found in + * AF_ModuleRec) and face globals (in AF_FaceGlobalsRec). + */ + + /* index of fallback style in `af_style_classes' */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_STYLE_FALLBACK AF_STYLE_HANI_DFLT +#else +#define AF_STYLE_FALLBACK AF_STYLE_NONE_DFLT +#endif + /* default script for OpenType; ignored if HarfBuzz isn't used */ +#define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN + + /* a bit mask for AF_DIGIT and AF_NONBASE */ +#define AF_STYLE_MASK 0x3FFF + /* an uncovered glyph */ +#define AF_STYLE_UNASSIGNED AF_STYLE_MASK + + /* if this flag is set, we have an ASCII digit */ +#define AF_DIGIT 0x8000U + /* if this flag is set, we have a non-base character */ +#define AF_NONBASE 0x4000U + + /* `increase-x-height' property */ +#define AF_PROP_INCREASE_X_HEIGHT_MIN 6 +#define AF_PROP_INCREASE_X_HEIGHT_MAX 0 + + + /************************************************************************/ + /************************************************************************/ + /***** *****/ + /***** F A C E G L O B A L S *****/ + /***** *****/ + /************************************************************************/ + /************************************************************************/ + + + /* + * Note that glyph_styles[] maps each glyph to an index into the + * `af_style_classes' array. + * + */ + typedef struct AF_FaceGlobalsRec_ + { + FT_Face face; + FT_UInt glyph_count; /* unsigned face->num_glyphs */ + FT_UShort* glyph_styles; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + hb_font_t* hb_font; + hb_buffer_t* hb_buf; /* for feature comparison */ +#endif + + /* per-face auto-hinter properties */ + FT_UInt increase_x_height; + + AF_StyleMetrics metrics[AF_STYLE_MAX]; + + /* Compute darkening amount once per size. Use this to check whether */ + /* darken_{x,y} needs to be recomputed. */ + FT_UShort stem_darkening_for_ppem; + /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_HORZ] */ + /* to compute the darkening amount. */ + FT_Pos standard_vertical_width; + /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_VERT] */ + /* to compute the darkening amount. */ + FT_Pos standard_horizontal_width; + /* The actual amount to darken a glyph along the X axis. */ + FT_Pos darken_x; + /* The actual amount to darken a glyph along the Y axis. */ + FT_Pos darken_y; + /* Amount to scale down by to keep emboldened points */ + /* on the Y-axis in pre-computed blue zones. */ + FT_Fixed scale_down_factor; + AF_Module module; /* to access global properties */ + + } AF_FaceGlobalsRec; + + + /* + * model the global hints data for a given face, decomposed into + * style-specific items + */ + + FT_LOCAL( FT_Error ) + af_face_globals_new( FT_Face face, + AF_FaceGlobals *aglobals, + AF_Module module ); + + FT_LOCAL( FT_Error ) + af_face_globals_get_metrics( AF_FaceGlobals globals, + FT_UInt gindex, + FT_UInt options, + AF_StyleMetrics *ametrics ); + + FT_LOCAL( void ) + af_face_globals_free( void* globals ); + + FT_LOCAL( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ); + + /* */ + + +FT_END_HEADER + +#endif /* AFGLOBAL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afhints.c b/Dependencies/freetype/freetype/src/autofit/afhints.c new file mode 100644 index 00000000..96ffe343 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afhints.c @@ -0,0 +1,1796 @@ +/**************************************************************************** + * + * afhints.c + * + * Auto-fitter hinting routines (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afhints.h" +#include "aferrors.h" +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afhints + + + FT_LOCAL_DEF( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ) + { + FT_UInt i, j; + FT_Pos swap; + + + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j] >= table[j - 1] ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + FT_LOCAL_DEF( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width table, + FT_Pos threshold ) + { + FT_UInt i, j; + FT_UInt cur_idx; + FT_Pos cur_val; + FT_Pos sum; + AF_WidthRec swap; + + + if ( *count == 1 ) + return; + + /* sort */ + for ( i = 1; i < *count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j].org >= table[j - 1].org ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + + cur_idx = 0; + cur_val = table[cur_idx].org; + + /* compute and use mean values for clusters not larger than */ + /* `threshold'; this is very primitive and might not yield */ + /* the best result, but normally, using reference character */ + /* `o', `*count' is 2, so the code below is fully sufficient */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org - cur_val > threshold || + i == *count - 1 ) + { + sum = 0; + + /* fix loop for end of array */ + if ( table[i].org - cur_val <= threshold && + i == *count - 1 ) + i++; + + for ( j = cur_idx; j < i; j++ ) + { + sum += table[j].org; + table[j].org = 0; + } + table[cur_idx].org = sum / (FT_Pos)j; + + if ( i < *count - 1 ) + { + cur_idx = i + 1; + cur_val = table[cur_idx].org; + } + } + } + + cur_idx = 1; + + /* compress array to remove zero values */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org ) + table[cur_idx++] = table[i]; + } + + *count = cur_idx; + } + + /* Get new segment for given axis. */ + + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ) + { + FT_Error error = FT_Err_Ok; + AF_Segment segment = NULL; + + + if ( axis->num_segments < AF_SEGMENTS_EMBEDDED ) + { + if ( !axis->segments ) + { + axis->segments = axis->embedded.segments; + axis->max_segments = AF_SEGMENTS_EMBEDDED; + } + } + else if ( axis->num_segments >= axis->max_segments ) + { + FT_UInt old_max = axis->max_segments; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *segment ); + + + if ( old_max >= big_max ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( axis->segments == axis->embedded.segments ) + { + if ( FT_NEW_ARRAY( axis->segments, new_max ) ) + goto Exit; + ft_memcpy( axis->segments, axis->embedded.segments, + sizeof ( axis->embedded.segments ) ); + } + else + { + if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) + goto Exit; + } + + axis->max_segments = new_max; + } + + segment = axis->segments + axis->num_segments++; + + Exit: + *asegment = segment; + return error; + } + + + /* Get new edge for given axis, direction, and position, */ + /* without initializing the edge itself. */ + + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + AF_Direction dir, + FT_Bool top_to_bottom_hinting, + FT_Memory memory, + AF_Edge *anedge ) + { + FT_Error error = FT_Err_Ok; + AF_Edge edge = NULL; + AF_Edge edges; + + + if ( axis->num_edges < AF_EDGES_EMBEDDED ) + { + if ( !axis->edges ) + { + axis->edges = axis->embedded.edges; + axis->max_edges = AF_EDGES_EMBEDDED; + } + } + else if ( axis->num_edges >= axis->max_edges ) + { + FT_UInt old_max = axis->max_edges; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *edge ); + + + if ( old_max >= big_max ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( axis->edges == axis->embedded.edges ) + { + if ( FT_NEW_ARRAY( axis->edges, new_max ) ) + goto Exit; + ft_memcpy( axis->edges, axis->embedded.edges, + sizeof ( axis->embedded.edges ) ); + } + else + { + if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) + goto Exit; + } + + axis->max_edges = new_max; + } + + edges = axis->edges; + edge = edges + axis->num_edges; + + while ( edge > edges ) + { + if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos ) + : ( edge[-1].fpos < fpos ) ) + break; + + /* we want the edge with same position and minor direction */ + /* to appear before those in the major one in the list */ + if ( edge[-1].fpos == fpos && dir == axis->major_dir ) + break; + + edge[0] = edge[-1]; + edge--; + } + + axis->num_edges++; + + Exit: + *anedge = edge; + return error; + } + + +#ifdef FT_DEBUG_AUTOFIT + +#include FT_CONFIG_STANDARD_LIBRARY_H + + /* The dump functions are used in the `ftgrid' demo program, too. */ +#define AF_DUMP( varformat ) \ + do \ + { \ + if ( to_stdout ) \ + printf varformat; \ + else \ + FT_TRACE7( varformat ); \ + } while ( 0 ) + + + static const char* + af_dir_str( AF_Direction dir ) + { + const char* result; + + + switch ( dir ) + { + case AF_DIR_UP: + result = "up"; + break; + case AF_DIR_DOWN: + result = "down"; + break; + case AF_DIR_LEFT: + result = "left"; + break; + case AF_DIR_RIGHT: + result = "right"; + break; + default: + result = "none"; + } + + return result; + } + + +#define AF_INDEX_NUM( ptr, base ) (int)( (ptr) ? ( (ptr) - (base) ) : -1 ) + + + static char* + af_print_idx( char* p, + size_t n, + int idx ) + { + if ( idx == -1 ) + { + p[0] = '-'; + p[1] = '-'; + p[2] = '\0'; + } + else + ft_snprintf( p, n, "%d", idx ); + + return p; + } + + + static int + af_get_segment_index( AF_GlyphHints hints, + int point_idx, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Point point = hints->points + point_idx; + AF_Segment segments = axis->segments; + AF_Segment limit = segments + axis->num_segments; + AF_Segment segment; + + + for ( segment = segments; segment < limit; segment++ ) + { + if ( segment->first <= segment->last ) + { + if ( point >= segment->first && point <= segment->last ) + break; + } + else + { + AF_Point p = segment->first; + + + for (;;) + { + if ( point == p ) + goto Exit; + + if ( p == segment->last ) + break; + + p = p->next; + } + } + } + + Exit: + if ( segment == limit ) + return -1; + + return (int)( segment - segments ); + } + + + static int + af_get_edge_index( AF_GlyphHints hints, + int segment_idx, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + AF_Segment segment = axis->segments + segment_idx; + + + return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges ); + } + + + static int + af_get_strong_edge_index( AF_GlyphHints hints, + AF_Edge* strong_edges, + int dimension ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + + + return AF_INDEX_NUM( strong_edges[dimension], edges ); + } + + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_points( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + AF_Point points = hints->points; + AF_Point limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* climit = contour + hints->num_contours; + AF_Point point; + + + AF_DUMP(( "Table of points:\n" )); + + if ( hints->num_points ) + { + AF_DUMP(( " index hedge hseg vedge vseg flags " + /* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */ + " xorg yorg xscale yscale xfit yfit " + /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */ + " hbef haft vbef vaft" )); + /* " XXXXX XXXXX XXXXX XXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( point = points; point < limit; point++ ) + { + int point_idx = AF_INDEX_NUM( point, points ); + int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 ); + int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 ); + + char buf1[16], buf2[16], buf3[16], buf4[16]; + char buf5[16], buf6[16], buf7[16], buf8[16]; + + + /* insert extra newline at the beginning of a contour */ + if ( contour < climit && *contour == point ) + { + AF_DUMP(( "\n" )); + contour++; + } + + AF_DUMP(( " %5d %5s %5s %5s %5s %s" + " %5d %5d %7.2f %7.2f %7.2f %7.2f" + " %5s %5s %5s %5s\n", + point_idx, + af_print_idx( buf1, 16, + af_get_edge_index( hints, segment_idx_1, 1 ) ), + af_print_idx( buf2, 16, segment_idx_1 ), + af_print_idx( buf3, 16, + af_get_edge_index( hints, segment_idx_0, 0 ) ), + af_print_idx( buf4, 16, segment_idx_0 ), + ( point->flags & AF_FLAG_NEAR ) + ? " near " + : ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + ? " weak " + : "strong", + + point->fx, + point->fy, + (double)point->ox / 64, + (double)point->oy / 64, + (double)point->x / 64, + (double)point->y / 64, + + af_print_idx( buf5, 16, + af_get_strong_edge_index( hints, + point->before, + 1 ) ), + af_print_idx( buf6, 16, + af_get_strong_edge_index( hints, + point->after, + 1 ) ), + af_print_idx( buf7, 16, + af_get_strong_edge_index( hints, + point->before, + 0 ) ), + af_print_idx( buf8, 16, + af_get_strong_edge_index( hints, + point->after, + 0 ) ) )); + } + AF_DUMP(( "\n" )); + } +#ifdef __cplusplus + } +#endif + + + static const char* + af_edge_flags_to_string( FT_UInt flags ) + { + static char temp[32]; + int pos = 0; + + + if ( flags & AF_EDGE_ROUND ) + { + ft_memcpy( temp + pos, "round", 5 ); + pos += 5; + } + if ( flags & AF_EDGE_SERIF ) + { + if ( pos > 0 ) + temp[pos++] = ' '; + ft_memcpy( temp + pos, "serif", 5 ); + pos += 5; + } + if ( pos == 0 ) + return "normal"; + + temp[pos] = '\0'; + + return temp; + } + + + /* Dump the array of linked segments. */ + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_segments( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + FT_Int dimension; + + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Point points = hints->points; + AF_Edge edges = axis->edges; + AF_Segment segments = axis->segments; + AF_Segment limit = segments + axis->num_segments; + AF_Segment seg; + + char buf1[16], buf2[16], buf3[16]; + + + AF_DUMP(( "Table of %s segments:\n", + dimension == AF_DIMENSION_HORZ ? "vertical" + : "horizontal" )); + if ( axis->num_segments ) + { + AF_DUMP(( " index pos delta dir from to " + /* " XXXXX XXXXX XXXXX XXXXX XXXX XXXX" */ + " link serif edge" + /* " XXXX XXXXX XXXX" */ + " height extra flags\n" )); + /* " XXXXXX XXXXX XXXXXXXXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( seg = segments; seg < limit; seg++ ) + AF_DUMP(( " %5d %5d %5d %5s %4d %4d" + " %4s %5s %4s" + " %6d %5d %11s\n", + AF_INDEX_NUM( seg, segments ), + seg->pos, + seg->delta, + af_dir_str( (AF_Direction)seg->dir ), + AF_INDEX_NUM( seg->first, points ), + AF_INDEX_NUM( seg->last, points ), + + af_print_idx( buf1, 16, + AF_INDEX_NUM( seg->link, segments ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( seg->serif, segments ) ), + af_print_idx( buf3, 16, + AF_INDEX_NUM( seg->edge, edges ) ), + + seg->height, + seg->height - ( seg->max_coord - seg->min_coord ), + af_edge_flags_to_string( seg->flags ) )); + AF_DUMP(( "\n" )); + } + } +#ifdef __cplusplus + } +#endif + + + /* Fetch number of segments. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_num_segments( AF_GlyphHints hints, + FT_Int dimension, + FT_UInt* num_segments ) + { + AF_Dimension dim; + AF_AxisHints axis; + + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + *num_segments = axis->num_segments; + + return FT_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + + /* Fetch offset of segments into user supplied offset array. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_segment_offset( AF_GlyphHints hints, + FT_Int dimension, + FT_UInt idx, + FT_Pos *offset, + FT_Bool *is_blue, + FT_Pos *blue_offset ) + { + AF_Dimension dim; + AF_AxisHints axis; + AF_Segment seg; + + + if ( !offset ) + return FT_THROW( Invalid_Argument ); + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + + if ( idx >= axis->num_segments ) + return FT_THROW( Invalid_Argument ); + + seg = &axis->segments[idx]; + *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx + : seg->first->fy; + if ( seg->edge ) + *is_blue = FT_BOOL( seg->edge->blue_edge ); + else + *is_blue = FALSE; + + if ( *is_blue ) + *blue_offset = seg->edge->blue_edge->org; + else + *blue_offset = 0; + + return FT_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + + /* Dump the array of linked edges. */ + +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_edges( AF_GlyphHints hints, + FT_Bool to_stdout ) + { + FT_Int dimension; + + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_AxisHints axis = &hints->axis[dimension]; + AF_Edge edges = axis->edges; + AF_Edge limit = edges + axis->num_edges; + AF_Edge edge; + + char buf1[16], buf2[16]; + + + /* + * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges + * since they have a constant X coordinate. + */ + if ( dimension == AF_DIMENSION_HORZ ) + AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", + "vertical", + 65536 * 64 / (double)hints->x_scale, + 10 * (double)hints->x_scale / 65536 / 64 )); + else + AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", + "horizontal", + 65536 * 64 / (double)hints->y_scale, + 10 * (double)hints->y_scale / 65536 / 64 )); + + if ( axis->num_edges ) + { + AF_DUMP(( " index pos dir link serif" + /* " XXXXX XXXX.XX XXXXX XXXX XXXXX" */ + " blue opos pos flags\n" )); + /* " X XXXX.XX XXXX.XX XXXXXXXXXXX" */ + } + else + AF_DUMP(( " (none)\n" )); + + for ( edge = edges; edge < limit; edge++ ) + AF_DUMP(( " %5d %7.2f %5s %4s %5s" + " %c %7.2f %7.2f %11s\n", + AF_INDEX_NUM( edge, edges ), + (double)(int)edge->opos / 64, + af_dir_str( (AF_Direction)edge->dir ), + af_print_idx( buf1, 16, + AF_INDEX_NUM( edge->link, edges ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( edge->serif, edges ) ), + + edge->blue_edge ? 'y' : 'n', + (double)edge->opos / 64, + (double)edge->pos / 64, + af_edge_flags_to_string( edge->flags ) )); + AF_DUMP(( "\n" )); + } + } +#ifdef __cplusplus + } +#endif + +#undef AF_DUMP + +#endif /* !FT_DEBUG_AUTOFIT */ + + + /* Compute the direction value of a given vector. */ + + FT_LOCAL_DEF( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ll, ss; /* long and short arm lengths */ + AF_Direction dir; /* candidate direction */ + + + if ( dy >= dx ) + { + if ( dy >= -dx ) + { + dir = AF_DIR_UP; + ll = dy; + ss = dx; + } + else + { + dir = AF_DIR_LEFT; + ll = -dx; + ss = dy; + } + } + else /* dy < dx */ + { + if ( dy >= -dx ) + { + dir = AF_DIR_RIGHT; + ll = dx; + ss = dy; + } + else + { + dir = AF_DIR_DOWN; + ll = -dy; + ss = dx; + } + } + + /* return no direction if arm lengths do not differ enough */ + /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */ + /* the long arm is never negative */ + if ( ll <= 14 * FT_ABS( ss ) ) + dir = AF_DIR_NONE; + + return dir; + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ) + { + /* no need to initialize the embedded items */ + FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) ); + hints->memory = memory; + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_done( AF_GlyphHints hints ) + { + FT_Memory memory; + int dim; + + + if ( !( hints && hints->memory ) ) + return; + + memory = hints->memory; + + /* + * note that we don't need to free the segment and edge + * buffers since they are really within the hints->points array + */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_AxisHints axis = &hints->axis[dim]; + + + axis->num_segments = 0; + axis->max_segments = 0; + if ( axis->segments != axis->embedded.segments ) + FT_FREE( axis->segments ); + + axis->num_edges = 0; + axis->max_edges = 0; + if ( axis->edges != axis->embedded.edges ) + FT_FREE( axis->edges ); + } + + if ( hints->contours != hints->embedded.contours ) + FT_FREE( hints->contours ); + hints->max_contours = 0; + hints->num_contours = 0; + + if ( hints->points != hints->embedded.points ) + FT_FREE( hints->points ); + hints->max_points = 0; + hints->num_points = 0; + + hints->memory = NULL; + } + + + /* Reset metrics. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_rescale( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + hints->metrics = metrics; + hints->scaler_flags = metrics->scaler.flags; + } + + + /* Recompute all AF_Point in AF_GlyphHints from the definitions */ + /* in a source outline. */ + + FT_LOCAL_DEF( FT_Error ) + af_glyph_hints_reload( AF_GlyphHints hints, + FT_Outline* outline ) + { + FT_Error error = FT_Err_Ok; + AF_Point points; + FT_Int old_max, new_max; + FT_Fixed x_scale = hints->x_scale; + FT_Fixed y_scale = hints->y_scale; + FT_Pos x_delta = hints->x_delta; + FT_Pos y_delta = hints->y_delta; + FT_Memory memory = hints->memory; + + + hints->num_points = 0; + hints->num_contours = 0; + + hints->axis[0].num_segments = 0; + hints->axis[0].num_edges = 0; + hints->axis[1].num_segments = 0; + hints->axis[1].num_edges = 0; + + /* first of all, reallocate the contours array if necessary */ + new_max = outline->n_contours; + old_max = hints->max_contours; + + if ( new_max <= AF_CONTOURS_EMBEDDED ) + { + if ( !hints->contours ) + { + hints->contours = hints->embedded.contours; + hints->max_contours = AF_CONTOURS_EMBEDDED; + } + } + else if ( new_max > old_max ) + { + if ( hints->contours == hints->embedded.contours ) + hints->contours = NULL; + + new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ + + if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) + goto Exit; + + hints->max_contours = new_max; + } + + /* + * then reallocate the points arrays if necessary -- + * note that we reserve two additional point positions, used to + * hint metrics appropriately + */ + new_max = outline->n_points + 2; + old_max = hints->max_points; + + if ( new_max <= AF_POINTS_EMBEDDED ) + { + if ( !hints->points ) + { + hints->points = hints->embedded.points; + hints->max_points = AF_POINTS_EMBEDDED; + } + } + else if ( new_max > old_max ) + { + if ( hints->points == hints->embedded.points ) + hints->points = NULL; + + new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ + + if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) + goto Exit; + + hints->max_points = new_max; + } + + hints->num_points = outline->n_points; + hints->num_contours = outline->n_contours; + + /* We can't rely on the value of `FT_Outline.flags' to know the fill */ + /* direction used for a glyph, given that some fonts are broken (e.g., */ + /* the Arphic ones). We thus recompute it each time we need to. */ + /* */ + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; + + if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) + { + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; + } + + hints->x_scale = x_scale; + hints->y_scale = y_scale; + hints->x_delta = x_delta; + hints->y_delta = y_delta; + + points = hints->points; + if ( hints->num_points == 0 ) + goto Exit; + + { + AF_Point point; + AF_Point point_limit = points + hints->num_points; + + /* value 20 in `near_limit' is heuristic */ + FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM; + FT_Int near_limit = 20 * units_per_em / 2048; + + + /* compute coordinates & Bezier flags, next and prev */ + { + FT_Vector* vec = outline->points; + FT_Byte* tag = outline->tags; + FT_UShort endpoint = outline->contours[0]; + AF_Point end = points + endpoint; + AF_Point prev = end; + FT_Int contour_index = 0; + + + for ( point = points; point < point_limit; point++, vec++, tag++ ) + { + FT_Pos out_x, out_y; + + + point->in_dir = (FT_Char)AF_DIR_NONE; + point->out_dir = (FT_Char)AF_DIR_NONE; + + point->fx = (FT_Short)vec->x; + point->fy = (FT_Short)vec->y; + point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; + point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; + + end->fx = (FT_Short)outline->points[endpoint].x; + end->fy = (FT_Short)outline->points[endpoint].y; + + switch ( FT_CURVE_TAG( *tag ) ) + { + case FT_CURVE_TAG_CONIC: + point->flags = AF_FLAG_CONIC; + break; + case FT_CURVE_TAG_CUBIC: + point->flags = AF_FLAG_CUBIC; + break; + default: + point->flags = AF_FLAG_NONE; + } + + out_x = point->fx - prev->fx; + out_y = point->fy - prev->fy; + + if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) + prev->flags |= AF_FLAG_NEAR; + + point->prev = prev; + prev->next = point; + prev = point; + + if ( point == end ) + { + if ( ++contour_index < outline->n_contours ) + { + endpoint = outline->contours[contour_index]; + end = points + endpoint; + prev = end; + } + } + +#ifdef FT_DEBUG_AUTOFIT + point->before[0] = NULL; + point->before[1] = NULL; + point->after[0] = NULL; + point->after[1] = NULL; +#endif + + } + } + + /* set up the contours array */ + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UShort* end = outline->contours; + FT_Int idx = 0; + + + for ( ; contour < contour_limit; contour++, end++ ) + { + contour[0] = points + idx; + idx = *end + 1; + } + } + + { + /* + * Compute directions of `in' and `out' vectors. + * + * Note that distances between points that are very near to each + * other are accumulated. In other words, the auto-hinter either + * prepends the small vectors between near points to the first + * non-near vector, or the sum of small vector lengths exceeds a + * threshold, thus `grouping' the small vectors. All intermediate + * points are tagged as weak; the directions are adjusted also to + * be equal to the accumulated one. + */ + + FT_Int near_limit2 = 2 * near_limit - 1; + + AF_Point* contour; + AF_Point* contour_limit = hints->contours + hints->num_contours; + + + for ( contour = hints->contours; contour < contour_limit; contour++ ) + { + AF_Point first = *contour; + AF_Point next, prev, curr; + + FT_Pos out_x, out_y; + + + /* since the first point of a contour could be part of a */ + /* series of near points, go backwards to find the first */ + /* non-near point and adjust `first' */ + + point = first; + prev = first->prev; + + while ( prev != first ) + { + out_x = point->fx - prev->fx; + out_y = point->fy - prev->fy; + + /* + * We use Taxicab metrics to measure the vector length. + * + * Note that the accumulated distances so far could have the + * opposite direction of the distance measured here. For this + * reason we use `near_limit2' for the comparison to get a + * non-near point even in the worst case. + */ + if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 ) + break; + + point = prev; + prev = prev->prev; + } + + /* adjust first point */ + first = point; + + /* now loop over all points of the contour to get */ + /* `in' and `out' vector directions */ + + curr = first; + + /* + * We abuse the `u' and `v' fields to store index deltas to the + * next and previous non-near point, respectively. + * + * To avoid problems with not having non-near points, we point to + * `first' by default as the next non-near point. + * + */ + curr->u = (FT_Pos)( first - curr ); + first->v = -curr->u; + + out_x = 0; + out_y = 0; + + next = first; + do + { + AF_Direction out_dir; + + + point = next; + next = point->next; + + out_x += next->fx - point->fx; + out_y += next->fy - point->fy; + + if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit ) + { + next->flags |= AF_FLAG_WEAK_INTERPOLATION; + continue; + } + + curr->u = (FT_Pos)( next - curr ); + next->v = -curr->u; + + out_dir = af_direction_compute( out_x, out_y ); + + /* adjust directions for all points inbetween; */ + /* the loop also updates position of `curr' */ + curr->out_dir = (FT_Char)out_dir; + for ( curr = curr->next; curr != next; curr = curr->next ) + { + curr->in_dir = (FT_Char)out_dir; + curr->out_dir = (FT_Char)out_dir; + } + next->in_dir = (FT_Char)out_dir; + + curr->u = (FT_Pos)( first - curr ); + first->v = -curr->u; + + out_x = 0; + out_y = 0; + + } while ( next != first ); + } + + /* + * The next step is to `simplify' an outline's topology so that we + * can identify local extrema more reliably: A series of + * non-horizontal or non-vertical vectors pointing into the same + * quadrant are handled as a single, long vector. From a + * topological point of the view, the intermediate points are of no + * interest and thus tagged as weak. + */ + + for ( point = points; point < point_limit; point++ ) + { + if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + continue; + + if ( point->in_dir == AF_DIR_NONE && + point->out_dir == AF_DIR_NONE ) + { + /* check whether both vectors point into the same quadrant */ + + FT_Pos in_x, in_y; + FT_Pos out_x, out_y; + + AF_Point next_u = point + point->u; + AF_Point prev_v = point + point->v; + + + in_x = point->fx - prev_v->fx; + in_y = point->fy - prev_v->fy; + + out_x = next_u->fx - point->fx; + out_y = next_u->fy - point->fy; + + if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 ) + { + /* yes, so tag current point as weak */ + /* and update index deltas */ + + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + + prev_v->u = (FT_Pos)( next_u - prev_v ); + next_u->v = -prev_v->u; + } + } + } + + /* + * Finally, check for remaining weak points. Everything else not + * collected in edges so far is then implicitly classified as strong + * points. + */ + + for ( point = points; point < point_limit; point++ ) + { + if ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) + continue; + + if ( point->flags & AF_FLAG_CONTROL ) + { + /* control points are always weak */ + Is_Weak_Point: + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + } + else if ( point->out_dir == point->in_dir ) + { + if ( point->out_dir != AF_DIR_NONE ) + { + /* current point lies on a horizontal or */ + /* vertical segment (but doesn't start or end it) */ + goto Is_Weak_Point; + } + + { + AF_Point next_u = point + point->u; + AF_Point prev_v = point + point->v; + + + if ( ft_corner_is_flat( point->fx - prev_v->fx, + point->fy - prev_v->fy, + next_u->fx - point->fx, + next_u->fy - point->fy ) ) + { + /* either the `in' or the `out' vector is much more */ + /* dominant than the other one, so tag current point */ + /* as weak and update index deltas */ + + prev_v->u = (FT_Pos)( next_u - prev_v ); + next_u->v = -prev_v->u; + + goto Is_Weak_Point; + } + } + } + else if ( point->in_dir == -point->out_dir ) + { + /* current point forms a spike */ + goto Is_Weak_Point; + } + } + } + } + + Exit: + return error; + } + + + /* Store the hinted outline in an FT_Outline structure. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_save( AF_GlyphHints hints, + FT_Outline* outline ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + FT_Vector* vec = outline->points; + FT_Byte* tag = outline->tags; + + + for ( ; point < limit; point++, vec++, tag++ ) + { + vec->x = point->x; + vec->y = point->y; + + if ( point->flags & AF_FLAG_CONIC ) + tag[0] = FT_CURVE_TAG_CONIC; + else if ( point->flags & AF_FLAG_CUBIC ) + tag[0] = FT_CURVE_TAG_CUBIC; + else + tag[0] = FT_CURVE_TAG_ON; + } + } + + + /**************************************************************** + * + * EDGE POINT GRID-FITTING + * + ****************************************************************/ + + + /* Align all points of an edge to the same coordinate value, */ + /* either horizontally or vertically. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + + + if ( dim == AF_DIMENSION_HORZ ) + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + + + if ( !edge ) + continue; + + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + + if ( point == last ) + break; + + point = point->next; + } + } + } + else + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + + + if ( !edge ) + continue; + + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + + if ( point == last ) + break; + + point = point->next; + } + } + } + } + + + /**************************************************************** + * + * STRONG POINT INTERPOLATION + * + ****************************************************************/ + + + /* Hint the strong points -- this is equivalent to the TrueType `IP' */ + /* hinting instruction. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_UInt touch_flag; + + + if ( dim == AF_DIMENSION_HORZ ) + touch_flag = AF_FLAG_TOUCH_X; + else + touch_flag = AF_FLAG_TOUCH_Y; + + if ( edges < edge_limit ) + { + AF_Point point; + AF_Edge edge; + + + for ( point = points; point < point_limit; point++ ) + { + FT_Pos u, ou, fu; /* point position */ + FT_Pos delta; + + + if ( point->flags & touch_flag ) + continue; + + /* if this point is candidate to weak interpolation, we */ + /* interpolate it after all strong points have been processed */ + + if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ) + continue; + + if ( dim == AF_DIMENSION_VERT ) + { + u = point->fy; + ou = point->oy; + } + else + { + u = point->fx; + ou = point->ox; + } + + fu = u; + + /* is the point before the first edge? */ + edge = edges; + delta = edge->fpos - u; + if ( delta >= 0 ) + { + u = edge->pos - ( edge->opos - ou ); + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = edge; + point->after[dim] = NULL; +#endif + + goto Store_Point; + } + + /* is the point after the last edge? */ + edge = edge_limit - 1; + delta = u - edge->fpos; + if ( delta >= 0 ) + { + u = edge->pos + ( ou - edge->opos ); + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = NULL; + point->after[dim] = edge; +#endif + + goto Store_Point; + } + + { + FT_PtrDist min, max, mid; + FT_Pos fpos; + + + /* find enclosing edges */ + min = 0; + max = edge_limit - edges; + +#if 1 + /* for a small number of edges, a linear search is better */ + if ( max <= 8 ) + { + FT_PtrDist nn; + + + for ( nn = 0; nn < max; nn++ ) + if ( edges[nn].fpos >= u ) + break; + + if ( edges[nn].fpos == u ) + { + u = edges[nn].pos; + goto Store_Point; + } + min = nn; + } + else +#endif + while ( min < max ) + { + mid = ( max + min ) >> 1; + edge = edges + mid; + fpos = edge->fpos; + + if ( u < fpos ) + max = mid; + else if ( u > fpos ) + min = mid + 1; + else + { + /* we are on the edge */ + u = edge->pos; + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = NULL; + point->after[dim] = NULL; +#endif + + goto Store_Point; + } + } + + /* point is not on an edge */ + { + AF_Edge before = edges + min - 1; + AF_Edge after = edges + min + 0; + + +#ifdef FT_DEBUG_AUTOFIT + point->before[dim] = before; + point->after[dim] = after; +#endif + + /* assert( before && after && before != after ) */ + if ( before->scale == 0 ) + before->scale = FT_DivFix( after->pos - before->pos, + after->fpos - before->fpos ); + + u = before->pos + FT_MulFix( fu - before->fpos, + before->scale ); + } + } + + Store_Point: + /* save the point position */ + if ( dim == AF_DIMENSION_HORZ ) + point->x = u; + else + point->y = u; + + point->flags |= touch_flag; + } + } + } + + + /**************************************************************** + * + * WEAK POINT INTERPOLATION + * + ****************************************************************/ + + + /* Shift the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using the same difference as */ + /* given by `ref'. */ + + static void + af_iup_shift( AF_Point p1, + AF_Point p2, + AF_Point ref ) + { + AF_Point p; + FT_Pos delta = ref->u - ref->v; + + + if ( delta == 0 ) + return; + + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } + + + /* Interpolate the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */ + /* reference points. The `u' and `v' members are the current and */ + /* original coordinate values, respectively. */ + /* */ + /* Details can be found in the TrueType bytecode specification. */ + + static void + af_iup_interp( AF_Point p1, + AF_Point p2, + AF_Point ref1, + AF_Point ref2 ) + { + AF_Point p; + FT_Pos u, v1, v2, u1, u2, d1, d2; + + + if ( p1 > p2 ) + return; + + if ( ref1->v > ref2->v ) + { + p = ref1; + ref1 = ref2; + ref2 = p; + } + + v1 = ref1->v; + v2 = ref2->v; + u1 = ref1->u; + u2 = ref2->u; + d1 = u1 - v1; + d2 = u2 - v2; + + if ( u1 == u2 || v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = u1; + + p->u = u; + } + } + else + { + FT_Fixed scale = FT_DivFix( u2 - u1, v2 - v1 ); + + + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = u1 + FT_MulFix( u - v1, scale ); + + p->u = u; + } + } + } + + + /* Hint the weak points -- this is equivalent to the TrueType `IUP' */ + /* hinting instruction. */ + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UInt touch_flag; + AF_Point point; + AF_Point end_point; + AF_Point first_point; + + + /* PASS 1: Move segment points to edge positions */ + + if ( dim == AF_DIMENSION_HORZ ) + { + touch_flag = AF_FLAG_TOUCH_X; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->x; + point->v = point->ox; + } + } + else + { + touch_flag = AF_FLAG_TOUCH_Y; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->y; + point->v = point->oy; + } + } + + for ( ; contour < contour_limit; contour++ ) + { + AF_Point first_touched, last_touched; + + + point = *contour; + end_point = point->prev; + first_point = point; + + /* find first touched point */ + for (;;) + { + if ( point > end_point ) /* no touched point in contour */ + goto NextContour; + + if ( point->flags & touch_flag ) + break; + + point++; + } + + first_touched = point; + + for (;;) + { + FT_ASSERT( point <= end_point && + ( point->flags & touch_flag ) != 0 ); + + /* skip any touched neighbours */ + while ( point < end_point && + ( point[1].flags & touch_flag ) != 0 ) + point++; + + last_touched = point; + + /* find the next touched point, if any */ + point++; + for (;;) + { + if ( point > end_point ) + goto EndContour; + + if ( ( point->flags & touch_flag ) != 0 ) + break; + + point++; + } + + /* interpolate between last_touched and point */ + af_iup_interp( last_touched + 1, point - 1, + last_touched, point ); + } + + EndContour: + /* special case: only one point was touched */ + if ( last_touched == first_touched ) + af_iup_shift( first_point, end_point, first_touched ); + + else /* interpolate the last part */ + { + if ( last_touched < end_point ) + af_iup_interp( last_touched + 1, end_point, + last_touched, first_touched ); + + if ( first_touched > points ) + af_iup_interp( first_point, first_touched - 1, + last_touched, first_touched ); + } + + NextContour: + ; + } + + /* now save the interpolated values back to x/y */ + if ( dim == AF_DIMENSION_HORZ ) + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + } + else + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + } + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afhints.h b/Dependencies/freetype/freetype/src/autofit/afhints.h new file mode 100644 index 00000000..76fe8300 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afhints.h @@ -0,0 +1,467 @@ +/**************************************************************************** + * + * afhints.h + * + * Auto-fitter hinting routines (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFHINTS_H_ +#define AFHINTS_H_ + +#include "aftypes.h" + +FT_BEGIN_HEADER + + /* + * The definition of outline glyph hints. These are shared by all + * writing system analysis routines (until now). + */ + + typedef enum AF_Dimension_ + { + AF_DIMENSION_HORZ = 0, /* x coordinates, */ + /* i.e., vertical segments & edges */ + AF_DIMENSION_VERT = 1, /* y coordinates, */ + /* i.e., horizontal segments & edges */ + + AF_DIMENSION_MAX /* do not remove */ + + } AF_Dimension; + + + /* hint directions -- the values are computed so that two vectors are */ + /* in opposite directions iff `dir1 + dir2 == 0' */ + typedef enum AF_Direction_ + { + AF_DIR_NONE = 4, + AF_DIR_RIGHT = 1, + AF_DIR_LEFT = -1, + AF_DIR_UP = 2, + AF_DIR_DOWN = -2 + + } AF_Direction; + + + /* + * The following explanations are mostly taken from the article + * + * Real-Time Grid Fitting of Typographic Outlines + * + * by David Turner and Werner Lemberg + * + * https://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * + * with appropriate updates. + * + * + * Segments + * + * `af_{cjk,latin,...}_hints_compute_segments' are the functions to + * find segments in an outline. + * + * A segment is a series of at least two consecutive points that are + * approximately aligned along a coordinate axis. The analysis to do + * so is specific to a writing system. + * + * + * Edges + * + * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find + * edges. + * + * As soon as segments are defined, the auto-hinter groups them into + * edges. An edge corresponds to a single position on the main + * dimension that collects one or more segments (allowing for a small + * threshold). + * + * As an example, the `latin' writing system first tries to grid-fit + * edges, then to align segments on the edges unless it detects that + * they form a serif. + * + * + * A H + * | | + * | | + * | | + * | | + * C | | F + * +------<-----+ +-----<------+ + * | B G | + * | | + * | | + * +--------------->------------------+ + * D E + * + * + * Stems + * + * Stems are detected by `af_{cjk,latin,...}_hint_edges'. + * + * Segments need to be `linked' to other ones in order to detect stems. + * A stem is made of two segments that face each other in opposite + * directions and that are sufficiently close to each other. Using + * vocabulary from the TrueType specification, stem segments form a + * `black distance'. + * + * In the above ASCII drawing, the horizontal segments are BC, DE, and + * FG; the vertical segments are AB, CD, EF, and GH. + * + * Each segment has at most one `best' candidate to form a black + * distance, or no candidate at all. Notice that two distinct segments + * can have the same candidate, which frequently means a serif. + * + * A stem is recognized by the following condition: + * + * best segment_1 = segment_2 && best segment_2 = segment_1 + * + * The best candidate is stored in field `link' in structure + * `AF_Segment'. + * + * In the above ASCII drawing, the best candidate for both AB and CD is + * GH, while the best candidate for GH is AB. Similarly, the best + * candidate for EF and GH is AB, while the best candidate for AB is + * GH. + * + * The detection and handling of stems is dependent on the writing + * system. + * + * + * Serifs + * + * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. + * + * In comparison to a stem, a serif (as handled by the auto-hinter + * module that takes care of the `latin' writing system) has + * + * best segment_1 = segment_2 && best segment_2 != segment_1 + * + * where segment_1 corresponds to the serif segment (CD and EF in the + * above ASCII drawing). + * + * The best candidate is stored in field `serif' in structure + * `AF_Segment' (and `link' is set to NULL). + * + * + * Touched points + * + * A point is called `touched' if it has been processed somehow by the + * auto-hinter. It basically means that it shouldn't be moved again + * (or moved only under certain constraints to preserve the already + * applied processing). + * + * + * Flat and round segments + * + * Segments are `round' or `flat', depending on the series of points + * that define them. A segment is round if the next and previous point + * of an extremum (which can be either a single point or sequence of + * points) are both conic or cubic control points. Otherwise, a + * segment with an extremum is flat. + * + * + * Strong Points + * + * Experience has shown that points not part of an edge need to be + * interpolated linearly between their two closest edges, even if these + * are not part of the contour of those particular points. Typical + * candidates for this are + * + * - angle points (i.e., points where the `in' and `out' direction + * differ greatly) + * + * - inflection points (i.e., where the `in' and `out' angles are the + * same, but the curvature changes sign) [currently, such points + * aren't handled specially in the auto-hinter] + * + * `af_glyph_hints_align_strong_points' is the function that takes + * care of such situations; it is equivalent to the TrueType `IP' + * hinting instruction. + * + * + * Weak Points + * + * Other points in the outline must be interpolated using the + * coordinates of their previous and next unfitted contour neighbours. + * These are called `weak points' and are touched by the function + * `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP' + * hinting instruction. Typical candidates are control points and + * points on the contour without a major direction. + * + * The major effect is to reduce possible distortion caused by + * alignment of edges and strong points, thus weak points are processed + * after strong points. + */ + + + /* point hint flags */ +#define AF_FLAG_NONE 0 + + /* point type flags */ +#define AF_FLAG_CONIC ( 1U << 0 ) +#define AF_FLAG_CUBIC ( 1U << 1 ) +#define AF_FLAG_CONTROL ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) + + /* point touch flags */ +#define AF_FLAG_TOUCH_X ( 1U << 2 ) +#define AF_FLAG_TOUCH_Y ( 1U << 3 ) + + /* candidates for weak interpolation have this flag set */ +#define AF_FLAG_WEAK_INTERPOLATION ( 1U << 4 ) + + /* the distance to the next point is very small */ +#define AF_FLAG_NEAR ( 1U << 5 ) + + + /* edge hint flags */ +#define AF_EDGE_NORMAL 0 +#define AF_EDGE_ROUND ( 1U << 0 ) +#define AF_EDGE_SERIF ( 1U << 1 ) +#define AF_EDGE_DONE ( 1U << 2 ) +#define AF_EDGE_NEUTRAL ( 1U << 3 ) /* edge aligns to a neutral blue zone */ + + + typedef struct AF_PointRec_* AF_Point; + typedef struct AF_SegmentRec_* AF_Segment; + typedef struct AF_EdgeRec_* AF_Edge; + + + typedef struct AF_PointRec_ + { + FT_UShort flags; /* point flags used by hinter */ + FT_Char in_dir; /* direction of inwards vector */ + FT_Char out_dir; /* direction of outwards vector */ + + FT_Pos ox, oy; /* original, scaled position */ + FT_Short fx, fy; /* original, unscaled position (in font units) */ + FT_Pos x, y; /* current position */ + FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ + + AF_Point next; /* next point in contour */ + AF_Point prev; /* previous point in contour */ + +#ifdef FT_DEBUG_AUTOFIT + /* track `before' and `after' edges for strong points */ + AF_Edge before[2]; + AF_Edge after[2]; +#endif + + } AF_PointRec; + + + typedef struct AF_SegmentRec_ + { + FT_Byte flags; /* edge/segment flags for this segment */ + FT_Char dir; /* segment direction */ + FT_Short pos; /* position of segment */ + FT_Short delta; /* deviation from segment position */ + FT_Short min_coord; /* minimum coordinate of segment */ + FT_Short max_coord; /* maximum coordinate of segment */ + FT_Short height; /* the hinted segment height */ + + AF_Edge edge; /* the segment's parent edge */ + AF_Segment edge_next; /* link to next segment in parent edge */ + + AF_Segment link; /* (stem) link segment */ + AF_Segment serif; /* primary segment for serifs */ + FT_Pos score; /* used during stem matching */ + FT_Pos len; /* used during stem matching */ + + AF_Point first; /* first point in edge segment */ + AF_Point last; /* last point in edge segment */ + + } AF_SegmentRec; + + + typedef struct AF_EdgeRec_ + { + FT_Short fpos; /* original, unscaled position (in font units) */ + FT_Pos opos; /* original, scaled position */ + FT_Pos pos; /* current position */ + + FT_Byte flags; /* edge flags */ + FT_Char dir; /* edge direction */ + FT_Fixed scale; /* used to speed up interpolation between edges */ + + AF_Width blue_edge; /* non-NULL if this is a blue edge */ + AF_Edge link; /* link edge */ + AF_Edge serif; /* primary edge for serifs */ + FT_Int score; /* used during stem matching */ + + AF_Segment first; /* first segment in edge */ + AF_Segment last; /* last segment in edge */ + + } AF_EdgeRec; + +#define AF_SEGMENTS_EMBEDDED 18 /* number of embedded segments */ +#define AF_EDGES_EMBEDDED 12 /* number of embedded edges */ + + typedef struct AF_AxisHintsRec_ + { + FT_UInt num_segments; /* number of used segments */ + FT_UInt max_segments; /* number of allocated segments */ + AF_Segment segments; /* segments array */ + + FT_UInt num_edges; /* number of used edges */ + FT_UInt max_edges; /* number of allocated edges */ + AF_Edge edges; /* edges array */ + + AF_Direction major_dir; /* either vertical or horizontal */ + + /* two arrays to avoid allocation penalty */ + struct + { + AF_SegmentRec segments[AF_SEGMENTS_EMBEDDED]; + AF_EdgeRec edges[AF_EDGES_EMBEDDED]; + } embedded; + + + } AF_AxisHintsRec, *AF_AxisHints; + + +#define AF_POINTS_EMBEDDED 96 /* number of embedded points */ +#define AF_CONTOURS_EMBEDDED 8 /* number of embedded contours */ + + typedef struct AF_GlyphHintsRec_ + { + FT_Memory memory; + + FT_Fixed x_scale; + FT_Pos x_delta; + + FT_Fixed y_scale; + FT_Pos y_delta; + + FT_Int max_points; /* number of allocated points */ + FT_Int num_points; /* number of used points */ + AF_Point points; /* points array */ + + FT_Int max_contours; /* number of allocated contours */ + FT_Int num_contours; /* number of used contours */ + AF_Point* contours; /* contours array */ + + AF_AxisHintsRec axis[AF_DIMENSION_MAX]; + + FT_UInt32 scaler_flags; /* copy of scaler flags */ + FT_UInt32 other_flags; /* free for style-specific */ + /* implementations */ + AF_StyleMetrics metrics; + + /* Two arrays to avoid allocation penalty. */ + /* The `embedded' structure must be the last element! */ + struct + { + AF_Point contours[AF_CONTOURS_EMBEDDED]; + AF_PointRec points[AF_POINTS_EMBEDDED]; + } embedded; + + } AF_GlyphHintsRec; + + +#define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) ) +#define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) ) + + +#ifdef FT_DEBUG_AUTOFIT + +#define AF_HINTS_DO_HORIZONTAL( h ) \ + ( !af_debug_disable_horz_hints_ && \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) ) + +#define AF_HINTS_DO_VERTICAL( h ) \ + ( !af_debug_disable_vert_hints_ && \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) ) + +#define AF_HINTS_DO_BLUES( h ) ( !af_debug_disable_blue_hints_ ) + +#else /* !FT_DEBUG_AUTOFIT */ + +#define AF_HINTS_DO_HORIZONTAL( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) + +#define AF_HINTS_DO_VERTICAL( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) + +#define AF_HINTS_DO_BLUES( h ) 1 + +#endif /* !FT_DEBUG_AUTOFIT */ + + +#define AF_HINTS_DO_ADVANCE( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) + + + FT_LOCAL( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ); + + + FT_LOCAL( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ); + + FT_LOCAL( FT_Error) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + AF_Direction dir, + FT_Bool top_to_bottom_hinting, + FT_Memory memory, + AF_Edge *edge ); + + FT_LOCAL( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ); + + FT_LOCAL( void ) + af_glyph_hints_rescale( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + FT_LOCAL( FT_Error ) + af_glyph_hints_reload( AF_GlyphHints hints, + FT_Outline* outline ); + + FT_LOCAL( void ) + af_glyph_hints_save( AF_GlyphHints hints, + FT_Outline* outline ); + + FT_LOCAL( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_glyph_hints_done( AF_GlyphHints hints ); + +/* */ + +#define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord ) + +#define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \ + ? (seg1)->pos - (seg2)->pos \ + : (seg2)->pos - (seg1)->pos ) + + +FT_END_HEADER + +#endif /* AFHINTS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afindic.c b/Dependencies/freetype/freetype/src/autofit/afindic.c new file mode 100644 index 00000000..c6d23efd --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afindic.c @@ -0,0 +1,157 @@ +/**************************************************************************** + * + * afindic.c + * + * Auto-fitter hinting routines for Indic writing system (body). + * + * Copyright (C) 2007-2024 by + * Rahul Bhalerao , . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "aftypes.h" +#include "aflatin.h" +#include "afcjk.h" + + +#ifdef AF_CONFIG_OPTION_INDIC + +#include "afindic.h" +#include "aferrors.h" + + + static FT_Error + af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + /* skip blue zone init in CJK routines */ + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + face->charmap = NULL; + else + { + af_cjk_metrics_init_widths( metrics, face ); +#if 0 + /* either need indic specific blue_chars[] or just skip blue zones */ + af_cjk_metrics_init_blues( metrics, face, af_cjk_blue_chars ); +#endif + af_cjk_metrics_check_digits( metrics, face ); + } + + face->charmap = oldmap; + return FT_Err_Ok; + } + + + static void + af_indic_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ) + { + /* use CJK routines */ + af_cjk_metrics_scale( metrics, scaler ); + } + + + static FT_Error + af_indic_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ) + { + /* use CJK routines */ + return af_cjk_hints_init( hints, metrics ); + } + + + static FT_Error + af_indic_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ) + { + /* use CJK routines */ + return af_cjk_hints_apply( glyph_index, hints, outline, metrics ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + static void + af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** I N D I C S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, + + AF_WRITING_SYSTEM_INDIC, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_indic_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_indic_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_indic_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_indic_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_indic_hints_apply /* style_hints_apply */ + ) + + +#else /* !AF_CONFIG_OPTION_INDIC */ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_indic_writing_system_class, + + AF_WRITING_SYSTEM_INDIC, + + sizeof ( AF_CJKMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) NULL, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) NULL /* style_hints_apply */ + ) + + +#endif /* !AF_CONFIG_OPTION_INDIC */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afindic.h b/Dependencies/freetype/freetype/src/autofit/afindic.h new file mode 100644 index 00000000..a7f73f25 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afindic.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * afindic.h + * + * Auto-fitter hinting routines for Indic writing system + * (specification). + * + * Copyright (C) 2007-2024 by + * Rahul Bhalerao , . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFINDIC_H_ +#define AFINDIC_H_ + +#include "afhints.h" + + +FT_BEGIN_HEADER + + + /* the `indic' writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class ) + + +/* */ + +FT_END_HEADER + +#endif /* AFINDIC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/aflatin.c b/Dependencies/freetype/freetype/src/autofit/aflatin.c new file mode 100644 index 00000000..89287f7e --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/aflatin.c @@ -0,0 +1,3643 @@ +/**************************************************************************** + * + * aflatin.c + * + * Auto-fitter hinting routines for latin writing system (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "afglobal.h" +#include "aflatin.h" +#include "aferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT aflatin + + + /* needed for computation of round vs. flat segments */ +#define FLAT_THRESHOLD( x ) ( x / 14 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Find segments and links, compute all stem widths, and initialize */ + /* standard width and height for the glyph with given charcode. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ) + { + /* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + + + FT_TRACE5(( "\n" )); + FT_TRACE5(( "latin standard widths computation (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "=====================================================\n" )); + FT_TRACE5(( "\n" )); + + af_glyph_hints_init( hints, face->memory ); + + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + + { + FT_Error error; + FT_ULong glyph_index; + int dim; + AF_LatinMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + + AF_StyleClass style_class = metrics->root.style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + const char* p; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong ch = 0; +#endif + + + p = script_class->standard_charstring; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + /* + * We check a list of standard characters to catch features like + * `c2sc' (small caps from caps) that don't contain lowercase letters + * by definition, or other features that mainly operate on numerals. + * The first match wins. + */ + + glyph_index = 0; + while ( *p ) + { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); + if ( glyph_index ) + break; + } + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + { + FT_TRACE5(( "standard character missing;" + " using fallback stem widths\n" )); + goto Exit; + } + + FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + ch, glyph_index )); + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + + FT_ZERO( dummy ); + + dummy->units_per_em = metrics->units_per_em; + + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); + + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + + + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + + /* + * We assume that the glyphs selected for the stem width + * computation are `featureless' enough so that the linking + * algorithm works fine without adjustments of its scoring + * function. + */ + af_latin_hints_link_segments( hints, + 0, + NULL, + (AF_Dimension)dim ); + + seg = axhints->segments; + limit = FT_OFFSET( seg, axhints->num_segments ); + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < AF_LATIN_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + + /* this also replaces multiple almost identical stem widths */ + /* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + + + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); + + /* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE5(( "%s widths:\n", + dim == AF_DIMENSION_VERT ? "horizontal" + : "vertical" )); + + FT_TRACE5(( " %ld (standard)", axis->standard_width )); + for ( i = 1; i < axis->width_count; i++ ) + FT_TRACE5(( " %ld", axis->widths[i].org )); + + FT_TRACE5(( "\n" )); + } +#endif + } + } + + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } + + + static void + af_latin_sort_blue( FT_UInt count, + AF_LatinBlue* table ) + { + FT_UInt i, j; + AF_LatinBlue swap; + + + /* we sort from bottom to top */ + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + FT_Pos a, b; + + + if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + a = table[j - 1]->ref.org; + else + a = table[j - 1]->shoot.org; + + if ( table[j]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + b = table[j]->ref.org; + else + b = table[j]->shoot.org; + + if ( b >= a ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + /* Find all blue zones. Flat segments give the reference points, */ + /* round segments the overshoot positions. */ + + static int + af_latin_metrics_init_blues( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Pos flats [AF_BLUE_STRING_MAX_LEN]; + FT_Pos rounds[AF_BLUE_STRING_MAX_LEN]; + + FT_UInt num_flats; + FT_UInt num_rounds; + + AF_LatinBlue blue; + FT_Error error; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + FT_Outline outline; + + AF_StyleClass sc = metrics->root.style_class; + + AF_Blue_Stringset bss = sc->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + + /* we walk over the blue character strings as specified in the */ + /* style's entry in the `af_blue_stringset' array */ + + FT_TRACE5(( "latin blue zones computation\n" )); + FT_TRACE5(( "============================\n" )); + FT_TRACE5(( "\n" )); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + FT_Pos ascender; + FT_Pos descender; + + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Bool have_flag = 0; + + + FT_TRACE5(( "blue zone %d", axis->blue_count )); + + if ( bs->properties ) + { + FT_TRACE5(( " (" )); + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + FT_TRACE5(( "top" )); + have_flag = 1; + } + else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + { + FT_TRACE5(( "sub top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "neutral" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "small top" )); + have_flag = 1; + } + + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "long" )); + } + + FT_TRACE5(( ")" )); + } + + FT_TRACE5(( ":\n" )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + num_flats = 0; + num_rounds = 0; + ascender = 0; + descender = 0; + + while ( *p ) + { + FT_ULong glyph_index; + FT_Long y_offset; + FT_Int best_point, best_contour_first, best_contour_last; + FT_Vector* points; + + FT_Pos best_y_extremum; /* same as points.y */ + FT_Bool best_round = 0; + + unsigned int i, num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + + if ( !num_idx ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + best_y_extremum = FT_INT_MIN; + else + best_y_extremum = FT_INT_MAX; + + /* iterate over all glyph elements of the character cluster */ + /* and get the data of the `biggest' one */ + for ( i = 0; i < num_idx; i++ ) + { + FT_Pos best_y; + FT_Bool round = 0; + + + /* load the character in the face -- skip unknown or empty ones */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + i, + NULL, + &y_offset ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + /* reject glyphs that don't produce any rendering */ + if ( error || outline.n_points <= 2 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( num_idx == 1 ) + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); + else + FT_TRACE5(( " component %d of cluster starting with U+%04lX" + " contains no (usable) outlines\n", i, ch )); +#endif + continue; + } + + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_contour_first = -1; + best_contour_last = -1; + best_y = 0; /* make compiler happy */ + + { + FT_Int nn; + FT_Int pp, first, last; + + + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) + { + first = last + 1; + last = outline.contours[nn]; + + /* Avoid single-point contours since they are never */ + /* rasterized. In some fonts, they correspond to mark */ + /* attachment points that are way outside of the glyph's */ + /* real outline. */ + if ( last <= first ) + continue; + + if ( AF_LATIN_IS_TOP_BLUE( bs ) || + AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + { + for ( pp = first; pp <= last; pp++ ) + { + if ( best_point < 0 || points[pp].y > best_y ) + { + best_point = pp; + best_y = points[pp].y; + ascender = FT_MAX( ascender, best_y + y_offset ); + } + else + descender = FT_MIN( descender, points[pp].y + y_offset ); + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + { + if ( best_point < 0 || points[pp].y < best_y ) + { + best_point = pp; + best_y = points[pp].y; + descender = FT_MIN( descender, best_y + y_offset ); + } + else + ascender = FT_MAX( ascender, points[pp].y + y_offset ); + } + } + + if ( best_point > best_contour_last ) + { + best_contour_first = first; + best_contour_last = last; + } + } + } + + /* now check whether the point belongs to a straight or round */ + /* segment; we first need to find in which contour the extremum */ + /* lies, then inspect its previous and next points */ + if ( best_point >= 0 ) + { + FT_Pos best_x = points[best_point].x; + FT_Int prev, next; + FT_Int best_segment_first, best_segment_last; + FT_Int best_on_point_first, best_on_point_last; + FT_Pos dist; + + + best_segment_first = best_point; + best_segment_last = best_point; + + if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = best_point; + best_on_point_last = best_point; + } + else + { + best_on_point_first = -1; + best_on_point_last = -1; + } + + /* look for the previous and next points on the contour */ + /* that are not on the same Y coordinate, then threshold */ + /* the `closeness'... */ + prev = best_point; + next = prev; + + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + + dist = FT_ABS( points[prev].y - best_y ); + /* accept a small distance or a small angle (both values are */ + /* heuristic; value 20 corresponds to approx. 2.9 degrees) */ + if ( dist > 5 ) + if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) + break; + + best_segment_first = prev; + + if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = prev; + if ( best_on_point_last < 0 ) + best_on_point_last = prev; + } + + } while ( prev != best_point ); + + do + { + if ( next < best_contour_last ) + next++; + else + next = best_contour_first; + + dist = FT_ABS( points[next].y - best_y ); + if ( dist > 5 ) + if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) + break; + + best_segment_last = next; + + if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON ) + { + best_on_point_last = next; + if ( best_on_point_first < 0 ) + best_on_point_first = next; + } + + } while ( next != best_point ); + + if ( AF_LATIN_IS_LONG_BLUE( bs ) ) + { + /* If this flag is set, we have an additional constraint to */ + /* get the blue zone distance: Find a segment of the topmost */ + /* (or bottommost) contour that is longer than a heuristic */ + /* threshold. This ensures that small bumps in the outline */ + /* are ignored (for example, the `vertical serifs' found in */ + /* many Hebrew glyph designs). */ + + /* If this segment is long enough, we are done. Otherwise, */ + /* search the segment next to the extremum that is long */ + /* enough, has the same direction, and a not too large */ + /* vertical distance from the extremum. Note that the */ + /* algorithm doesn't check whether the found segment is */ + /* actually the one (vertically) nearest to the extremum. */ + + /* heuristic threshold value */ + FT_Pos length_threshold = metrics->units_per_em / 25; + + + dist = FT_ABS( points[best_segment_last].x - + points[best_segment_first].x ); + + if ( dist < length_threshold && + best_segment_last - best_segment_first + 2 <= + best_contour_last - best_contour_first ) + { + /* heuristic threshold value */ + FT_Pos height_threshold = metrics->units_per_em / 4; + + FT_Int first; + FT_Int last; + FT_Bool hit; + + /* we intentionally declare these two variables */ + /* outside of the loop since various compilers emit */ + /* incorrect warning messages otherwise, talking about */ + /* `possibly uninitialized variables' */ + FT_Int p_first = 0; /* make compiler happy */ + FT_Int p_last = 0; + + FT_Bool left2right; + + + /* compute direction */ + prev = best_point; + + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + + if ( points[prev].x != best_x ) + break; + + } while ( prev != best_point ); + + /* skip glyph for the degenerate case */ + if ( prev == best_point ) + continue; + + left2right = FT_BOOL( points[prev].x < points[best_point].x ); + + first = best_segment_last; + last = first; + hit = 0; + + do + { + FT_Bool l2r; + FT_Pos d; + + + if ( !hit ) + { + /* no hit; adjust first point */ + first = last; + + /* also adjust first and last on point */ + if ( FT_CURVE_TAG( outline.tags[first] ) == + FT_CURVE_TAG_ON ) + { + p_first = first; + p_last = first; + } + else + { + p_first = -1; + p_last = -1; + } + + hit = 1; + } + + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + if ( FT_ABS( best_y - points[first].y ) > height_threshold ) + { + /* vertical distance too large */ + hit = 0; + continue; + } + + /* same test as above */ + dist = FT_ABS( points[last].y - points[first].y ); + if ( dist > 5 ) + if ( FT_ABS( points[last].x - points[first].x ) <= + 20 * dist ) + { + hit = 0; + continue; + } + + if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + l2r = FT_BOOL( points[first].x < points[last].x ); + d = FT_ABS( points[last].x - points[first].x ); + + if ( l2r == left2right && + d >= length_threshold ) + { + /* all constraints are met; update segment after */ + /* finding its end */ + do + { + if ( last < best_contour_last ) + last++; + else + last = best_contour_first; + + d = FT_ABS( points[last].y - points[first].y ); + if ( d > 5 ) + if ( FT_ABS( points[next].x - points[first].x ) <= + 20 * dist ) + { + if ( last > best_contour_first ) + last--; + else + last = best_contour_last; + break; + } + + p_last = last; + + if ( FT_CURVE_TAG( outline.tags[last] ) == + FT_CURVE_TAG_ON ) + { + p_last = last; + if ( p_first < 0 ) + p_first = last; + } + + } while ( last != best_segment_first ); + + best_y = points[first].y; + + best_segment_first = first; + best_segment_last = last; + + best_on_point_first = p_first; + best_on_point_last = p_last; + + break; + } + + } while ( last != best_segment_first ); + } + } + + /* for computing blue zones, we add the y offset as returned */ + /* by the currently used OpenType feature -- for example, */ + /* superscript glyphs might be identical to subscript glyphs */ + /* with a vertical shift */ + best_y += y_offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( num_idx == 1 ) + FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); + else + FT_TRACE5(( " component %d of cluster starting with U+%04lX:" + " best_y = %5ld", i, ch, best_y )); +#endif + + /* now set the `round' flag depending on the segment's kind: */ + /* */ + /* - if the horizontal distance between the first and last */ + /* `on' point is larger than a heuristic threshold */ + /* we have a flat segment */ + /* - if either the first or the last point of the segment is */ + /* an `off' point, the segment is round, otherwise it is */ + /* flat */ + if ( best_on_point_first >= 0 && + best_on_point_last >= 0 && + ( FT_ABS( points[best_on_point_last].x - + points[best_on_point_first].x ) ) > + flat_threshold ) + round = 0; + else + round = FT_BOOL( + FT_CURVE_TAG( outline.tags[best_segment_first] ) != + FT_CURVE_TAG_ON || + FT_CURVE_TAG( outline.tags[best_segment_last] ) != + FT_CURVE_TAG_ON ); + + if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + { + /* only use flat segments for a neutral blue zone */ + FT_TRACE5(( " (round, skipped)\n" )); + continue; + } + + FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); + } + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + if ( best_y > best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } + else + { + if ( best_y < best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } + + } /* end for loop */ + + if ( !( best_y_extremum == FT_INT_MIN || + best_y_extremum == FT_INT_MAX ) ) + { + if ( best_round ) + rounds[num_rounds++] = best_y_extremum; + else + flats[num_flats++] = best_y_extremum; + } + + } /* end while loop */ + + if ( num_flats == 0 && num_rounds == 0 ) + { + /* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } + + /* we have computed the contents of the `rounds' and `flats' tables, */ + /* now determine the reference and overshoot position of the blue -- */ + /* we simply take the median value after a simple sort */ + af_sort_pos( num_rounds, rounds ); + af_sort_pos( num_flats, flats ); + + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; + + axis->blue_count++; + + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = rounds[num_rounds / 2]; + } + else if ( num_rounds == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = flats [num_flats / 2]; + *blue_shoot = rounds[num_rounds / 2]; + } + + /* there are sometimes problems: if the overshoot position of top */ + /* zones is under its reference position, or the opposite for bottom */ + /* zones. We must thus check everything there and correct the errors */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool over_ref = FT_BOOL( shoot > ref ); + + + if ( ( AF_LATIN_IS_TOP_BLUE( bs ) || + AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } + } + + blue->ascender = ascender; + blue->descender = descender; + + blue->flags = 0; + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_TOP; + if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_SUB_TOP; + if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_NEUTRAL; + + /* + * The following flag is used later to adjust the y and x scales + * in order to optimize the pixel grid alignment of the top of small + * letters. + */ + if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; + + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); + + if ( axis->blue_count ) + { + /* we finally check whether blue zones are ordered; */ + /* `ref' and `shoot' values of two blue zones must not overlap */ + + FT_UInt i; + AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN]; + + + for ( i = 0; i < axis->blue_count; i++ ) + blue_sorted[i] = &axis->blues[i]; + + /* sort bottoms of blue zones... */ + af_latin_sort_blue( axis->blue_count, blue_sorted ); + + /* ...and adjust top values if necessary */ + for ( i = 0; i < axis->blue_count - 1; i++ ) + { + FT_Pos* a; + FT_Pos* b; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool a_is_top = 0; +#endif + + + if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + { + a = &blue_sorted[i]->shoot.org; +#ifdef FT_DEBUG_LEVEL_TRACE + a_is_top = 1; +#endif + } + else + a = &blue_sorted[i]->ref.org; + + if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) + b = &blue_sorted[i + 1]->shoot.org; + else + b = &blue_sorted[i + 1]->ref.org; + + if ( *a > *b ) + { + *a = *b; + FT_TRACE5(( "blue zone overlap:" + " adjusting %s %td to %ld\n", + a_is_top ? "overshoot" : "reference", + blue_sorted[i] - axis->blues, + *a )); + } + } + + FT_TRACE5(( "\n" )); + + return 0; + } + else + { + /* disable hinting for the current style if there are no blue zones */ + + AF_FaceGlobals globals = metrics->root.globals; + FT_UShort* gstyles = globals->glyph_styles; + + FT_UInt i; + + + FT_TRACE5(( "no blue zones found:" + " hinting disabled for this style\n" )); + + for ( i = 0; i < globals->glyph_count; i++ ) + { + if ( ( gstyles[i] & AF_STYLE_MASK ) == sc->style ) + gstyles[i] = AF_STYLE_NONE_DFLT; + } + + FT_TRACE5(( "\n" )); + + return 1; + } + } + + + /* Check whether all ASCII digits have the same advance width. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; + + /* If HarfBuzz is not available, we need a pointer to a single */ + /* unsigned long value. */ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + void* shaper_buf; +#else + FT_ULong shaper_buf_; + void* shaper_buf = &shaper_buf_; +#endif + + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + shaper_buf = af_shaper_buf_create( face ); +#endif + + while ( *p ) + { + FT_ULong glyph_index; + unsigned int num_idx; + + + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) + continue; + + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + + af_shaper_buf_destroy( face, shaper_buf ); + + metrics->root.digits_have_same_width = same_width; + } + + + /* Initialize global metrics. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_metrics_init( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + FT_Face face ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Error error = FT_Err_Ok; + + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + { + af_latin_metrics_init_widths( metrics, face ); + if ( af_latin_metrics_init_blues( metrics, face ) ) + { + /* use internal error code to indicate missing blue zones */ + error = -1; + goto Exit; + } + af_latin_metrics_check_digits( metrics, face ); + } + + Exit: + face->charmap = oldmap; + return error; + } + + + /* Adjust scaling value, then scale and shift widths */ + /* and blue zones (if applicable) for given dimension. */ + + static void + af_latin_metrics_scale_dim( AF_LatinMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_LatinAxis axis; + FT_UInt nn; + + + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + + axis = &metrics->axis[dim]; + + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + + axis->org_scale = scale; + axis->org_delta = delta; + + /* + * correct X and Y scale to optimize the alignment of the top of small + * letters to the pixel grid + */ + { + AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinBlue blue = NULL; + + + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + { + blue = &Axis->blues[nn]; + break; + } + } + + if ( blue ) + { + FT_Pos scaled; + FT_Pos threshold; + FT_Pos fitted; + FT_UInt limit; + FT_UInt ppem; + + + scaled = FT_MulFix( blue->shoot.org, scale ); + ppem = metrics->root.scaler.face->size->metrics.x_ppem; + limit = metrics->root.globals->increase_x_height; + threshold = 40; + + /* if the `increase-x-height' property is active, */ + /* we round up much more often */ + if ( limit && + ppem <= limit && + ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN ) + threshold = 52; + + fitted = ( scaled + threshold ) & ~63; + + if ( scaled != fitted ) + { +#if 0 + if ( dim == AF_DIMENSION_HORZ ) + { + if ( fitted < scaled ) + scale -= scale / 50; /* scale *= 0.98 */ + } + else +#endif + if ( dim == AF_DIMENSION_VERT ) + { + FT_Pos max_height; + FT_Pos dist; + FT_Fixed new_scale; + + + new_scale = FT_MulDiv( scale, fitted, scaled ); + + /* the scaling should not change the result by more than two pixels */ + max_height = metrics->units_per_em; + + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { + max_height = FT_MAX( max_height, Axis->blues[nn].ascender ); + max_height = FT_MAX( max_height, -Axis->blues[nn].descender ); + } + + dist = FT_MulFix( max_height, new_scale - scale ); + + if ( -128 < dist && dist < 128 ) + { + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " vertical scaling changed" + " from %.5f to %.5f (by %ld%%)\n", + (double)scale / 65536, + (double)new_scale / 65536, + ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "\n" )); + + scale = new_scale; + } +#ifdef FT_DEBUG_LEVEL_TRACE + else + { + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " excessive vertical scaling abandoned\n" )); + FT_TRACE5(( "\n" )); + } +#endif + } + } + } + } + + axis->scale = scale; + axis->delta = delta; + + if ( dim == AF_DIMENSION_HORZ ) + { + metrics->root.scaler.x_scale = scale; + metrics->root.scaler.x_delta = delta; + } + else + { + metrics->root.scaler.y_scale = scale; + metrics->root.scaler.y_delta = delta; + } + + FT_TRACE5(( "%s widths (style `%s')\n", + dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical", + af_style_names[metrics->root.style_class->style] )); + + /* scale the widths */ + for ( nn = 0; nn < axis->width_count; nn++ ) + { + AF_Width width = axis->widths + nn; + + + width->cur = FT_MulFix( width->org, scale ); + width->fit = width->cur; + + FT_TRACE5(( " %ld scaled to %.2f\n", + width->org, + (double)width->cur / 64 )); + } + + FT_TRACE5(( "\n" )); + + /* an extra-light axis corresponds to a standard width that is */ + /* smaller than 5/8 pixels */ + axis->extra_light = + FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( axis->extra_light ) + { + FT_TRACE5(( "`%s' style is extra light (at current resolution)\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "\n" )); + } +#endif + + if ( dim == AF_DIMENSION_VERT ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( axis->blue_count ) + FT_TRACE5(( "blue zones (style `%s')\n", + af_style_names[metrics->root.style_class->style] )); +#endif + + /* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_Pos dist; + + + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { +#if 0 + FT_Pos delta1; +#endif + FT_Pos delta2; + + + /* use discrete values for blue zone widths */ + +#if 0 + + /* generic, original code */ + delta1 = blue->shoot.org - blue->ref.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + + delta2 = FT_MulFix( delta2, scale ); + + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); + else + delta2 = FT_PIX_ROUND( delta2 ); + + if ( delta1 < 0 ) + delta2 = -delta2; + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit + delta2; + +#else + + /* simplified version due to abs(dist) <= 48 */ + delta2 = dist; + if ( dist < 0 ) + delta2 = -delta2; + + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 48 ) + delta2 = 32; + else + delta2 = 64; + + if ( dist < 0 ) + delta2 = -delta2; + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit - delta2; + +#endif + + blue->flags |= AF_LATIN_BLUE_ACTIVE; + } + } + + /* use sub-top blue zone only if it doesn't overlap with */ + /* another (non-sup-top) blue zone; otherwise, the */ + /* effect would be similar to a neutral blue zone, which */ + /* is not desired here */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_UInt i; + + + if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) ) + continue; + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + for ( i = 0; i < axis->blue_count; i++ ) + { + AF_LatinBlue b = &axis->blues[i]; + + + if ( b->flags & AF_LATIN_BLUE_SUB_TOP ) + continue; + if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + if ( b->ref.fit <= blue->shoot.fit && + b->shoot.fit >= blue->ref.fit ) + { + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; + break; + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + + + FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n", + nn, + blue->ref.org, + (double)blue->ref.fit / 64, + ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" + : " (inactive)" )); + FT_TRACE5(( " overshoot %d: %ld scaled to %.2f%s\n", + nn, + blue->shoot.org, + (double)blue->shoot.fit / 64, + ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" + : " (inactive)" )); + } +#endif + } + } + + + /* Scale global values in both directions. */ + + FT_LOCAL_DEF( void ) + af_latin_metrics_scale( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + AF_Scaler scaler ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + metrics->root.scaler.render_mode = scaler->render_mode; + metrics->root.scaler.face = scaler->face; + metrics->root.scaler.flags = scaler->flags; + + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } + + + /* Extract standard_width from writing system/script specific */ + /* metrics class. */ + + FT_CALLBACK_DEF( void ) + af_latin_get_standard_widths( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + if ( stdHW ) + *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; + + if ( stdVW ) + *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* Walk over all contours and compute its segments. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_AxisHints axis = &hints->axis[dim]; + FT_Memory memory = hints->memory; + FT_Error error = FT_Err_Ok; + AF_Segment segment = NULL; + AF_SegmentRec seg0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Direction major_dir, segment_dir; + + FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); + + + FT_ZERO( &seg0 ); + seg0.score = 32000; + seg0.flags = AF_EDGE_NORMAL; + + major_dir = (AF_Direction)FT_ABS( axis->major_dir ); + segment_dir = major_dir; + + axis->num_segments = 0; + + /* set up (u,v) in each point */ + if ( dim == AF_DIMENSION_HORZ ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + + + for ( ; point < limit; point++ ) + { + point->u = point->fx; + point->v = point->fy; + } + } + else + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + + + for ( ; point < limit; point++ ) + { + point->u = point->fy; + point->v = point->fx; + } + } + + /* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point last = point->prev; + int on_edge = 0; + + /* we call values measured along a segment (point->v) */ + /* `coordinates', and values orthogonal to it (point->u) */ + /* `positions' */ + FT_Pos min_pos = 32000; + FT_Pos max_pos = -32000; + FT_Pos min_coord = 32000; + FT_Pos max_coord = -32000; + FT_UShort min_flags = AF_FLAG_NONE; + FT_UShort max_flags = AF_FLAG_NONE; + FT_Pos min_on_coord = 32000; + FT_Pos max_on_coord = -32000; + + FT_Bool passed; + + AF_Segment prev_segment = NULL; + + FT_Pos prev_min_pos = min_pos; + FT_Pos prev_max_pos = max_pos; + FT_Pos prev_min_coord = min_coord; + FT_Pos prev_max_coord = max_coord; + FT_UShort prev_min_flags = min_flags; + FT_UShort prev_max_flags = max_flags; + FT_Pos prev_min_on_coord = min_on_coord; + FT_Pos prev_max_on_coord = max_on_coord; + + + if ( FT_ABS( last->out_dir ) == major_dir && + FT_ABS( point->out_dir ) == major_dir ) + { + /* we are already on an edge, try to locate its start */ + last = point; + + for (;;) + { + point = point->prev; + if ( FT_ABS( point->out_dir ) != major_dir ) + { + point = point->next; + break; + } + if ( point == last ) + break; + } + } + + last = point; + passed = 0; + + for (;;) + { + FT_Pos u, v; + + + if ( on_edge ) + { + /* get minimum and maximum position */ + u = point->u; + if ( u < min_pos ) + min_pos = u; + if ( u > max_pos ) + max_pos = u; + + /* get minimum and maximum coordinate together with flags */ + v = point->v; + if ( v < min_coord ) + { + min_coord = v; + min_flags = point->flags; + } + if ( v > max_coord ) + { + max_coord = v; + max_flags = point->flags; + } + + /* get minimum and maximum coordinate of `on' points */ + if ( !( point->flags & AF_FLAG_CONTROL ) ) + { + v = point->v; + if ( v < min_on_coord ) + min_on_coord = v; + if ( v > max_on_coord ) + max_on_coord = v; + } + + if ( point->out_dir != segment_dir || point == last ) + { + /* check whether the new segment's start point is identical to */ + /* the previous segment's end point; for example, this might */ + /* happen for spikes */ + + if ( !prev_segment || segment->first != prev_segment->last ) + { + /* points are different: we are just leaving an edge, thus */ + /* record a new segment */ + + segment->last = point; + segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); + segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 ); + + /* a segment is round if either its first or last point */ + /* is a control point, and the length of the on points */ + /* inbetween doesn't exceed a heuristic limit */ + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)min_coord; + segment->max_coord = (FT_Short)max_coord; + segment->height = segment->max_coord - segment->min_coord; + + prev_segment = segment; + prev_min_pos = min_pos; + prev_max_pos = max_pos; + prev_min_coord = min_coord; + prev_max_coord = max_coord; + prev_min_flags = min_flags; + prev_max_flags = max_flags; + prev_min_on_coord = min_on_coord; + prev_max_on_coord = max_on_coord; + } + else + { + /* points are the same: we don't create a new segment but */ + /* merge the current segment with the previous one */ + + if ( prev_segment->last->in_dir == point->in_dir ) + { + /* we have identical directions (this can happen for */ + /* degenerate outlines that move zig-zag along the main */ + /* axis without changing the coordinate value of the other */ + /* axis, and where the segments have just been merged): */ + /* unify segments */ + + /* update constraints */ + + if ( prev_min_pos < min_pos ) + min_pos = prev_min_pos; + if ( prev_max_pos > max_pos ) + max_pos = prev_max_pos; + + if ( prev_min_coord < min_coord ) + { + min_coord = prev_min_coord; + min_flags = prev_min_flags; + } + if ( prev_max_coord > max_coord ) + { + max_coord = prev_max_coord; + max_flags = prev_max_flags; + } + + if ( prev_min_on_coord < min_on_coord ) + min_on_coord = prev_min_on_coord; + if ( prev_max_on_coord > max_on_coord ) + max_on_coord = prev_max_on_coord; + + prev_segment->last = point; + prev_segment->pos = (FT_Short)( ( min_pos + + max_pos ) >> 1 ); + prev_segment->delta = (FT_Short)( ( max_pos - + min_pos ) >> 1 ); + + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + prev_segment->flags |= AF_EDGE_ROUND; + else + prev_segment->flags &= ~AF_EDGE_ROUND; + + prev_segment->min_coord = (FT_Short)min_coord; + prev_segment->max_coord = (FT_Short)max_coord; + prev_segment->height = prev_segment->max_coord - + prev_segment->min_coord; + } + else + { + /* we have different directions; use the properties of the */ + /* longer segment and discard the other one */ + + if ( FT_ABS( prev_max_coord - prev_min_coord ) > + FT_ABS( max_coord - min_coord ) ) + { + /* discard current segment */ + + if ( min_pos < prev_min_pos ) + prev_min_pos = min_pos; + if ( max_pos > prev_max_pos ) + prev_max_pos = max_pos; + + prev_segment->last = point; + prev_segment->pos = (FT_Short)( ( prev_min_pos + + prev_max_pos ) >> 1 ); + prev_segment->delta = (FT_Short)( ( prev_max_pos - + prev_min_pos ) >> 1 ); + } + else + { + /* discard previous segment */ + + if ( prev_min_pos < min_pos ) + min_pos = prev_min_pos; + if ( prev_max_pos > max_pos ) + max_pos = prev_max_pos; + + segment->last = point; + segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); + segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 ); + + if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL && + ( max_on_coord - min_on_coord ) < flat_threshold ) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)min_coord; + segment->max_coord = (FT_Short)max_coord; + segment->height = segment->max_coord - + segment->min_coord; + + *prev_segment = *segment; + + prev_min_pos = min_pos; + prev_max_pos = max_pos; + prev_min_coord = min_coord; + prev_max_coord = max_coord; + prev_min_flags = min_flags; + prev_max_flags = max_flags; + prev_min_on_coord = min_on_coord; + prev_max_on_coord = max_on_coord; + } + } + + axis->num_segments--; + } + + on_edge = 0; + segment = NULL; + + /* fall through */ + } + } + + /* now exit if we are at the start/end point */ + if ( point == last ) + { + if ( passed ) + break; + passed = 1; + } + + /* if we are not on an edge, check whether the major direction */ + /* coincides with the current point's `out' direction, or */ + /* whether we have a single-point contour */ + if ( !on_edge && + ( FT_ABS( point->out_dir ) == major_dir || + point == point->prev ) ) + { + /* + * For efficiency, we restrict the number of segments to 1000, + * which is a heuristic value: it is very unlikely that a glyph + * with so many segments can be hinted in a sensible way. + * Reasons: + * + * - The glyph has really 1000 segments; this implies that it has + * at least 2000 outline points. Assuming 'normal' fonts that + * have superfluous points optimized away, viewing such a glyph + * only makes sense at large magnifications where hinting + * isn't applied anyway. + * + * - We have a broken glyph. Hinting doesn't make sense in this + * case either. + */ + if ( axis->num_segments > 1000 ) + { + FT_TRACE0(( "af_latin_hints_compute_segments:" + " more than 1000 segments in this glyph;\n" )); + FT_TRACE0(( " " + " hinting is suppressed\n" )); + axis->num_segments = 0; + return FT_Err_Ok; + } + + /* this is the start of a new segment! */ + segment_dir = (AF_Direction)point->out_dir; + + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; + + /* clear all segment fields */ + segment[0] = seg0; + + segment->dir = (FT_Char)segment_dir; + segment->first = point; + segment->last = point; + + /* `af_axis_hints_new_segment' reallocates memory, */ + /* thus we have to refresh the `prev_segment' pointer */ + if ( prev_segment ) + prev_segment = segment - 1; + + min_pos = max_pos = point->u; + min_coord = max_coord = point->v; + min_flags = max_flags = point->flags; + + if ( point->flags & AF_FLAG_CONTROL ) + { + min_on_coord = 32000; + max_on_coord = -32000; + } + else + min_on_coord = max_on_coord = point->v; + + on_edge = 1; + + if ( point == point->prev ) + { + /* we have a one-point segment: this is a one-point */ + /* contour with `in' and `out' direction set to */ + /* AF_DIR_NONE */ + segment->pos = (FT_Short)min_pos; + + if (point->flags & AF_FLAG_CONTROL) + segment->flags |= AF_EDGE_ROUND; + + segment->min_coord = (FT_Short)point->v; + segment->max_coord = (FT_Short)point->v; + segment->height = 0; + + on_edge = 0; + segment = NULL; + } + } + + point = point->next; + } + + } /* contours */ + + + /* now slightly increase the height of segments if this makes */ + /* sense -- this is used to better detect and ignore serifs */ + { + AF_Segment segments = axis->segments; + AF_Segment segments_end = FT_OFFSET( segments, axis->num_segments ); + + + for ( segment = segments; segment < segments_end; segment++ ) + { + AF_Point first = segment->first; + AF_Point last = segment->last; + FT_Pos first_v = first->v; + FT_Pos last_v = last->v; + + + if ( first_v < last_v ) + { + AF_Point p; + + + p = first->prev; + if ( p->v < first_v ) + segment->height = (FT_Short)( segment->height + + ( ( first_v - p->v ) >> 1 ) ); + + p = last->next; + if ( p->v > last_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - last_v ) >> 1 ) ); + } + else + { + AF_Point p; + + + p = first->prev; + if ( p->v > first_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - first_v ) >> 1 ) ); + + p = last->next; + if ( p->v < last_v ) + segment->height = (FT_Short)( segment->height + + ( ( last_v - p->v ) >> 1 ) ); + } + } + } + + Exit: + return error; + } + + + /* Link segments to form stems and serifs. If `width_count' and */ + /* `widths' are non-zero, use them to fine-tune the scoring function. */ + + FT_LOCAL_DEF( void ) + af_latin_hints_link_segments( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + FT_Pos len_threshold, len_score, dist_score, max_width; + AF_Segment seg1, seg2; + + + if ( width_count ) + max_width = widths[width_count - 1].org; + else + max_width = 0; + + /* a heuristic value to set up a minimum value for overlapping */ + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + if ( len_threshold == 0 ) + len_threshold = 1; + + /* a heuristic value to weight lengths */ + len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); + + /* a heuristic value to weight distances (no call to */ + /* AF_LATIN_CONSTANT needed, since we work on multiples */ + /* of the stem width) */ + dist_score = 3000; + + /* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + if ( seg1->dir != axis->major_dir ) + continue; + + /* search for stems having opposite directions, */ + /* with seg1 to the `left' of seg2 */ + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + FT_Pos pos1 = seg1->pos; + FT_Pos pos2 = seg2->pos; + + + if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 ) + { + /* compute distance between the two segments */ + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len; + + + if ( min < seg2->min_coord ) + min = seg2->min_coord; + + if ( max > seg2->max_coord ) + max = seg2->max_coord; + + /* compute maximum coordinate difference of the two segments */ + /* (that is, how much they overlap) */ + len = max - min; + if ( len >= len_threshold ) + { + /* + * The score is the sum of two demerits indicating the + * `badness' of a fit, measured along the segments' main axis + * and orthogonal to it, respectively. + * + * - The less overlapping along the main axis, the worse it + * is, causing a larger demerit. + * + * - The nearer the orthogonal distance to a stem width, the + * better it is, causing a smaller demerit. For simplicity, + * however, we only increase the demerit for values that + * exceed the largest stem width. + */ + + FT_Pos dist = pos2 - pos1; + + FT_Pos dist_demerit, score; + + + if ( max_width ) + { + /* distance demerits are based on multiples of `max_width'; */ + /* we scale by 1024 for getting more precision */ + FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 ); + + + if ( delta > 10000 ) + dist_demerit = 32000; + else if ( delta > 0 ) + dist_demerit = delta * delta / dist_score; + else + dist_demerit = 0; + } + else + dist_demerit = dist; /* default if no widths available */ + + score = dist_demerit + len_score / len; + + /* and we search for the smallest score */ + if ( score < seg1->score ) + { + seg1->score = score; + seg1->link = seg2; + } + + if ( score < seg2->score ) + { + seg2->score = score; + seg2->link = seg1; + } + } + } + } + } + + /* now compute the `serif' segments, cf. explanations in `afhints.h' */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = NULL; + seg1->serif = seg2->link; + } + } + } + } + + + /* Link segments to edges, using feature analysis for selection. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = FT_Err_Ok; + FT_Memory memory = hints->memory; + AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; + + AF_StyleClass style_class = hints->metrics->style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + FT_Bool top_to_bottom_hinting = 0; + + AF_Segment segments = axis->segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); + AF_Segment seg; + +#if 0 + AF_Direction up_dir; +#endif + FT_Fixed scale; + FT_Pos edge_distance_threshold; + FT_Pos segment_length_threshold; + FT_Pos segment_width_threshold; + + + axis->num_edges = 0; + + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + +#if 0 + up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP + : AF_DIR_RIGHT; +#endif + + if ( dim == AF_DIMENSION_VERT ) + top_to_bottom_hinting = script_class->top_to_bottom_hinting; + + /* + * We ignore all segments that are less than 1 pixel in length + * to avoid many problems with serif fonts. We compute the + * corresponding threshold in font units. + */ + if ( dim == AF_DIMENSION_HORZ ) + segment_length_threshold = FT_DivFix( 64, hints->y_scale ); + else + segment_length_threshold = 0; + + /* + * Similarly, we ignore segments that have a width delta + * larger than 0.5px (i.e., a width larger than 1px). + */ + segment_width_threshold = FT_DivFix( 32, scale ); + + /********************************************************************** + * + * We begin by generating a sorted table of edges for the current + * direction. To do so, we simply scan each segment and try to find + * an edge in our table that corresponds to its position. + * + * If no edge is found, we create and insert a new edge in the + * sorted table. Otherwise, we simply add the segment to the edge's + * list which gets processed in the second step to compute the + * edge's properties. + * + * Note that the table of edges is sorted along the segment/edge + * position. + * + */ + + /* assure that edge distance threshold is at most 0.25px */ + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = 64 / 4; + + edge_distance_threshold = FT_DivFix( edge_distance_threshold, + scale ); + + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_UInt ee; + + + /* ignore too short segments, too wide ones, and, in this loop, */ + /* one-point segments without a direction */ + if ( seg->height < segment_length_threshold || + seg->delta > segment_width_threshold || + seg->dir == AF_DIR_NONE ) + continue; + + /* A special case for serif edges: If they are smaller than */ + /* 1.5 pixels we ignore them. */ + if ( seg->serif && + 2 * seg->height < 3 * segment_length_threshold ) + continue; + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold && edge->dir == seg->dir ) + { + found = edge; + break; + } + } + + if ( !found ) + { + AF_Edge edge; + + + /* insert a new edge in the list and */ + /* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, + top_to_bottom_hinting, + memory, &edge ); + if ( error ) + goto Exit; + + /* add the segment to the new edge's list */ + FT_ZERO( edge ); + + edge->first = seg; + edge->last = seg; + edge->dir = seg->dir; + edge->fpos = seg->pos; + edge->opos = FT_MulFix( seg->pos, scale ); + edge->pos = edge->opos; + seg->edge_next = seg; + } + else + { + /* if an edge was found, simply add the segment to the edge's */ + /* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + /* we loop again over all segments to catch one-point segments */ + /* without a direction: if possible, link them to existing edges */ + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_UInt ee; + + + if ( seg->dir != AF_DIR_NONE ) + continue; + + /* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + + + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + + if ( dist < edge_distance_threshold ) + { + found = edge; + break; + } + } + + /* one-point segments without a match are ignored */ + if ( found ) + { + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } + + + /******************************************************************* + * + * Good, we now compute each edge's properties according to the + * segments found on its position. Basically, these are + * + * - the edge's main direction + * - stem edge, serif edge or both (which defaults to stem then) + * - rounded edge, straight or both (which defaults to straight) + * - link for edge + * + */ + + /* first of all, set the `edge' field in each segment -- this is */ + /* required in order to compute edge links */ + + /* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + + /* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Int is_round = 0; /* does it contain round segments? */ + FT_Int is_straight = 0; /* does it contain straight segments? */ +#if 0 + FT_Pos ups = 0; /* number of upwards segments */ + FT_Pos downs = 0; /* number of downwards segments */ +#endif + + + seg = edge->first; + + do + { + FT_Bool is_serif; + + + /* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; + +#if 0 + /* check for segment direction */ + if ( seg->dir == up_dir ) + ups += seg->max_coord - seg->min_coord; + else + downs += seg->max_coord - seg->min_coord; +#endif + + /* check for links -- if seg->serif is set, then seg->link must */ + /* be ignored */ + is_serif = FT_BOOL( seg->serif && + seg->serif->edge && + seg->serif->edge != edge ); + + if ( ( seg->link && seg->link->edge ) || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + + + edge2 = edge->link; + seg2 = seg->link; + + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + + /* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; + +#if 0 + /* set the edge's main direction */ + edge->dir = AF_DIR_NONE; + + if ( ups > downs ) + edge->dir = (FT_Char)up_dir; + + else if ( ups < downs ) + edge->dir = (FT_Char)-up_dir; + + else if ( ups == downs ) + edge->dir = 0; /* both up and down! */ +#endif + + /* get rid of serifs if link is set */ + /* XXX: This gets rid of many unpleasant artefacts! */ + /* Example: the `c' in cour.pfa at size 13 */ + + if ( edge->serif && edge->link ) + edge->serif = NULL; + } + } + + Exit: + return error; + } + + + /* Detect segments and edges for given dimension. */ + + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_detect_features( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ) + { + FT_Error error; + + + error = af_latin_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_latin_hints_link_segments( hints, width_count, widths, dim ); + + error = af_latin_hints_compute_edges( hints, dim ); + } + + return error; + } + + + /* Compute all edges which lie within blue zones. */ + + static void + af_latin_hints_compute_blue_edges( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); + AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; + FT_Fixed scale = latin->scale; + + + /* compute which blue zones are active, i.e. have their scaled */ + /* size < 3/4 pixels */ + + /* for each horizontal edge search the blue zone which is closest */ + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Bool best_blue_is_neutral = 0; + FT_Pos best_dist; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + /* (the value 40 is heuristic) */ + best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); + + /* assure a minimum distance of 0.5px */ + if ( best_dist > 64 / 2 ) + best_dist = 64 / 2; + + for ( bb = 0; bb < latin->blue_count; bb++ ) + { + AF_LatinBlue blue = latin->blues + bb; + FT_Bool is_top_blue, is_neutral_blue, is_major_dir; + + + /* skip inactive blue zones (i.e., those that are too large) */ + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; + + /* if it is a top zone, check for right edges (against the major */ + /* direction); if it is a bottom zone, check for left edges (in */ + /* the major direction) -- this assumes the TrueType convention */ + /* for the orientation of contours */ + is_top_blue = + (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP | + AF_LATIN_BLUE_SUB_TOP ) ) != 0 ); + is_neutral_blue = + (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0); + is_major_dir = + FT_BOOL( edge->dir == axis->major_dir ); + + /* neutral blue zones are handled for both directions */ + if ( is_top_blue ^ is_major_dir || is_neutral_blue ) + { + FT_Pos dist; + + + /* first of all, compare it to the reference position */ + dist = edge->fpos - blue->ref.org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->ref; + best_blue_is_neutral = is_neutral_blue; + } + + /* now compare it to the overshoot position and check whether */ + /* the edge is rounded, and whether the edge is over the */ + /* reference position of a top zone, or under the reference */ + /* position of a bottom zone (provided we don't have a */ + /* neutral blue zone) */ + if ( edge->flags & AF_EDGE_ROUND && + dist != 0 && + !is_neutral_blue ) + { + FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); + + + if ( is_top_blue ^ is_under_ref ) + { + dist = edge->fpos - blue->shoot.org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->shoot; + best_blue_is_neutral = is_neutral_blue; + } + } + } + } + } + + if ( best_blue ) + { + edge->blue_edge = best_blue; + if ( best_blue_is_neutral ) + edge->flags |= AF_EDGE_NEUTRAL; + } + } + } + + + /* Initalize hinting engine. */ + + static FT_Error + af_latin_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + FT_Face face = metrics->root.scaler.face; + + + af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); + + /* + * correct x_scale and y_scale if needed, since they may have + * been modified by `af_latin_metrics_scale_dim' above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; + + /* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; + + scaler_flags = hints->scaler_flags; + other_flags = 0; + + /* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; + + /* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; + + /* + * We adjust stems to full pixels unless in `light' or `lcd' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; + + /* + * In `light' or `lcd' mode we disable horizontal hinting completely. + * We also do it if the face is italic. + * + * However, if warping is enabled (which only works in `light' hinting + * mode), advance widths get adjusted, too. + */ + if ( mode == FT_RENDER_MODE_LIGHT || mode == FT_RENDER_MODE_LCD || + ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) + scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; + + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H G R I D - F I T T I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* Snap a given width in scaled coordinates to one of the */ + /* current standard widths. */ + + static FT_Pos + af_latin_snap_width( AF_Width widths, + FT_UInt count, + FT_Pos width ) + { + FT_UInt n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + + + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + scaled = FT_PIX_ROUND( reference ); + + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + + return width; + } + + + /* Compute the snapped width of a given stem, ignoring very thin ones. */ + /* There is a lot of voodoo in this function; changing the hard-coded */ + /* parameters influence the whole hinting process. */ + + static FT_Pos + af_latin_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + FT_Pos base_delta, + FT_UInt base_flags, + FT_UInt stem_flags ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Int vertical = ( dim == AF_DIMENSION_VERT ); + + + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; + + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { + /* smooth hinting process: very lightly quantize the stem width */ + + /* leave the widths of serifs alone */ + if ( ( stem_flags & AF_EDGE_SERIF ) && + vertical && + ( dist < 3 * 64 ) ) + goto Done_Width; + + else if ( base_flags & AF_EDGE_ROUND ) + { + if ( dist < 80 ) + dist = 64; + } + else if ( dist < 56 ) + dist = 56; + + if ( axis->width_count > 0 ) + { + FT_Pos delta; + + + /* compare to standard width */ + delta = dist - axis->widths[0].cur; + + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } + + if ( dist < 3 * 64 ) + { + delta = dist & 63; + dist &= -64; + + if ( delta < 10 ) + dist += delta; + + else if ( delta < 32 ) + dist += 10; + + else if ( delta < 54 ) + dist += 54; + + else + dist += delta; + } + else + { + /* A stem's end position depends on two values: the start */ + /* position and the stem length. The former gets usually */ + /* rounded to the grid, while the latter gets rounded also if it */ + /* exceeds a certain length (see below in this function). This */ + /* `double rounding' can lead to a great difference to the */ + /* original, unhinted position; this normally doesn't matter for */ + /* large PPEM values, but for small sizes it can easily make */ + /* outlines collide. For this reason, we adjust the stem length */ + /* by a small amount depending on the PPEM value in case the */ + /* former and latter rounding both point into the same */ + /* direction. */ + + FT_Pos bdelta = 0; + + + if ( ( ( width > 0 ) && ( base_delta > 0 ) ) || + ( ( width < 0 ) && ( base_delta < 0 ) ) ) + { + FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem; + + + if ( ppem < 10 ) + bdelta = base_delta; + else if ( ppem < 30 ) + bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20; + + if ( bdelta < 0 ) + bdelta = -bdelta; + } + + dist = ( dist - bdelta + 32 ) & ~63; + } + } + } + else + { + /* strong hinting process: snap the stem width to integer pixels */ + + FT_Pos org_dist = dist; + + + dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); + + if ( vertical ) + { + /* in the case of vertical hinting, always round */ + /* the stem heights to integer pixels */ + + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { + /* monochrome horizontal hinting: snap widths to integer pixels */ + /* with a different threshold */ + + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { + /* for horizontal anti-aliased hinting, we adopt a more subtle */ + /* approach: we strengthen small stems, round stems whose size */ + /* is between 1 and 2 pixels to an integer, otherwise nothing */ + + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + + else if ( dist < 128 ) + { + /* We only round to an integer width if the corresponding */ + /* distortion is less than 1/4 pixel. Otherwise this */ + /* makes everything worse since the diagonals, which are */ + /* not hinted, appear a lot bolder or thinner than the */ + /* vertical stems. */ + + FT_Pos delta; + + + dist = ( dist + 22 ) & ~63; + delta = dist - org_dist; + if ( delta < 0 ) + delta = -delta; + + if ( delta >= 16 ) + { + dist = org_dist; + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + } + } + else + /* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + + Done_Width: + if ( sign ) + dist = -dist; + + return dist; + } + + + /* Align one stem edge relative to the previous stem edge. */ + + static void + af_latin_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist, base_delta; + FT_Pos fitted_width; + + + dist = stem_edge->opos - base_edge->opos; + base_delta = base_edge->pos - base_edge->opos; + + fitted_width = af_latin_compute_stem_width( hints, dim, + dist, base_delta, + base_edge->flags, + stem_edge->flags ); + + + stem_edge->pos = base_edge->pos + fitted_width; + + FT_TRACE5(( " LINK: edge %td (opos=%.2f) linked to %.2f," + " dist was %.2f, now %.2f\n", + stem_edge - hints->axis[dim].edges, + (double)stem_edge->opos / 64, (double)stem_edge->pos / 64, + (double)dist / 64, (double)fitted_width / 64 )); + } + + + /* Shift the coordinates of the `serif' edge by the same amount */ + /* as the corresponding `base' edge has been moved already. */ + + static void + af_latin_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + + serif->pos = base->pos + ( serif->opos - base->opos ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* The main grid-fitting routine. */ + + static void + af_latin_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = NULL; + FT_Int has_serifs = 0; + + AF_StyleClass style_class = hints->metrics->style_class; + AF_ScriptClass script_class = af_script_classes[style_class->script]; + + FT_Bool top_to_bottom_hinting = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "latin %s edge hinting (style `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_style_names[hints->metrics->style_class->style] )); + + if ( dim == AF_DIMENSION_VERT ) + top_to_bottom_hinting = script_class->top_to_bottom_hinting; + + /* we begin by aligning all stems relative to the blue zone */ + /* if needed -- that's only for horizontal edges */ + + if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; /* these edges form the stem to check */ + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + edge1 = NULL; + edge2 = edge->link; + + /* + * If a stem contains both a neutral and a non-neutral blue zone, + * skip the neutral one. Otherwise, outlines with different + * directions might be incorrectly aligned at the same vertical + * position. + * + * If we have two neutral blue zones, skip one of them. + * + */ + if ( edge->blue_edge && edge2 && edge2->blue_edge ) + { + FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL; + FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL; + + + if ( neutral2 ) + { + edge2->blue_edge = NULL; + edge2->flags &= ~AF_EDGE_NEUTRAL; + } + else if ( neutral ) + { + edge->blue_edge = NULL; + edge->flags &= ~AF_EDGE_NEUTRAL; + } + } + + blue = edge->blue_edge; + if ( blue ) + edge1 = edge; + + /* flip edges if the other edge is aligned to a blue zone */ + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + if ( !edge1 ) + continue; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !anchor ) + FT_TRACE5(( " BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f," + " was %.2f (anchor=edge %td)\n", + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64, edge - edges )); + else + FT_TRACE5(( " BLUE: edge %td (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64 )); + + num_actions++; +#endif + + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + + if ( edge2 && !edge2->blue_edge ) + { + af_latin_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + } + + if ( !anchor ) + anchor = edge; + } + } + + /* now we align all other stem edges, trying to maintain the */ + /* relative order of stems in the glyph */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + /* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + has_serifs++; + continue; + } + + /* now align the stem */ + + /* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( " ASSERTION FAILED for edge %td\n", edge2 - edges )); + + af_latin_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + continue; + } + + if ( !anchor ) + { + /* if we reach this if clause, no stem has been aligned yet */ + + FT_Pos org_len, org_center, cur_len; + FT_Pos cur_pos1, error1, error2, u_off, d_off; + + + org_len = edge2->opos - edge->opos; + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + /* some voodoo to specially round edges for small stem widths; */ + /* the idea is to align the center of a stem, then shifting */ + /* the stem edges to suitable positions */ + if ( cur_len <= 64 ) + { + /* width <= 1px */ + u_off = 32; + d_off = 32; + } + else + { + /* 1px < width < 1.5px */ + u_off = 38; + d_off = 26; + } + + if ( cur_len < 96 ) + { + org_center = edge->opos + ( org_len >> 1 ); + cur_pos1 = FT_PIX_ROUND( org_center ); + + error1 = org_center - ( cur_pos1 - u_off ); + if ( error1 < 0 ) + error1 = -error1; + + error2 = org_center - ( cur_pos1 + d_off ); + if ( error2 < 0 ) + error2 = -error2; + + if ( error1 < error2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = edge->pos + cur_len; + } + else + edge->pos = FT_PIX_ROUND( edge->opos ); + + anchor = edge; + edge->flags |= AF_EDGE_DONE; + + FT_TRACE5(( " ANCHOR: edge %td (opos=%.2f) and %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + + af_latin_align_linked_edge( hints, dim, edge, edge2 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions += 2; +#endif + } + else + { + FT_Pos org_pos, org_len, org_center, cur_len; + FT_Pos cur_pos1, cur_pos2, delta1, delta2; + + + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + if ( edge2->flags & AF_EDGE_DONE ) + { + FT_TRACE5(( " ADJUST: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, (double)edge->pos / 64, + (double)( edge2->pos - cur_len ) / 64 )); + + edge->pos = edge2->pos - cur_len; + } + + else if ( cur_len < 96 ) + { + FT_Pos u_off, d_off; + + + cur_pos1 = FT_PIX_ROUND( org_center ); + + if ( cur_len <= 64 ) + { + u_off = 32; + d_off = 32; + } + else + { + u_off = 38; + d_off = 26; + } + + delta1 = org_center - ( cur_pos1 - u_off ); + if ( delta1 < 0 ) + delta1 = -delta1; + + delta2 = org_center - ( cur_pos1 + d_off ); + if ( delta2 < 0 ) + delta2 = -delta2; + + if ( delta1 < delta2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = cur_pos1 + cur_len / 2; + + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + } + + else + { + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, + edge->flags, + edge2->flags ); + + cur_pos1 = FT_PIX_ROUND( org_pos ); + delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; + if ( delta1 < 0 ) + delta1 = -delta1; + + cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; + delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; + if ( delta2 < 0 ) + delta2 = -delta2; + + edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; + edge2->pos = edge->pos + cur_len; + + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + + if ( edge > edges && + ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos ) + : ( edge->pos < edge[-1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); + + num_actions++; +#endif + + edge->pos = edge[-1].pos; + } + } + } + } + + /* make sure that lowercase m's maintain their symmetry */ + + /* In general, lowercase m's have six vertical edges if they are sans */ + /* serif, or twelve if they are with serifs. This implementation is */ + /* based on that assumption, and seems to work very well with most */ + /* faces. However, if for a certain face this assumption is not */ + /* true, the m is just rendered like before. In addition, any stem */ + /* correction will only be applied to symmetrical glyphs (even if the */ + /* glyph is not an m), so the potential for unwanted distortion is */ + /* relatively low. */ + + /* We don't handle horizontal edges since we can't easily assure that */ + /* the third (lowest) stem aligns with the base line; it might end up */ + /* one pixel higher or lower. */ + + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span, delta; + + + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + + if ( span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; + + /* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + + if ( has_serifs || !anchor ) + { + /* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos delta; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + delta = 1000; + + if ( edge->serif ) + { + delta = edge->serif->opos - edge->opos; + if ( delta < 0 ) + delta = -delta; + } + + if ( delta < 64 + 16 ) + { + af_latin_align_serif_edge( hints, edge->serif, edge ); + FT_TRACE5(( " SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)" + " aligned to %.2f\n", + edge - edges, (double)edge->opos / 64, + edge->serif - edges, (double)edge->serif->opos / 64, + (double)edge->pos / 64 )); + } + else if ( !anchor ) + { + edge->pos = FT_PIX_ROUND( edge->opos ); + anchor = edge; + FT_TRACE5(( " SERIF_ANCHOR: edge %td (opos=%.2f)" + " snapped to %.2f\n", + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); + } + else + { + AF_Edge before, after; + + + for ( before = edge - 1; before >= edges; before-- ) + if ( before->flags & AF_EDGE_DONE ) + break; + + for ( after = edge + 1; after < edge_limit; after++ ) + if ( after->flags & AF_EDGE_DONE ) + break; + + if ( before >= edges && before < edge && + after < edge_limit && after > edge ) + { + if ( after->opos == before->opos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->opos - before->opos, + after->pos - before->pos, + after->opos - before->opos ); + + FT_TRACE5(( " SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f" + " from %td (opos=%.2f)\n", + edge - edges, (double)edge->opos / 64, + (double)edge->pos / 64, + before - edges, (double)before->opos / 64 )); + } + else + { + edge->pos = anchor->pos + + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); + FT_TRACE5(( " SERIF_LINK2: edge %td (opos=%.2f)" + " snapped to %.2f\n", + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + edge->flags |= AF_EDGE_DONE; + + if ( edge > edges && + ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos ) + : ( edge->pos < edge[-1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); + + num_actions++; +#endif + edge->pos = edge[-1].pos; + } + } + + if ( edge + 1 < edge_limit && + edge[1].flags & AF_EDGE_DONE && + ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos ) + : ( edge->pos > edge[1].pos ) ) ) + { + /* don't move if stem would (almost) disappear otherwise; */ + /* the ad-hoc value 16 corresponds to 1/4px */ + if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, + (double)edge->pos / 64, + (double)edge[1].pos / 64 )); + + num_actions++; +#endif + + edge->pos = edge[1].pos; + } + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + } + + + /* Apply the complete hinting algorithm to a latin glyph. */ + + static FT_Error + af_latin_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + FT_Error error; + int dim; + + AF_LatinAxis axis; + + + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; + + /* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + axis = &metrics->axis[AF_DIMENSION_HORZ]; + error = af_latin_hints_detect_features( hints, + axis->width_count, + axis->widths, + AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + } + + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + axis = &metrics->axis[AF_DIMENSION_VERT]; + error = af_latin_hints_detect_features( hints, + axis->width_count, + axis->widths, + AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + + /* apply blue zones to base characters only */ + if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) ) + af_latin_hints_compute_blue_edges( hints, metrics ); + } + + /* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_latin_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + + af_glyph_hints_save( hints, outline ); + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N S C R I P T C L A S S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_latin_writing_system_class, + + AF_WRITING_SYSTEM_LATIN, + + sizeof ( AF_LatinMetricsRec ), + + (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */ + (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */ + (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */ + + (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */ + (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply /* style_hints_apply */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/aflatin.h b/Dependencies/freetype/freetype/src/autofit/aflatin.h new file mode 100644 index 00000000..54e50615 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/aflatin.h @@ -0,0 +1,194 @@ +/**************************************************************************** + * + * aflatin.h + * + * Auto-fitter hinting routines for latin writing system + * (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFLATIN_H_ +#define AFLATIN_H_ + +#include "afhints.h" + + +FT_BEGIN_HEADER + + /* the `latin' writing system */ + + AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin_writing_system_class ) + + + /* constants are given with units_per_em == 2048 in mind */ +#define AF_LATIN_CONSTANT( metrics, c ) \ + ( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L O B A L M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* + * The following declarations could be embedded in the file `aflatin.c'; + * they have been made semi-public to allow alternate writing system + * hinters to re-use some of them. + */ + + +#define AF_LATIN_IS_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP ) +#define AF_LATIN_IS_SUB_TOP_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SUB_TOP ) +#define AF_LATIN_IS_NEUTRAL_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_NEUTRAL ) +#define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) +#define AF_LATIN_IS_LONG_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) + +#define AF_LATIN_MAX_WIDTHS 16 + + +#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ +#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript top */ + /* blue zone */ +#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have neutral blue zone */ +#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustment */ + /* optimization */ + + + typedef struct AF_LatinBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; + FT_Pos ascender; + FT_Pos descender; + FT_UInt flags; + + } AF_LatinBlueRec, *AF_LatinBlue; + + + typedef struct AF_LatinAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ + + /* ignored for horizontal metrics */ + FT_UInt blue_count; + AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; + + FT_Fixed org_scale; + FT_Pos org_delta; + + } AF_LatinAxisRec, *AF_LatinAxis; + + + typedef struct AF_LatinMetricsRec_ + { + AF_StyleMetricsRec root; + FT_UInt units_per_em; + AF_LatinAxisRec axis[AF_DIMENSION_MAX]; + + } AF_LatinMetricsRec, *AF_LatinMetrics; + + + FT_LOCAL( FT_Error ) + af_latin_metrics_init( AF_StyleMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_latin_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + FT_LOCAL( void ) + af_latin_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_latin_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H A N A L Y S I S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AF_LATIN_HINTS_HORZ_SNAP ( 1U << 0 ) /* stem width snapping */ +#define AF_LATIN_HINTS_VERT_SNAP ( 1U << 1 ) /* stem height snapping */ +#define AF_LATIN_HINTS_STEM_ADJUST ( 1U << 2 ) /* stem width/height */ + /* adjustment */ +#define AF_LATIN_HINTS_MONO ( 1U << 3 ) /* monochrome rendering */ + + +#define AF_LATIN_HINTS_DO_HORZ_SNAP( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_HORZ_SNAP ) + +#define AF_LATIN_HINTS_DO_VERT_SNAP( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_VERT_SNAP ) + +#define AF_LATIN_HINTS_DO_STEM_ADJUST( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_STEM_ADJUST ) + +#define AF_LATIN_HINTS_DO_MONO( h ) \ + AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_MONO ) + + + /* + * The next functions shouldn't normally be exported. However, other + * writing systems might like to use these functions as-is. + */ + FT_LOCAL( FT_Error ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( void ) + af_latin_hints_link_segments( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ); + + FT_LOCAL( FT_Error ) + af_latin_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ); + + FT_LOCAL( FT_Error ) + af_latin_hints_detect_features( AF_GlyphHints hints, + FT_UInt width_count, + AF_WidthRec* widths, + AF_Dimension dim ); + +/* */ + +FT_END_HEADER + +#endif /* AFLATIN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afloader.c b/Dependencies/freetype/freetype/src/autofit/afloader.c new file mode 100644 index 00000000..af1d59a6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afloader.c @@ -0,0 +1,706 @@ +/**************************************************************************** + * + * afloader.c + * + * Auto-fitter glyph loading routines (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afloader.h" +#include "afhints.h" +#include "aferrors.h" +#include "afmodule.h" + +#include + + + /* Initialize glyph loader. */ + + FT_LOCAL_DEF( void ) + af_loader_init( AF_Loader loader, + AF_GlyphHints hints ) + { + FT_ZERO( loader ); + + loader->hints = hints; + } + + + /* Reset glyph loader and compute globals if necessary. */ + + FT_LOCAL_DEF( FT_Error ) + af_loader_reset( AF_Loader loader, + AF_Module module, + FT_Face face ) + { + FT_Error error = FT_Err_Ok; + + + loader->face = face; + loader->globals = (AF_FaceGlobals)face->autohint.data; + + if ( !loader->globals ) + { + error = af_face_globals_new( face, &loader->globals, module ); + if ( !error ) + { + face->autohint.data = (FT_Pointer)loader->globals; + face->autohint.finalizer = af_face_globals_free; + } + } + + return error; + } + + + /* Finalize glyph loader. */ + + FT_LOCAL_DEF( void ) + af_loader_done( AF_Loader loader ) + { + loader->face = NULL; + loader->globals = NULL; + loader->hints = NULL; + } + + +#define af_intToFixed( i ) \ + ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) ) +#define af_fixedToInt( x ) \ + ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) +#define af_floatToFixed( f ) \ + ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) ) + + + static FT_Error + af_loader_embolden_glyph_in_slot( AF_Loader loader, + FT_Face face, + AF_StyleMetrics style_metrics ) + { + FT_Error error = FT_Err_Ok; + + FT_GlyphSlot slot = face->glyph; + AF_FaceGlobals globals = loader->globals; + AF_WritingSystemClass writing_system_class; + + FT_Size_Metrics* size_metrics = &face->size->internal->autohint_metrics; + + FT_Pos stdVW = 0; + FT_Pos stdHW = 0; + + FT_Bool size_changed = size_metrics->x_ppem != + globals->stem_darkening_for_ppem; + + FT_Fixed em_size = af_intToFixed( face->units_per_EM ); + + FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; + + + /* Skip stem darkening for broken fonts. */ + if ( !face->units_per_EM ) + { + error = FT_ERR( Corrupted_Font_Header ); + goto Exit; + } + + /* + * We depend on the writing system (script analyzers) to supply + * standard widths for the script of the glyph we are looking at. If + * it can't deliver, stem darkening is disabled. + */ + writing_system_class = + af_writing_system_classes[style_metrics->style_class->writing_system]; + + if ( writing_system_class->style_metrics_getstdw ) + writing_system_class->style_metrics_getstdw( style_metrics, + &stdHW, + &stdVW ); + else + { + error = FT_ERR( Unimplemented_Feature ); + goto Exit; + } + + if ( size_changed || + ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) + { + FT_Fixed darken_by_font_units_x, darken_x; + + + darken_by_font_units_x = + af_loader_compute_darkening( loader, + face, + stdVW ) ; + darken_x = FT_MulFix( darken_by_font_units_x, + size_metrics->x_scale ); + + globals->standard_vertical_width = stdVW; + globals->stem_darkening_for_ppem = size_metrics->x_ppem; + globals->darken_x = af_fixedToInt( darken_x ); + } + + if ( size_changed || + ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) + { + FT_Fixed darken_by_font_units_y, darken_y; + + + darken_by_font_units_y = + af_loader_compute_darkening( loader, + face, + stdHW ) ; + darken_y = FT_MulFix( darken_by_font_units_y, + size_metrics->y_scale ); + + globals->standard_horizontal_width = stdHW; + globals->stem_darkening_for_ppem = size_metrics->x_ppem; + globals->darken_y = af_fixedToInt( darken_y ); + + /* + * Scale outlines down on the Y-axis to keep them inside their blue + * zones. The stronger the emboldening, the stronger the downscaling + * (plus heuristical padding to prevent outlines still falling out + * their zones due to rounding). + * + * Reason: `FT_Outline_Embolden' works by shifting the rightmost + * points of stems farther to the right, and topmost points farther + * up. This positions points on the Y-axis outside their + * pre-computed blue zones and leads to distortion when applying the + * hints in the code further below. Code outside this emboldening + * block doesn't know we are presenting it with modified outlines the + * analyzer didn't see! + * + * An unfortunate side effect of downscaling is that the emboldening + * effect is slightly decreased. The loss becomes more pronounced + * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. + */ + globals->scale_down_factor = + FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), + em_size ); + } + + FT_Outline_EmboldenXY( &slot->outline, + globals->darken_x, + globals->darken_y ); + + scale_down_matrix.yy = globals->scale_down_factor; + FT_Outline_Transform( &slot->outline, &scale_down_matrix ); + + Exit: + return error; + } + + + /* Load the glyph at index into the current slot of a face and hint it. */ + + FT_LOCAL_DEF( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + AF_Module module, + FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + + FT_Size size = face->size; + FT_Size_Internal size_internal = size->internal; + FT_GlyphSlot slot = face->glyph; + FT_Slot_Internal slot_internal = slot->internal; + FT_GlyphLoader gloader = slot_internal->loader; + + AF_GlyphHints hints = loader->hints; + AF_ScalerRec scaler; + AF_StyleMetrics style_metrics; + FT_UInt style_options = AF_STYLE_NONE_DFLT; + AF_StyleClass style_class; + AF_WritingSystemClass writing_system_class; + + + FT_ZERO( &scaler ); + + if ( !size_internal->autohint_metrics.x_scale || + size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) ) + { + /* switching between hinting modes usually means different scaling */ + /* values; this later on enforces recomputation of everything */ + /* related to the current size */ + + size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags ); + size_internal->autohint_metrics = size->metrics; + +#ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS + { + FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics; + + + /* set metrics to integer values and adjust scaling accordingly; */ + /* this is the same setup as with TrueType fonts, cf. function */ + /* `tt_size_reset' in file `ttobjs.c' */ + size_metrics->ascender = FT_PIX_ROUND( + FT_MulFix( face->ascender, + size_metrics->y_scale ) ); + size_metrics->descender = FT_PIX_ROUND( + FT_MulFix( face->descender, + size_metrics->y_scale ) ); + size_metrics->height = FT_PIX_ROUND( + FT_MulFix( face->height, + size_metrics->y_scale ) ); + + size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, + face->units_per_EM ); + size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, + face->units_per_EM ); + size_metrics->max_advance = FT_PIX_ROUND( + FT_MulFix( face->max_advance_width, + size_metrics->x_scale ) ); + } +#endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ + } + + /* + * TODO: This code currently doesn't support fractional advance widths, + * i.e., placing hinted glyphs at anything other than integer + * x-positions. This is only relevant for the warper code, which + * scales and shifts glyphs to optimize blackness of stems (hinting on + * the x-axis by nature places things on pixel integers, hinting on the + * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta + * values of the scaler would need to be adjusted. + */ + scaler.face = face; + scaler.x_scale = size_internal->autohint_metrics.x_scale; + scaler.x_delta = 0; + scaler.y_scale = size_internal->autohint_metrics.y_scale; + scaler.y_delta = 0; + + scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); + scaler.flags = 0; + + /* note that the fallback style can't be changed anymore */ + /* after the first call of `af_loader_load_glyph' */ + error = af_loader_reset( loader, module, face ); + if ( error ) + goto Exit; + + /* + * Glyphs (really code points) are assigned to scripts. Script + * analysis is done lazily: For each glyph that passes through here, + * the corresponding script analyzer is called, but returns immediately + * if it has been run already. + */ + error = af_face_globals_get_metrics( loader->globals, glyph_index, + style_options, &style_metrics ); + if ( error ) + goto Exit; + + style_class = style_metrics->style_class; + writing_system_class = + af_writing_system_classes[style_class->writing_system]; + + loader->metrics = style_metrics; + + if ( writing_system_class->style_metrics_scale ) + writing_system_class->style_metrics_scale( style_metrics, &scaler ); + else + style_metrics->scaler = scaler; + + if ( writing_system_class->style_hints_init ) + { + error = writing_system_class->style_hints_init( hints, + style_metrics ); + if ( error ) + goto Exit; + } + + /* + * Do the main work of `af_loader_load_glyph'. Note that we never have + * to deal with composite glyphs as those get loaded into + * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. + * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies + * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. + */ + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM | + FT_LOAD_LINEAR_DESIGN; + load_flags &= ~FT_LOAD_RENDER; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + + /* + * Apply stem darkening (emboldening) here before hints are applied to + * the outline. Glyphs are scaled down proportionally to the + * emboldening so that curve points don't fall outside their + * precomputed blue zones. + * + * Any emboldening done by the font driver (e.g., the CFF driver) + * doesn't reach here because the autohinter loads the unprocessed + * glyphs in font units for analysis (functions `af_*_metrics_init_*') + * and then above to prepare it for the rasterizers by itself, + * independently of the font driver. So emboldening must be done here, + * within the autohinter. + * + * All glyphs to be autohinted pass through here one by one. The + * standard widths can therefore change from one glyph to the next, + * depending on what script a glyph is assigned to (each script has its + * own set of standard widths and other metrics). The darkening amount + * must therefore be recomputed for each size and + * `standard_{vertical,horizontal}_width' change. + * + * Ignore errors and carry on without emboldening. + * + */ + + /* stem darkening only works well in `light' mode */ + if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && + ( !face->internal->no_stem_darkening || + ( face->internal->no_stem_darkening < 0 && + !module->no_stem_darkening ) ) ) + af_loader_embolden_glyph_in_slot( loader, face, style_metrics ); + + loader->transformed = slot_internal->glyph_transformed; + if ( loader->transformed ) + { + FT_Matrix inverse; + + + loader->trans_matrix = slot_internal->glyph_matrix; + loader->trans_delta = slot_internal->glyph_delta; + + inverse = loader->trans_matrix; + if ( !FT_Matrix_Invert( &inverse ) ) + FT_Vector_Transform( &loader->trans_delta, &inverse ); + } + + switch ( slot->format ) + { + case FT_GLYPH_FORMAT_OUTLINE: + /* translate the loaded glyph when an internal transform is needed */ + if ( loader->transformed ) + FT_Outline_Translate( &slot->outline, + loader->trans_delta.x, + loader->trans_delta.y ); + + /* compute original horizontal phantom points */ + /* (and ignore vertical ones) */ + loader->pp1.x = hints->x_delta; + loader->pp1.y = hints->y_delta; + loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, + hints->x_scale ) + hints->x_delta; + loader->pp2.y = hints->y_delta; + + /* be sure to check for spacing glyphs */ + if ( slot->outline.n_points == 0 ) + goto Hint_Metrics; + + /* now load the slot image into the auto-outline */ + /* and run the automatic hinting process */ + if ( writing_system_class->style_hints_apply ) + { + error = writing_system_class->style_hints_apply( + glyph_index, + hints, + &gloader->base.outline, + style_metrics ); + if ( error ) + goto Exit; + } + + /* we now need to adjust the metrics according to the change in */ + /* width/positioning that occurred during the hinting process */ + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; + + + if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) + { + AF_Edge edge1 = axis->edges; /* leftmost edge */ + AF_Edge edge2 = edge1 + + axis->num_edges - 1; /* rightmost edge */ + + FT_Pos old_rsb = loader->pp2.x - edge2->opos; + /* loader->pp1.x is always zero at this point of time */ + FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */ + FT_Pos new_lsb = edge1->pos; + + /* remember unhinted values to later account */ + /* for rounding errors */ + FT_Pos pp1x_uh = new_lsb - old_lsb; + FT_Pos pp2x_uh = edge2->pos + old_rsb; + + + /* prefer too much space over too little space */ + /* for very small sizes */ + + if ( old_lsb < 24 ) + pp1x_uh -= 8; + + if ( old_rsb < 24 ) + pp2x_uh += 8; + + loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); + loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); + + if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) + loader->pp1.x -= 64; + + if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) + loader->pp2.x += 64; + + slot->lsb_delta = loader->pp1.x - pp1x_uh; + slot->rsb_delta = loader->pp2.x - pp2x_uh; + } + else + { + FT_Pos pp1x = loader->pp1.x; + FT_Pos pp2x = loader->pp2.x; + + + loader->pp1.x = FT_PIX_ROUND( pp1x ); + loader->pp2.x = FT_PIX_ROUND( pp2x ); + + slot->lsb_delta = loader->pp1.x - pp1x; + slot->rsb_delta = loader->pp2.x - pp2x; + } + } + /* `light' mode uses integer advance widths */ + /* but sets `lsb_delta' and `rsb_delta' */ + else + { + FT_Pos pp1x = loader->pp1.x; + FT_Pos pp2x = loader->pp2.x; + + + loader->pp1.x = FT_PIX_ROUND( pp1x ); + loader->pp2.x = FT_PIX_ROUND( pp2x ); + + slot->lsb_delta = loader->pp1.x - pp1x; + slot->rsb_delta = loader->pp2.x - pp2x; + } + + break; + + default: + /* we don't support other formats (yet?) */ + error = FT_THROW( Unimplemented_Feature ); + } + + Hint_Metrics: + { + FT_BBox bbox; + FT_Vector vvector; + + + vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; + vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; + vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale ); + vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale ); + + /* transform the hinted outline if needed */ + if ( loader->transformed ) + { + FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); + FT_Vector_Transform( &vvector, &loader->trans_matrix ); + } + + /* we must translate our final outline by -pp1.x and compute */ + /* the new metrics */ + if ( loader->pp1.x ) + FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); + + FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); + + bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); + bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); + bbox.xMax = FT_PIX_CEIL( bbox.xMax ); + bbox.yMax = FT_PIX_CEIL( bbox.yMax ); + + slot->metrics.width = bbox.xMax - bbox.xMin; + slot->metrics.height = bbox.yMax - bbox.yMin; + slot->metrics.horiBearingX = bbox.xMin; + slot->metrics.horiBearingY = bbox.yMax; + + slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); + slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); + + /* for mono-width fonts (like Andale, Courier, etc.) we need */ + /* to keep the original rounded advance width; ditto for */ + /* digits if all have the same advance width */ + if ( scaler.render_mode != FT_RENDER_MODE_LIGHT && + ( FT_IS_FIXED_WIDTH( slot->face ) || + ( af_face_globals_is_digit( loader->globals, glyph_index ) && + style_metrics->digits_have_same_width ) ) ) + { + slot->metrics.horiAdvance = + FT_MulFix( slot->metrics.horiAdvance, + style_metrics->scaler.x_scale ); + + /* Set delta values to 0. Otherwise code that uses them is */ + /* going to ruin the fixed advance width. */ + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + else + { + /* non-spacing glyphs must stay as-is */ + if ( slot->metrics.horiAdvance ) + slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + } + + slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, + style_metrics->scaler.y_scale ); + + slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); + slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); + + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + + Exit: + return error; + } + + + /* + * Compute amount of font units the face should be emboldened by, in + * analogy to the CFF driver's `cf2_computeDarkening' function. See there + * for details of the algorithm. + * + * XXX: Currently a crude adaption of the original algorithm. Do better? + */ + FT_LOCAL_DEF( FT_Fixed ) + af_loader_compute_darkening( AF_Loader loader, + FT_Face face, + FT_Pos standard_width ) + { + AF_Module module = loader->globals->module; + + FT_UShort units_per_EM; + FT_Fixed ppem, em_ratio; + FT_Fixed stem_width, stem_width_per_1000, scaled_stem, darken_amount; + FT_Int log_base_2; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + + + ppem = FT_MAX( af_intToFixed( 4 ), + af_intToFixed( face->size->metrics.x_ppem ) ); + units_per_EM = face->units_per_EM; + + em_ratio = FT_DivFix( af_intToFixed( 1000 ), + af_intToFixed ( units_per_EM ) ); + if ( em_ratio < af_floatToFixed( .01 ) ) + { + /* If something goes wrong, don't embolden. */ + return 0; + } + + x1 = module->darken_params[0]; + y1 = module->darken_params[1]; + x2 = module->darken_params[2]; + y2 = module->darken_params[3]; + x3 = module->darken_params[4]; + y3 = module->darken_params[5]; + x4 = module->darken_params[6]; + y4 = module->darken_params[7]; + + if ( standard_width <= 0 ) + { + stem_width = af_intToFixed( 75 ); /* taken from cf2font.c */ + stem_width_per_1000 = stem_width; + } + else + { + stem_width = af_intToFixed( standard_width ); + stem_width_per_1000 = FT_MulFix( stem_width, em_ratio ); + } + + log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) + + FT_MSB( (FT_UInt32)ppem ); + + if ( log_base_2 >= 46 ) + { + /* possible overflow */ + scaled_stem = af_intToFixed( x4 ); + } + else + scaled_stem = FT_MulFix( stem_width_per_1000, ppem ); + + /* now apply the darkening parameters */ + if ( scaled_stem < af_intToFixed( x1 ) ) + darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem ); + + else if ( scaled_stem < af_intToFixed( x2 ) ) + { + FT_Int xdelta = x2 - x1; + FT_Int ydelta = y2 - y1; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x1 ), ppem ); + + + if ( !xdelta ) + goto Try_x3; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y1 ), ppem ); + } + + else if ( scaled_stem < af_intToFixed( x3 ) ) + { + Try_x3: + { + FT_Int xdelta = x3 - x2; + FT_Int ydelta = y3 - y2; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x2 ), ppem ); + + + if ( !xdelta ) + goto Try_x4; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y2 ), ppem ); + } + } + + else if ( scaled_stem < af_intToFixed( x4 ) ) + { + Try_x4: + { + FT_Int xdelta = x4 - x3; + FT_Int ydelta = y4 - y3; + FT_Int x = stem_width_per_1000 - + FT_DivFix( af_intToFixed( x3 ), ppem ); + + + if ( !xdelta ) + goto Use_y4; + + darken_amount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( af_intToFixed( y3 ), ppem ); + } + } + + else + { + Use_y4: + darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem ); + } + + /* Convert darken_amount from per 1000 em to true character space. */ + return FT_DivFix( darken_amount, em_ratio ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afloader.h b/Dependencies/freetype/freetype/src/autofit/afloader.h new file mode 100644 index 00000000..99f0e15f --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afloader.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * afloader.h + * + * Auto-fitter glyph loading routines (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFLOADER_H_ +#define AFLOADER_H_ + +#include "afhints.h" +#include "afmodule.h" +#include "afglobal.h" + + +FT_BEGIN_HEADER + + /* + * The autofitter module's (global) data structure to communicate with + * actual fonts. If necessary, `local' data like the current face, the + * current face's auto-hint data, or the current glyph's parameters + * relevant to auto-hinting are `swapped in'. Cf. functions like + * `af_loader_reset' and `af_loader_load_g'. + */ + + typedef struct AF_LoaderRec_ + { + /* current face data */ + FT_Face face; + AF_FaceGlobals globals; + + /* current glyph data */ + AF_GlyphHints hints; + AF_StyleMetrics metrics; + FT_Bool transformed; + FT_Matrix trans_matrix; + FT_Vector trans_delta; + FT_Vector pp1; + FT_Vector pp2; + /* we don't handle vertical phantom points */ + + } AF_LoaderRec, *AF_Loader; + + + FT_LOCAL( void ) + af_loader_init( AF_Loader loader, + AF_GlyphHints hints ); + + + FT_LOCAL( FT_Error ) + af_loader_reset( AF_Loader loader, + AF_Module module, + FT_Face face ); + + + FT_LOCAL( void ) + af_loader_done( AF_Loader loader ); + + + FT_LOCAL( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + AF_Module module, + FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags ); + + FT_LOCAL( FT_Fixed ) + af_loader_compute_darkening( AF_Loader loader, + FT_Face face, + FT_Pos standard_width ); + +/* */ + + +FT_END_HEADER + +#endif /* AFLOADER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afmodule.c b/Dependencies/freetype/freetype/src/autofit/afmodule.c new file mode 100644 index 00000000..726f6ca2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afmodule.c @@ -0,0 +1,527 @@ +/**************************************************************************** + * + * afmodule.c + * + * Auto-fitter module implementation (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afglobal.h" +#include "afmodule.h" +#include "afloader.h" +#include "aferrors.h" + +#ifdef FT_DEBUG_AUTOFIT + +#ifndef FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef __cplusplus + extern "C" { +#endif + extern void + af_glyph_hints_dump_segments( AF_GlyphHints hints, + FT_Bool to_stdout ); + extern void + af_glyph_hints_dump_points( AF_GlyphHints hints, + FT_Bool to_stdout ); + extern void + af_glyph_hints_dump_edges( AF_GlyphHints hints, + FT_Bool to_stdout ); +#ifdef __cplusplus + } +#endif + +#endif + + int af_debug_disable_horz_hints_; + int af_debug_disable_vert_hints_; + int af_debug_disable_blue_hints_; + + /* we use a global object instead of a local one for debugging */ + static AF_GlyphHintsRec af_debug_hints_rec_[1]; + + void* af_debug_hints_ = af_debug_hints_rec_; +#endif + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afmodule + + + static FT_Error + af_property_get_face_globals( FT_Face face, + AF_FaceGlobals* aglobals, + AF_Module module ) + { + FT_Error error = FT_Err_Ok; + AF_FaceGlobals globals; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + globals = (AF_FaceGlobals)face->autohint.data; + if ( !globals ) + { + /* trigger computation of the global style data */ + /* in case it hasn't been done yet */ + error = af_face_globals_new( face, &globals, module ); + if ( !error ) + { + face->autohint.data = (FT_Pointer)globals; + face->autohint.finalizer = af_face_globals_free; + } + } + + if ( !error ) + *aglobals = globals; + + return error; + } + + + static FT_Error + af_property_set( FT_Module ft_module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + AF_Module module = (AF_Module)ft_module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + AF_Script* fallback_script; + FT_UInt ss; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + fallback_script = (AF_Script*)value; + + /* We translate the fallback script to a fallback style that uses */ + /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ + /* coverage value. */ + for ( ss = 0; af_style_classes[ss]; ss++ ) + { + AF_StyleClass style_class = af_style_classes[ss]; + + + if ( style_class->script == *fallback_script && + style_class->coverage == AF_COVERAGE_DEFAULT ) + { + module->fallback_style = ss; + break; + } + } + + if ( !af_style_classes[ss] ) + { + FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n", + *fallback_script, property_name )); + return FT_THROW( Invalid_Argument ); + } + + return error; + } + else if ( !ft_strcmp( property_name, "default-script" ) ) + { + AF_Script* default_script; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + default_script = (AF_Script*)value; + + module->default_script = *default_script; + + return error; + } + else if ( !ft_strcmp( property_name, "increase-x-height" ) ) + { + FT_Prop_IncreaseXHeight* prop; + AF_FaceGlobals globals; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + return FT_THROW( Invalid_Argument ); +#endif + + prop = (FT_Prop_IncreaseXHeight*)value; + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + globals->increase_x_height = prop->limit; + + return error; + } + else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_Int dp[8]; + + + if ( value_is_string ) + { + const char* s = (const char*)value; + char* ep; + int i; + + + /* eight comma-separated numbers */ + for ( i = 0; i < 7; i++ ) + { + dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( *ep != ',' || s == ep ) + return FT_THROW( Invalid_Argument ); + + s = ep + 1; + } + + dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) + return FT_THROW( Invalid_Argument ); + + darken_params = dp; + } + else +#endif + darken_params = (FT_Int*)value; + + x1 = darken_params[0]; + y1 = darken_params[1]; + x2 = darken_params[2]; + y2 = darken_params[3]; + x3 = darken_params[4]; + y3 = darken_params[5]; + x4 = darken_params[6]; + y4 = darken_params[7]; + + if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || + y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || + x1 > x2 || x2 > x3 || x3 > x4 || + y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) + return FT_THROW( Invalid_Argument ); + + module->darken_params[0] = x1; + module->darken_params[1] = y1; + module->darken_params[2] = x2; + module->darken_params[3] = y2; + module->darken_params[4] = x3; + module->darken_params[5] = y3; + module->darken_params[6] = x4; + module->darken_params[7] = y4; + + return error; + } + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long nsd = ft_strtol( s, NULL, 10 ); + + + if ( !nsd ) + module->no_stem_darkening = FALSE; + else + module->no_stem_darkening = TRUE; + } + else +#endif + { + FT_Bool* no_stem_darkening = (FT_Bool*)value; + + + module->no_stem_darkening = *no_stem_darkening; + } + + return error; + } + + FT_TRACE2(( "af_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + static FT_Error + af_property_get( FT_Module ft_module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + AF_Module module = (AF_Module)ft_module; + + + if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) + { + FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; + AF_FaceGlobals globals; + + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + prop->map = globals->glyph_styles; + + return error; + } + else if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + AF_Script* val = (AF_Script*)value; + + AF_StyleClass style_class = af_style_classes[module->fallback_style]; + + + *val = style_class->script; + + return error; + } + else if ( !ft_strcmp( property_name, "default-script" ) ) + { + AF_Script* val = (AF_Script*)value; + + + *val = module->default_script; + + return error; + } + else if ( !ft_strcmp( property_name, "increase-x-height" ) ) + { + FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; + AF_FaceGlobals globals; + + + error = af_property_get_face_globals( prop->face, &globals, module ); + if ( !error ) + prop->limit = globals->increase_x_height; + + return error; + } + else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params = module->darken_params; + FT_Int* val = (FT_Int*)value; + + + val[0] = darken_params[0]; + val[1] = darken_params[1]; + val[2] = darken_params[2]; + val[3] = darken_params[3]; + val[4] = darken_params[4]; + val[5] = darken_params[5]; + val[6] = darken_params[6]; + val[7] = darken_params[7]; + + return error; + } + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { + FT_Bool no_stem_darkening = module->no_stem_darkening; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_stem_darkening; + + return error; + } + + FT_TRACE2(( "af_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + af_service_properties, + + af_property_set, /* FT_Properties_SetFunc set_property */ + af_property_get /* FT_Properties_GetFunc get_property */ + ) + + + FT_DEFINE_SERVICEDESCREC1( + af_services, + + FT_SERVICE_ID_PROPERTIES, &af_service_properties ) + + + FT_CALLBACK_DEF( FT_Module_Interface ) + af_get_interface( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( af_services, module_interface ); + } + + + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_init( FT_Module ft_module ) /* AF_Module */ + { + AF_Module module = (AF_Module)ft_module; + + + module->fallback_style = AF_STYLE_FALLBACK; + module->default_script = AF_SCRIPT_DEFAULT; + module->no_stem_darkening = TRUE; + + module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + af_autofitter_done( FT_Module ft_module ) /* AF_Module */ + { + FT_UNUSED( ft_module ); + +#ifdef FT_DEBUG_AUTOFIT + if ( af_debug_hints_rec_->memory ) + af_glyph_hints_done( af_debug_hints_rec_ ); +#endif + } + + + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_load_glyph( FT_AutoHinter module_, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + AF_Module module = (AF_Module)module_; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = module->root.memory; + +#ifdef FT_DEBUG_AUTOFIT + + /* in debug mode, we use a global object that survives this routine */ + + AF_GlyphHints hints = af_debug_hints_rec_; + AF_LoaderRec loader[1]; + + FT_UNUSED( size ); + + + if ( hints->memory ) + af_glyph_hints_done( hints ); + + af_glyph_hints_init( hints, memory ); + af_loader_init( loader, hints ); + + error = af_loader_load_glyph( loader, module, slot->face, + glyph_index, load_flags ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] ) + { +#endif + af_glyph_hints_dump_points( hints, 0 ); + af_glyph_hints_dump_segments( hints, 0 ); + af_glyph_hints_dump_edges( hints, 0 ); +#ifdef FT_DEBUG_LEVEL_TRACE + } +#endif + + af_loader_done( loader ); + + return error; + +#else /* !FT_DEBUG_AUTOFIT */ + + AF_GlyphHintsRec hints[1]; + AF_LoaderRec loader[1]; + + FT_UNUSED( size ); + + + af_glyph_hints_init( hints, memory ); + af_loader_init( loader, hints ); + + error = af_loader_load_glyph( loader, module, slot->face, + glyph_index, load_flags ); + + af_loader_done( loader ); + af_glyph_hints_done( hints ); + + return error; + +#endif /* !FT_DEBUG_AUTOFIT */ + } + + + FT_DEFINE_AUTOHINTER_INTERFACE( + af_autofitter_interface, + + NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */ + NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */ + NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */ + af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */ + ) + + FT_DEFINE_MODULE( + autofit_module_class, + + FT_MODULE_HINTER, + sizeof ( AF_ModuleRec ), + + "autofitter", + 0x10000L, /* version 1.0 of the autofitter */ + 0x20000L, /* requires FreeType 2.0 or above */ + + (const void*)&af_autofitter_interface, + + af_autofitter_init, /* FT_Module_Constructor module_init */ + af_autofitter_done, /* FT_Module_Destructor module_done */ + af_get_interface /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afmodule.h b/Dependencies/freetype/freetype/src/autofit/afmodule.h new file mode 100644 index 00000000..91a1abfe --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afmodule.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * + * afmodule.h + * + * Auto-fitter module implementation (specification). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFMODULE_H_ +#define AFMODULE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + + /* + * This is the `extended' FT_Module structure that holds the + * autofitter's global data. + */ + + typedef struct AF_ModuleRec_ + { + FT_ModuleRec root; + + FT_UInt fallback_style; + AF_Script default_script; + FT_Bool no_stem_darkening; + FT_Int darken_params[8]; + + } AF_ModuleRec, *AF_Module; + + +FT_DECLARE_AUTOHINTER_INTERFACE( af_autofitter_interface ) +FT_DECLARE_MODULE( autofit_module_class ) + + +FT_END_HEADER + +#endif /* AFMODULE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afranges.c b/Dependencies/freetype/freetype/src/autofit/afranges.c new file mode 100644 index 00000000..007b4328 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afranges.c @@ -0,0 +1,1072 @@ +/**************************************************************************** + * + * afranges.c + * + * Auto-fitter Unicode script ranges (body). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "afranges.h" + + /* + * The algorithm for assigning properties and styles to the `glyph_styles' + * array is as follows (cf. the implementation in + * `af_face_globals_compute_style_coverage'). + * + * Walk over all scripts (as listed in `afscript.h'). + * + * For a given script, walk over all styles (as listed in `afstyles.h'). + * The order of styles is important and should be as follows. + * + * - First come styles based on OpenType features (small caps, for + * example). Since features rely on glyph indices, thus completely + * bypassing character codes, no properties are assigned. + * + * - Next comes the default style, using the character ranges as defined + * below. This also assigns properties. + * + * Note that there also exist fallback scripts, mainly covering + * superscript and subscript glyphs of a script that are not present as + * OpenType features. Fallback scripts are defined below, also + * assigning properties; they are applied after the corresponding + * script. + * + */ + + + /* XXX Check base character ranges again: */ + /* Right now, they are quickly derived by visual inspection. */ + /* I can imagine that fine-tuning is necessary. */ + + /* for the auto-hinter, a `non-base character' is something that should */ + /* not be affected by blue zones, regardless of whether this is a */ + /* spacing or no-spacing glyph */ + + /* the `af_xxxx_nonbase_uniranges' ranges must be strict subsets */ + /* of the corresponding `af_xxxx_uniranges' ranges */ + + + const AF_Script_UniRangeRec af_adlm_uniranges[] = + { + AF_UNIRANGE_REC( 0x1E900, 0x1E95F ), /* Adlam */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_adlm_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1D944, 0x1E94A ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_arab_uniranges[] = + { + AF_UNIRANGE_REC( 0x0600, 0x06FF ), /* Arabic */ + AF_UNIRANGE_REC( 0x0750, 0x07FF ), /* Arabic Supplement */ + AF_UNIRANGE_REC( 0x08A0, 0x08FF ), /* Arabic Extended-A */ + AF_UNIRANGE_REC( 0xFB50, 0xFDFF ), /* Arabic Presentation Forms-A */ + AF_UNIRANGE_REC( 0xFE70, 0xFEFF ), /* Arabic Presentation Forms-B */ + AF_UNIRANGE_REC( 0x1EE00, 0x1EEFF ), /* Arabic Mathematical Alphabetic Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_arab_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0600, 0x0605 ), + AF_UNIRANGE_REC( 0x0610, 0x061A ), + AF_UNIRANGE_REC( 0x064B, 0x065F ), + AF_UNIRANGE_REC( 0x0670, 0x0670 ), + AF_UNIRANGE_REC( 0x06D6, 0x06DC ), + AF_UNIRANGE_REC( 0x06DF, 0x06E4 ), + AF_UNIRANGE_REC( 0x06E7, 0x06E8 ), + AF_UNIRANGE_REC( 0x06EA, 0x06ED ), + AF_UNIRANGE_REC( 0x08D4, 0x08E1 ), + AF_UNIRANGE_REC( 0x08D3, 0x08FF ), + AF_UNIRANGE_REC( 0xFBB2, 0xFBC1 ), + AF_UNIRANGE_REC( 0xFE70, 0xFE70 ), + AF_UNIRANGE_REC( 0xFE72, 0xFE72 ), + AF_UNIRANGE_REC( 0xFE74, 0xFE74 ), + AF_UNIRANGE_REC( 0xFE76, 0xFE76 ), + AF_UNIRANGE_REC( 0xFE78, 0xFE78 ), + AF_UNIRANGE_REC( 0xFE7A, 0xFE7A ), + AF_UNIRANGE_REC( 0xFE7C, 0xFE7C ), + AF_UNIRANGE_REC( 0xFE7E, 0xFE7E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_armn_uniranges[] = + { + AF_UNIRANGE_REC( 0x0530, 0x058F ), /* Armenian */ + AF_UNIRANGE_REC( 0xFB13, 0xFB17 ), /* Alphab. Present. Forms (Armenian) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_armn_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0559, 0x055F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_avst_uniranges[] = + { + AF_UNIRANGE_REC( 0x10B00, 0x10B3F ), /* Avestan */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_avst_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x10B39, 0x10B3F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_bamu_uniranges[] = + { + AF_UNIRANGE_REC( 0xA6A0, 0xA6FF ), /* Bamum */ +#if 0 + /* The characters in the Bamum supplement are pictograms, */ + /* not (directly) related to the syllabic Bamum script */ + AF_UNIRANGE_REC( 0x16800, 0x16A3F ), /* Bamum Supplement */ +#endif + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_bamu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA6F0, 0xA6F1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_beng_uniranges[] = + { + AF_UNIRANGE_REC( 0x0980, 0x09FF ), /* Bengali */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_beng_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0981, 0x0981 ), + AF_UNIRANGE_REC( 0x09BC, 0x09BC ), + AF_UNIRANGE_REC( 0x09C1, 0x09C4 ), + AF_UNIRANGE_REC( 0x09CD, 0x09CD ), + AF_UNIRANGE_REC( 0x09E2, 0x09E3 ), + AF_UNIRANGE_REC( 0x09FE, 0x09FE ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_buhd_uniranges[] = + { + AF_UNIRANGE_REC( 0x1740, 0x175F ), /* Buhid */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_buhd_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1752, 0x1753 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cakm_uniranges[] = + { + AF_UNIRANGE_REC( 0x11100, 0x1114F ), /* Chakma */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cakm_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x11100, 0x11102 ), + AF_UNIRANGE_REC( 0x11127, 0x11134 ), + AF_UNIRANGE_REC( 0x11146, 0x11146 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cans_uniranges[] = + { + AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ + AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cans_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cari_uniranges[] = + { + AF_UNIRANGE_REC( 0x102A0, 0x102DF ), /* Carian */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cari_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cher_uniranges[] = + { + AF_UNIRANGE_REC( 0x13A0, 0x13FF ), /* Cherokee */ + AF_UNIRANGE_REC( 0xAB70, 0xABBF ), /* Cherokee Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cher_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_copt_uniranges[] = + { + AF_UNIRANGE_REC( 0x2C80, 0x2CFF ), /* Coptic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_copt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x2CEF, 0x2CF1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cprt_uniranges[] = + { + AF_UNIRANGE_REC( 0x10800, 0x1083F ), /* Cypriot */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cprt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_cyrl_uniranges[] = + { + AF_UNIRANGE_REC( 0x0400, 0x04FF ), /* Cyrillic */ + AF_UNIRANGE_REC( 0x0500, 0x052F ), /* Cyrillic Supplement */ + AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), /* Cyrillic Extended-A */ + AF_UNIRANGE_REC( 0xA640, 0xA69F ), /* Cyrillic Extended-B */ + AF_UNIRANGE_REC( 0x1C80, 0x1C8F ), /* Cyrillic Extended-C */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_cyrl_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0483, 0x0489 ), + AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), + AF_UNIRANGE_REC( 0xA66F, 0xA67F ), + AF_UNIRANGE_REC( 0xA69E, 0xA69F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + /* There are some characters in the Devanagari Unicode block that are */ + /* generic to Indic scripts; we omit them so that their presence doesn't */ + /* trigger Devanagari. */ + + const AF_Script_UniRangeRec af_deva_uniranges[] = + { + AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ + /* omitting U+093C nukta */ + AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ + /* omitting U+0951 udatta, U+0952 anudatta */ + AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ + /* omitting U+0964 danda, U+0965 double danda */ + AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ + AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ + AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_deva_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0900, 0x0902 ), + AF_UNIRANGE_REC( 0x093A, 0x093A ), + AF_UNIRANGE_REC( 0x0941, 0x0948 ), + AF_UNIRANGE_REC( 0x094D, 0x094D ), + AF_UNIRANGE_REC( 0x0953, 0x0957 ), + AF_UNIRANGE_REC( 0x0962, 0x0963 ), + AF_UNIRANGE_REC( 0xA8E0, 0xA8F1 ), + AF_UNIRANGE_REC( 0xA8FF, 0xA8FF ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_dsrt_uniranges[] = + { + AF_UNIRANGE_REC( 0x10400, 0x1044F ), /* Deseret */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_dsrt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_ethi_uniranges[] = + { + AF_UNIRANGE_REC( 0x1200, 0x137F ), /* Ethiopic */ + AF_UNIRANGE_REC( 0x1380, 0x139F ), /* Ethiopic Supplement */ + AF_UNIRANGE_REC( 0x2D80, 0x2DDF ), /* Ethiopic Extended */ + AF_UNIRANGE_REC( 0xAB00, 0xAB2F ), /* Ethiopic Extended-A */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_ethi_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x135D, 0x135F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_geor_uniranges[] = + { + AF_UNIRANGE_REC( 0x10D0, 0x10FF ), /* Georgian (Mkhedruli) */ + AF_UNIRANGE_REC( 0x1C90, 0x1CBF ), /* Georgian Extended (Mtavruli) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_geor_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_geok_uniranges[] = + { + /* Khutsuri */ + AF_UNIRANGE_REC( 0x10A0, 0x10CD ), /* Georgian (Asomtavruli) */ + AF_UNIRANGE_REC( 0x2D00, 0x2D2D ), /* Georgian Supplement (Nuskhuri) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_geok_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_glag_uniranges[] = + { + AF_UNIRANGE_REC( 0x2C00, 0x2C5F ), /* Glagolitic */ + AF_UNIRANGE_REC( 0x1E000, 0x1E02F ), /* Glagolitic Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_glag_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1E000, 0x1E02F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_goth_uniranges[] = + { + AF_UNIRANGE_REC( 0x10330, 0x1034F ), /* Gothic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_goth_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_grek_uniranges[] = + { + AF_UNIRANGE_REC( 0x0370, 0x03FF ), /* Greek and Coptic */ + AF_UNIRANGE_REC( 0x1F00, 0x1FFF ), /* Greek Extended */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_grek_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x037A, 0x037A ), + AF_UNIRANGE_REC( 0x0384, 0x0385 ), + AF_UNIRANGE_REC( 0x1FBD, 0x1FC1 ), + AF_UNIRANGE_REC( 0x1FCD, 0x1FCF ), + AF_UNIRANGE_REC( 0x1FDD, 0x1FDF ), + AF_UNIRANGE_REC( 0x1FED, 0x1FEF ), + AF_UNIRANGE_REC( 0x1FFD, 0x1FFE ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_gujr_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A80, 0x0AFF ), /* Gujarati */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_gujr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A81, 0x0A82 ), + AF_UNIRANGE_REC( 0x0ABC, 0x0ABC ), + AF_UNIRANGE_REC( 0x0AC1, 0x0AC8 ), + AF_UNIRANGE_REC( 0x0ACD, 0x0ACD ), + AF_UNIRANGE_REC( 0x0AE2, 0x0AE3 ), + AF_UNIRANGE_REC( 0x0AFA, 0x0AFF ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_guru_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A00, 0x0A7F ), /* Gurmukhi */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_guru_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0A01, 0x0A02 ), + AF_UNIRANGE_REC( 0x0A3C, 0x0A3C ), + AF_UNIRANGE_REC( 0x0A41, 0x0A51 ), + AF_UNIRANGE_REC( 0x0A70, 0x0A71 ), + AF_UNIRANGE_REC( 0x0A75, 0x0A75 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_hebr_uniranges[] = + { + AF_UNIRANGE_REC( 0x0590, 0x05FF ), /* Hebrew */ + AF_UNIRANGE_REC( 0xFB1D, 0xFB4F ), /* Alphab. Present. Forms (Hebrew) */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_hebr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0591, 0x05BF ), + AF_UNIRANGE_REC( 0x05C1, 0x05C2 ), + AF_UNIRANGE_REC( 0x05C4, 0x05C5 ), + AF_UNIRANGE_REC( 0x05C7, 0x05C7 ), + AF_UNIRANGE_REC( 0xFB1E, 0xFB1E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_kali_uniranges[] = + { + AF_UNIRANGE_REC( 0xA900, 0xA92F ), /* Kayah Li */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_kali_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA926, 0xA92D ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_knda_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C80, 0x0CFF ), /* Kannada */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_knda_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C81, 0x0C81 ), + AF_UNIRANGE_REC( 0x0CBC, 0x0CBC ), + AF_UNIRANGE_REC( 0x0CBF, 0x0CBF ), + AF_UNIRANGE_REC( 0x0CC6, 0x0CC6 ), + AF_UNIRANGE_REC( 0x0CCC, 0x0CCD ), + AF_UNIRANGE_REC( 0x0CE2, 0x0CE3 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_khmr_uniranges[] = + { + AF_UNIRANGE_REC( 0x1780, 0x17FF ), /* Khmer */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_khmr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x17B7, 0x17BD ), + AF_UNIRANGE_REC( 0x17C6, 0x17C6 ), + AF_UNIRANGE_REC( 0x17C9, 0x17D3 ), + AF_UNIRANGE_REC( 0x17DD, 0x17DD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_khms_uniranges[] = + { + AF_UNIRANGE_REC( 0x19E0, 0x19FF ), /* Khmer Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_khms_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_lao_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E80, 0x0EFF ), /* Lao */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_lao_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0EB1, 0x0EB1 ), + AF_UNIRANGE_REC( 0x0EB4, 0x0EBC ), + AF_UNIRANGE_REC( 0x0EC8, 0x0ECD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latn_uniranges[] = + { + AF_UNIRANGE_REC( 0x0020, 0x007F ), /* Basic Latin (no control chars) */ + AF_UNIRANGE_REC( 0x00A0, 0x00A9 ), /* Latin-1 Supplement (no control chars) */ + AF_UNIRANGE_REC( 0x00AB, 0x00B1 ), /* ... continued */ + AF_UNIRANGE_REC( 0x00B4, 0x00B8 ), /* ... continued */ + AF_UNIRANGE_REC( 0x00BB, 0x00FF ), /* ... continued */ + AF_UNIRANGE_REC( 0x0100, 0x017F ), /* Latin Extended-A */ + AF_UNIRANGE_REC( 0x0180, 0x024F ), /* Latin Extended-B */ + AF_UNIRANGE_REC( 0x0250, 0x02AF ), /* IPA Extensions */ + AF_UNIRANGE_REC( 0x02B9, 0x02DF ), /* Spacing Modifier Letters */ + AF_UNIRANGE_REC( 0x02E5, 0x02FF ), /* ... continued */ + AF_UNIRANGE_REC( 0x0300, 0x036F ), /* Combining Diacritical Marks */ + AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), /* Combining Diacritical Marks Extended */ + AF_UNIRANGE_REC( 0x1D00, 0x1D2B ), /* Phonetic Extensions */ + AF_UNIRANGE_REC( 0x1D6B, 0x1D77 ), /* ... continued */ + AF_UNIRANGE_REC( 0x1D79, 0x1D7F ), /* ... continued */ + AF_UNIRANGE_REC( 0x1D80, 0x1D9A ), /* Phonetic Extensions Supplement */ + AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), /* Combining Diacritical Marks Supplement */ + AF_UNIRANGE_REC( 0x1E00, 0x1EFF ), /* Latin Extended Additional */ + AF_UNIRANGE_REC( 0x2000, 0x206F ), /* General Punctuation */ + AF_UNIRANGE_REC( 0x20A0, 0x20B8 ), /* Currency Symbols ... */ + AF_UNIRANGE_REC( 0x20BA, 0x20CF ), /* ... except new Rupee sign */ + AF_UNIRANGE_REC( 0x2150, 0x218F ), /* Number Forms */ + AF_UNIRANGE_REC( 0x2C60, 0x2C7B ), /* Latin Extended-C */ + AF_UNIRANGE_REC( 0x2C7E, 0x2C7F ), /* ... continued */ + AF_UNIRANGE_REC( 0x2E00, 0x2E7F ), /* Supplemental Punctuation */ + AF_UNIRANGE_REC( 0xA720, 0xA76F ), /* Latin Extended-D */ + AF_UNIRANGE_REC( 0xA771, 0xA7F7 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA7FA, 0xA7FF ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB30, 0xAB5B ), /* Latin Extended-E */ + AF_UNIRANGE_REC( 0xAB60, 0xAB6F ), /* ... continued */ + AF_UNIRANGE_REC( 0xFB00, 0xFB06 ), /* Alphab. Present. Forms (Latin Ligs) */ + AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ), /* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latn_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x005E, 0x0060 ), + AF_UNIRANGE_REC( 0x007E, 0x007E ), + AF_UNIRANGE_REC( 0x00A8, 0x00A9 ), + AF_UNIRANGE_REC( 0x00AE, 0x00B0 ), + AF_UNIRANGE_REC( 0x00B4, 0x00B4 ), + AF_UNIRANGE_REC( 0x00B8, 0x00B8 ), + AF_UNIRANGE_REC( 0x00BC, 0x00BE ), + AF_UNIRANGE_REC( 0x02B9, 0x02DF ), + AF_UNIRANGE_REC( 0x02E5, 0x02FF ), + AF_UNIRANGE_REC( 0x0300, 0x036F ), + AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), + AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), + AF_UNIRANGE_REC( 0x2017, 0x2017 ), + AF_UNIRANGE_REC( 0x203E, 0x203E ), + AF_UNIRANGE_REC( 0xA788, 0xA788 ), + AF_UNIRANGE_REC( 0xA7F8, 0xA7FA ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latb_uniranges[] = + { + AF_UNIRANGE_REC( 0x1D62, 0x1D6A ), /* some small subscript letters */ + AF_UNIRANGE_REC( 0x2080, 0x209C ), /* subscript digits and letters */ + AF_UNIRANGE_REC( 0x2C7C, 0x2C7C ), /* latin subscript small letter j */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latb_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_latp_uniranges[] = + { + AF_UNIRANGE_REC( 0x00AA, 0x00AA ), /* feminine ordinal indicator */ + AF_UNIRANGE_REC( 0x00B2, 0x00B3 ), /* superscript two and three */ + AF_UNIRANGE_REC( 0x00B9, 0x00BA ), /* superscript one, masc. ord. indic. */ + AF_UNIRANGE_REC( 0x02B0, 0x02B8 ), /* some latin superscript mod. letters */ + AF_UNIRANGE_REC( 0x02E0, 0x02E4 ), /* some IPA modifier letters */ + AF_UNIRANGE_REC( 0x1D2C, 0x1D61 ), /* latin superscript modifier letters */ + AF_UNIRANGE_REC( 0x1D78, 0x1D78 ), /* modifier letter cyrillic en */ + AF_UNIRANGE_REC( 0x1D9B, 0x1DBF ), /* more modifier letters */ + AF_UNIRANGE_REC( 0x2070, 0x207F ), /* superscript digits and letters */ + AF_UNIRANGE_REC( 0x2C7D, 0x2C7D ), /* modifier letter capital v */ + AF_UNIRANGE_REC( 0xA770, 0xA770 ), /* modifier letter us */ + AF_UNIRANGE_REC( 0xA7F8, 0xA7F9 ), /* more modifier letters */ + AF_UNIRANGE_REC( 0xAB5C, 0xAB5F ), /* more modifier letters */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_latp_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_lisu_uniranges[] = + { + AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_lisu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mlym_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D00, 0x0D7F ), /* Malayalam */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mlym_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D00, 0x0D01 ), + AF_UNIRANGE_REC( 0x0D3B, 0x0D3C ), + AF_UNIRANGE_REC( 0x0D4D, 0x0D4E ), + AF_UNIRANGE_REC( 0x0D62, 0x0D63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_medf_uniranges[] = + { + AF_UNIRANGE_REC( 0x16E40, 0x16E9F ), /* Medefaidrin */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_medf_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mong_uniranges[] = + { + AF_UNIRANGE_REC( 0x1800, 0x18AF ), /* Mongolian */ + AF_UNIRANGE_REC( 0x11660, 0x1167F ), /* Mongolian Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mong_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1885, 0x1886 ), + AF_UNIRANGE_REC( 0x18A9, 0x18A9 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_mymr_uniranges[] = + { + AF_UNIRANGE_REC( 0x1000, 0x109F ), /* Myanmar */ + AF_UNIRANGE_REC( 0xA9E0, 0xA9FF ), /* Myanmar Extended-B */ + AF_UNIRANGE_REC( 0xAA60, 0xAA7F ), /* Myanmar Extended-A */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mymr_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x102D, 0x1030 ), + AF_UNIRANGE_REC( 0x1032, 0x1037 ), + AF_UNIRANGE_REC( 0x103A, 0x103A ), + AF_UNIRANGE_REC( 0x103D, 0x103E ), + AF_UNIRANGE_REC( 0x1058, 0x1059 ), + AF_UNIRANGE_REC( 0x105E, 0x1060 ), + AF_UNIRANGE_REC( 0x1071, 0x1074 ), + AF_UNIRANGE_REC( 0x1082, 0x1082 ), + AF_UNIRANGE_REC( 0x1085, 0x1086 ), + AF_UNIRANGE_REC( 0x108D, 0x108D ), + AF_UNIRANGE_REC( 0xA9E5, 0xA9E5 ), + AF_UNIRANGE_REC( 0xAA7C, 0xAA7C ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_nkoo_uniranges[] = + { + AF_UNIRANGE_REC( 0x07C0, 0x07FF ), /* N'Ko */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_nkoo_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x07EB, 0x07F5 ), + AF_UNIRANGE_REC( 0x07FD, 0x07FD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_none_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_none_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_olck_uniranges[] = + { + AF_UNIRANGE_REC( 0x1C50, 0x1C7F ), /* Ol Chiki */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_olck_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_orkh_uniranges[] = + { + AF_UNIRANGE_REC( 0x10C00, 0x10C4F ), /* Old Turkic */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_orkh_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_osge_uniranges[] = + { + AF_UNIRANGE_REC( 0x104B0, 0x104FF ), /* Osage */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_osge_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_osma_uniranges[] = + { + AF_UNIRANGE_REC( 0x10480, 0x104AF ), /* Osmanya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_osma_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_rohg_uniranges[] = + { + AF_UNIRANGE_REC( 0x10D00, 0x10D3F ), /* Hanifi Rohingya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_rohg_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_saur_uniranges[] = + { + AF_UNIRANGE_REC( 0xA880, 0xA8DF ), /* Saurashtra */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_saur_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA880, 0xA881 ), + AF_UNIRANGE_REC( 0xA8B4, 0xA8C5 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_shaw_uniranges[] = + { + AF_UNIRANGE_REC( 0x10450, 0x1047F ), /* Shavian */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_shaw_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sinh_uniranges[] = + { + AF_UNIRANGE_REC( 0x0D80, 0x0DFF ), /* Sinhala */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sinh_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0DCA, 0x0DCA ), + AF_UNIRANGE_REC( 0x0DD2, 0x0DD6 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sund_uniranges[] = + { + AF_UNIRANGE_REC( 0x1B80, 0x1BBF ), /* Sundanese */ + AF_UNIRANGE_REC( 0x1CC0, 0x1CCF ), /* Sundanese Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sund_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1B80, 0x1B82 ), + AF_UNIRANGE_REC( 0x1BA1, 0x1BAD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_taml_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_taml_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B82, 0x0B82 ), + AF_UNIRANGE_REC( 0x0BC0, 0x0BC2 ), + AF_UNIRANGE_REC( 0x0BCD, 0x0BCD ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tavt_uniranges[] = + { + AF_UNIRANGE_REC( 0xAA80, 0xAADF ), /* Tai Viet */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tavt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xAAB0, 0xAAB0 ), + AF_UNIRANGE_REC( 0xAAB2, 0xAAB4 ), + AF_UNIRANGE_REC( 0xAAB7, 0xAAB8 ), + AF_UNIRANGE_REC( 0xAABE, 0xAABF ), + AF_UNIRANGE_REC( 0xAAC1, 0xAAC1 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_telu_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C00, 0x0C7F ), /* Telugu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_telu_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0C00, 0x0C00 ), + AF_UNIRANGE_REC( 0x0C04, 0x0C04 ), + AF_UNIRANGE_REC( 0x0C3E, 0x0C40 ), + AF_UNIRANGE_REC( 0x0C46, 0x0C56 ), + AF_UNIRANGE_REC( 0x0C62, 0x0C63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_thai_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E00, 0x0E7F ), /* Thai */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_thai_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0E31, 0x0E31 ), + AF_UNIRANGE_REC( 0x0E34, 0x0E3A ), + AF_UNIRANGE_REC( 0x0E47, 0x0E4E ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tfng_uniranges[] = + { + AF_UNIRANGE_REC( 0x2D30, 0x2D7F ), /* Tifinagh */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tfng_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_vaii_uniranges[] = + { + AF_UNIRANGE_REC( 0xA500, 0xA63F ), /* Vai */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_vaii_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + +#ifdef AF_CONFIG_OPTION_INDIC + + const AF_Script_UniRangeRec af_limb_uniranges[] = + { + AF_UNIRANGE_REC( 0x1900, 0x194F ), /* Limbu */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_limb_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x1920, 0x1922 ), + AF_UNIRANGE_REC( 0x1927, 0x1934 ), + AF_UNIRANGE_REC( 0x1937, 0x193B ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_orya_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B00, 0x0B7F ), /* Oriya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_orya_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0B01, 0x0B02 ), + AF_UNIRANGE_REC( 0x0B3C, 0x0B3C ), + AF_UNIRANGE_REC( 0x0B3F, 0x0B3F ), + AF_UNIRANGE_REC( 0x0B41, 0x0B44 ), + AF_UNIRANGE_REC( 0x0B4D, 0x0B56 ), + AF_UNIRANGE_REC( 0x0B62, 0x0B63 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_sylo_uniranges[] = + { + AF_UNIRANGE_REC( 0xA800, 0xA82F ), /* Syloti Nagri */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_sylo_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0xA802, 0xA802 ), + AF_UNIRANGE_REC( 0xA806, 0xA806 ), + AF_UNIRANGE_REC( 0xA80B, 0xA80B ), + AF_UNIRANGE_REC( 0xA825, 0xA826 ), + AF_UNIRANGE_REC( 0, 0 ) + }; + + + const AF_Script_UniRangeRec af_tibt_uniranges[] = + { + AF_UNIRANGE_REC( 0x0F00, 0x0FFF ), /* Tibetan */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_tibt_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x0F18, 0x0F19 ), + AF_UNIRANGE_REC( 0x0F35, 0x0F35 ), + AF_UNIRANGE_REC( 0x0F37, 0x0F37 ), + AF_UNIRANGE_REC( 0x0F39, 0x0F39 ), + AF_UNIRANGE_REC( 0x0F3E, 0x0F3F ), + AF_UNIRANGE_REC( 0x0F71, 0x0F7E ), + AF_UNIRANGE_REC( 0x0F80, 0x0F84 ), + AF_UNIRANGE_REC( 0x0F86, 0x0F87 ), + AF_UNIRANGE_REC( 0x0F8D, 0x0FBC ), + AF_UNIRANGE_REC( 0, 0 ) + }; + +#endif /* !AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + /* this corresponds to Unicode 6.0 */ + + const AF_Script_UniRangeRec af_hani_uniranges[] = + { + AF_UNIRANGE_REC( 0x1100, 0x11FF ), /* Hangul Jamo */ + AF_UNIRANGE_REC( 0x2E80, 0x2EFF ), /* CJK Radicals Supplement */ + AF_UNIRANGE_REC( 0x2F00, 0x2FDF ), /* Kangxi Radicals */ + AF_UNIRANGE_REC( 0x2FF0, 0x2FFF ), /* Ideographic Description Characters */ + AF_UNIRANGE_REC( 0x3000, 0x303F ), /* CJK Symbols and Punctuation */ + AF_UNIRANGE_REC( 0x3040, 0x309F ), /* Hiragana */ + AF_UNIRANGE_REC( 0x30A0, 0x30FF ), /* Katakana */ + AF_UNIRANGE_REC( 0x3100, 0x312F ), /* Bopomofo */ + AF_UNIRANGE_REC( 0x3130, 0x318F ), /* Hangul Compatibility Jamo */ + AF_UNIRANGE_REC( 0x3190, 0x319F ), /* Kanbun */ + AF_UNIRANGE_REC( 0x31A0, 0x31BF ), /* Bopomofo Extended */ + AF_UNIRANGE_REC( 0x31C0, 0x31EF ), /* CJK Strokes */ + AF_UNIRANGE_REC( 0x31F0, 0x31FF ), /* Katakana Phonetic Extensions */ + AF_UNIRANGE_REC( 0x3300, 0x33FF ), /* CJK Compatibility */ + AF_UNIRANGE_REC( 0x3400, 0x4DBF ), /* CJK Unified Ideographs Extension A */ + AF_UNIRANGE_REC( 0x4DC0, 0x4DFF ), /* Yijing Hexagram Symbols */ + AF_UNIRANGE_REC( 0x4E00, 0x9FFF ), /* CJK Unified Ideographs */ + AF_UNIRANGE_REC( 0xA960, 0xA97F ), /* Hangul Jamo Extended-A */ + AF_UNIRANGE_REC( 0xAC00, 0xD7AF ), /* Hangul Syllables */ + AF_UNIRANGE_REC( 0xD7B0, 0xD7FF ), /* Hangul Jamo Extended-B */ + AF_UNIRANGE_REC( 0xF900, 0xFAFF ), /* CJK Compatibility Ideographs */ + AF_UNIRANGE_REC( 0xFE10, 0xFE1F ), /* Vertical forms */ + AF_UNIRANGE_REC( 0xFE30, 0xFE4F ), /* CJK Compatibility Forms */ + AF_UNIRANGE_REC( 0xFF00, 0xFFEF ), /* Halfwidth and Fullwidth Forms */ + AF_UNIRANGE_REC( 0x1B000, 0x1B0FF ), /* Kana Supplement */ + AF_UNIRANGE_REC( 0x1B100, 0x1B12F ), /* Kana Extended-A */ + AF_UNIRANGE_REC( 0x1D300, 0x1D35F ), /* Tai Xuan Hing Symbols */ + AF_UNIRANGE_REC( 0x20000, 0x2A6DF ), /* CJK Unified Ideographs Extension B */ + AF_UNIRANGE_REC( 0x2A700, 0x2B73F ), /* CJK Unified Ideographs Extension C */ + AF_UNIRANGE_REC( 0x2B740, 0x2B81F ), /* CJK Unified Ideographs Extension D */ + AF_UNIRANGE_REC( 0x2B820, 0x2CEAF ), /* CJK Unified Ideographs Extension E */ + AF_UNIRANGE_REC( 0x2CEB0, 0x2EBEF ), /* CJK Unified Ideographs Extension F */ + AF_UNIRANGE_REC( 0x2F800, 0x2FA1F ), /* CJK Compatibility Ideographs Supplement */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_hani_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0x302A, 0x302F ), + AF_UNIRANGE_REC( 0x3190, 0x319F ), + AF_UNIRANGE_REC( 0, 0 ) + }; + +#endif /* !AF_CONFIG_OPTION_CJK */ + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afranges.h b/Dependencies/freetype/freetype/src/autofit/afranges.h new file mode 100644 index 00000000..813b3ee7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afranges.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * afranges.h + * + * Auto-fitter Unicode script ranges (specification). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFRANGES_H_ +#define AFRANGES_H_ + + +#include "aftypes.h" + + +FT_BEGIN_HEADER + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + extern const AF_Script_UniRangeRec af_ ## s ## _uniranges[]; + +#include "afscript.h" + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + extern const AF_Script_UniRangeRec af_ ## s ## _nonbase_uniranges[]; + +#include "afscript.h" + + /* */ + +FT_END_HEADER + +#endif /* AFRANGES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afscript.h b/Dependencies/freetype/freetype/src/autofit/afscript.h new file mode 100644 index 00000000..0a83d771 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afscript.h @@ -0,0 +1,408 @@ +/**************************************************************************** + * + * afscript.h + * + * Auto-fitter scripts (specification only). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* The following part can be included multiple times. */ + /* Define `SCRIPT' as needed. */ + + + /* Add new scripts here. The first and second arguments are the */ + /* script name in lowercase and uppercase, respectively, followed */ + /* by a description string. Then comes the corresponding HarfBuzz */ + /* script name tag, followed by a string of standard characters (to */ + /* derive the standard width and height of stems). */ + /* */ + /* Note that fallback scripts only have a default style, thus we */ + /* use `HB_SCRIPT_INVALID' as the HarfBuzz script name tag for */ + /* them. */ + + SCRIPT( adlm, ADLM, + "Adlam", + HB_SCRIPT_ADLAM, + HINTING_BOTTOM_TO_TOP, + "\xF0\x9E\xA4\x8C \xF0\x9E\xA4\xAE" ) /* 𞤌 𞤮 */ + + SCRIPT( arab, ARAB, + "Arabic", + HB_SCRIPT_ARABIC, + HINTING_BOTTOM_TO_TOP, + "\xD9\x84 \xD8\xAD \xD9\x80" ) /* ل ح ـ */ + + SCRIPT( armn, ARMN, + "Armenian", + HB_SCRIPT_ARMENIAN, + HINTING_BOTTOM_TO_TOP, + "\xD5\xBD \xD5\x8D" ) /* ս Ս */ + + SCRIPT( avst, AVST, + "Avestan", + HB_SCRIPT_AVESTAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xAC\x9A" ) /* 𐬚 */ + + SCRIPT( bamu, BAMU, + "Bamum", + HB_SCRIPT_BAMUM, + HINTING_BOTTOM_TO_TOP, + "\xEA\x9B\x81 \xEA\x9B\xAF" ) /* ꛁ ꛯ */ + + /* there are no simple forms for letters; we thus use two digit shapes */ + SCRIPT( beng, BENG, + "Bengali", + HB_SCRIPT_BENGALI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA7\xA6 \xE0\xA7\xAA" ) /* ০ ৪ */ + + SCRIPT( buhd, BUHD, + "Buhid", + HB_SCRIPT_BUHID, + HINTING_BOTTOM_TO_TOP, + "\xE1\x9D\x8B \xE1\x9D\x8F" ) /* ᝋ ᝏ */ + + SCRIPT( cakm, CAKM, + "Chakma", + HB_SCRIPT_CHAKMA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x91\x84\xA4 \xF0\x91\x84\x89 \xF0\x91\x84\x9B" ) /* 𑄤 𑄉 𑄛 */ + + SCRIPT( cans, CANS, + "Canadian Syllabics", + HB_SCRIPT_CANADIAN_SYLLABICS, + HINTING_BOTTOM_TO_TOP, + "\xE1\x91\x8C \xE1\x93\x9A" ) /* ᑌ ᓚ */ + + SCRIPT( cari, CARI, + "Carian", + HB_SCRIPT_CARIAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x8A\xAB \xF0\x90\x8B\x89" ) /* 𐊫 𐋉 */ + + SCRIPT( cher, CHER, + "Cherokee", + HB_SCRIPT_CHEROKEE, + HINTING_BOTTOM_TO_TOP, + "\xE1\x8E\xA4 \xE1\x8F\x85 \xEA\xAE\x95" ) /* Ꭴ Ꮕ ꮕ */ + + SCRIPT( copt, COPT, + "Coptic", + HB_SCRIPT_COPTIC, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB2\x9E \xE2\xB2\x9F" ) /* Ⲟ ⲟ */ + + SCRIPT( cprt, CPRT, + "Cypriot", + HB_SCRIPT_CYPRIOT, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xA0\x85 \xF0\x90\xA0\xA3" ) /* 𐠅 𐠣 */ + + SCRIPT( cyrl, CYRL, + "Cyrillic", + HB_SCRIPT_CYRILLIC, + HINTING_BOTTOM_TO_TOP, + "\xD0\xBE \xD0\x9E" ) /* о О */ + + SCRIPT( deva, DEVA, + "Devanagari", + HB_SCRIPT_DEVANAGARI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA4\xA0 \xE0\xA4\xB5 \xE0\xA4\x9F" ) /* ठ व ट */ + + SCRIPT( dsrt, DSRT, + "Deseret", + HB_SCRIPT_DESERET, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x90\x84 \xF0\x90\x90\xAC" ) /* 𐐄 𐐬 */ + + SCRIPT( ethi, ETHI, + "Ethiopic", + HB_SCRIPT_ETHIOPIC, + HINTING_BOTTOM_TO_TOP, + "\xE1\x8B\x90" ) /* ዐ */ + + SCRIPT( geor, GEOR, + "Georgian (Mkhedruli)", + HB_SCRIPT_GEORGIAN, + HINTING_BOTTOM_TO_TOP, + "\xE1\x83\x98 \xE1\x83\x94 \xE1\x83\x90 \xE1\xB2\xBF" ) /* ი ე ა Ი */ + + SCRIPT( geok, GEOK, + "Georgian (Khutsuri)", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\x82\xB6 \xE1\x82\xB1 \xE2\xB4\x99" ) /* Ⴖ Ⴑ ⴙ */ + + SCRIPT( glag, GLAG, + "Glagolitic", + HB_SCRIPT_GLAGOLITIC, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB0\x95 \xE2\xB1\x85" ) /* Ⱅ ⱅ */ + + SCRIPT( goth, GOTH, + "Gothic", + HB_SCRIPT_GOTHIC, + HINTING_TOP_TO_BOTTOM, + "\xF0\x90\x8C\xB4 \xF0\x90\x8C\xBE \xF0\x90\x8D\x83" ) /* 𐌴 𐌾 𐍃 */ + + SCRIPT( grek, GREK, + "Greek", + HB_SCRIPT_GREEK, + HINTING_BOTTOM_TO_TOP, + "\xCE\xBF \xCE\x9F" ) /* ο Ο */ + + SCRIPT( gujr, GUJR, + "Gujarati", + HB_SCRIPT_GUJARATI, + HINTING_BOTTOM_TO_TOP, + "\xE0\xAA\x9F \xE0\xAB\xA6" ) /* ટ ૦ */ + + SCRIPT( guru, GURU, + "Gurmukhi", + HB_SCRIPT_GURMUKHI, + HINTING_TOP_TO_BOTTOM, + "\xE0\xA8\xA0 \xE0\xA8\xB0 \xE0\xA9\xA6" ) /* ਠ ਰ ੦ */ + + SCRIPT( hebr, HEBR, + "Hebrew", + HB_SCRIPT_HEBREW, + HINTING_BOTTOM_TO_TOP, + "\xD7\x9D" ) /* ם */ + + SCRIPT( kali, KALI, + "Kayah Li", + HB_SCRIPT_KAYAH_LI, + HINTING_BOTTOM_TO_TOP, + "\xEA\xA4\x8D \xEA\xA4\x80" ) /* ꤍ ꤀ */ + + /* only digit zero has a simple shape in the Khmer script */ + SCRIPT( khmr, KHMR, + "Khmer", + HB_SCRIPT_KHMER, + HINTING_BOTTOM_TO_TOP, + "\xE1\x9F\xA0" ) /* ០ */ + + SCRIPT( khms, KHMS, + "Khmer Symbols", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\xA7\xA1 \xE1\xA7\xAA" ) /* ᧡ ᧪ */ + + SCRIPT( knda, KNDA, + "Kannada", + HB_SCRIPT_KANNADA, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB3\xA6 \xE0\xB2\xAC" ) /* ೦ ಬ */ + + /* only digit zero has a simple shape in the Lao script */ + SCRIPT( lao, LAO, + "Lao", + HB_SCRIPT_LAO, + HINTING_BOTTOM_TO_TOP, + "\xE0\xBB\x90" ) /* ໐ */ + + SCRIPT( latn, LATN, + "Latin", + HB_SCRIPT_LATIN, + HINTING_BOTTOM_TO_TOP, + "o O 0" ) + + SCRIPT( latb, LATB, + "Latin Subscript Fallback", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE2\x82\x92 \xE2\x82\x80" ) /* ₒ ₀ */ + + SCRIPT( latp, LATP, + "Latin Superscript Fallback", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "\xE1\xB5\x92 \xE1\xB4\xBC \xE2\x81\xB0" ) /* ᵒ ᴼ ⁰ */ + + SCRIPT( lisu, LISU, + "Lisu", + HB_SCRIPT_LISU, + HINTING_BOTTOM_TO_TOP, + "\xEA\x93\xB3" ) /* ꓳ */ + + SCRIPT( mlym, MLYM, + "Malayalam", + HB_SCRIPT_MALAYALAM, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB4\xA0 \xE0\xB4\xB1" ) /* ഠ റ */ + + SCRIPT( medf, MEDF, + "Medefaidrin", + HB_SCRIPT_MEDEFAIDRIN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x96\xB9\xA1 \xF0\x96\xB9\x9B \xF0\x96\xB9\xAF" ) /* 𖹡 𖹛 𖹯 */ + + SCRIPT( mong, MONG, + "Mongolian", + HB_SCRIPT_MONGOLIAN, + HINTING_TOP_TO_BOTTOM, + "\xE1\xA1\x82 \xE1\xA0\xAA" ) /* ᡂ ᠪ */ + + SCRIPT( mymr, MYMR, + "Myanmar", + HB_SCRIPT_MYANMAR, + HINTING_BOTTOM_TO_TOP, + "\xE1\x80\x9D \xE1\x80\x84 \xE1\x80\x82" ) /* ဝ င ဂ */ + + SCRIPT( nkoo, NKOO, + "N'Ko", + HB_SCRIPT_NKO, + HINTING_BOTTOM_TO_TOP, + "\xDF\x8B \xDF\x80" ) /* ߋ ߀ */ + + SCRIPT( none, NONE, + "no script", + HB_SCRIPT_INVALID, + HINTING_BOTTOM_TO_TOP, + "" ) + + SCRIPT( olck, OLCK, + "Ol Chiki", + HB_SCRIPT_OL_CHIKI, + HINTING_BOTTOM_TO_TOP, + "\xE1\xB1\x9B" ) /* ᱛ */ + + SCRIPT( orkh, ORKH, + "Old Turkic", + HB_SCRIPT_OLD_TURKIC, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xB0\x97" ) /* 𐰗 */ + + SCRIPT( osge, OSGE, + "Osage", + HB_SCRIPT_OSAGE, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x93\x82 \xF0\x90\x93\xAA" ) /* 𐓂 𐓪 */ + + SCRIPT( osma, OSMA, + "Osmanya", + HB_SCRIPT_OSMANYA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x92\x86 \xF0\x90\x92\xA0" ) /* 𐒆 𐒠 */ + + SCRIPT( rohg, ROHG, + "Hanifi Rohingya", + HB_SCRIPT_HANIFI_ROHINGYA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xB4\xB0" ) /* 𐴰 */ + + SCRIPT( saur, SAUR, + "Saurashtra", + HB_SCRIPT_SAURASHTRA, + HINTING_BOTTOM_TO_TOP, + "\xEA\xA2\x9D \xEA\xA3\x90" ) /* ꢝ ꣐ */ + + SCRIPT( shaw, SHAW, + "Shavian", + HB_SCRIPT_SHAVIAN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\x91\xB4" ) /* 𐑴 */ + + SCRIPT( sinh, SINH, + "Sinhala", + HB_SCRIPT_SINHALA, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB6\xA7" ) /* ට */ + + /* only digit zero has a simple (round) shape in the Sundanese script */ + SCRIPT( sund, SUND, + "Sundanese", + HB_SCRIPT_SUNDANESE, + HINTING_BOTTOM_TO_TOP, + "\xE1\xAE\xB0" ) /* ᮰ */ + + /* only digit zero has a simple (round) shape in the Tamil script */ + SCRIPT( taml, TAML, + "Tamil", + HB_SCRIPT_TAMIL, + HINTING_BOTTOM_TO_TOP, + "\xE0\xAF\xA6" ) /* ௦ */ + + SCRIPT( tavt, TAVT, + "Tai Viet", + HB_SCRIPT_TAI_VIET, + HINTING_BOTTOM_TO_TOP, + "\xEA\xAA\x92 \xEA\xAA\xAB" ) /* ꪒ ꪫ */ + + /* there are no simple forms for letters; we thus use two digit shapes */ + SCRIPT( telu, TELU, + "Telugu", + HB_SCRIPT_TELUGU, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB1\xA6 \xE0\xB1\xA7" ) /* ౦ ౧ */ + + SCRIPT( tfng, TFNG, + "Tifinagh", + HB_SCRIPT_TIFINAGH, + HINTING_BOTTOM_TO_TOP, + "\xE2\xB5\x94" ) /* ⵔ */ + + SCRIPT( thai, THAI, + "Thai", + HB_SCRIPT_THAI, + HINTING_BOTTOM_TO_TOP, + "\xE0\xB8\xB2 \xE0\xB9\x85 \xE0\xB9\x90" ) /* า ๅ ๐ */ + + SCRIPT( vaii, VAII, + "Vai", + HB_SCRIPT_VAI, + HINTING_BOTTOM_TO_TOP, + "\xEA\x98\x93 \xEA\x96\x9C \xEA\x96\xB4" ) /* ꘓ ꖜ ꖴ */ + +#ifdef AF_CONFIG_OPTION_INDIC + + SCRIPT( limb, LIMB, + "Limbu", + HB_SCRIPT_LIMBU, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( orya, ORYA, + "Oriya", + HB_SCRIPT_ORIYA, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( sylo, SYLO, + "Syloti Nagri", + HB_SCRIPT_SYLOTI_NAGRI, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + + SCRIPT( tibt, TIBT, + "Tibetan", + HB_SCRIPT_TIBETAN, + HINTING_BOTTOM_TO_TOP, + "o" ) /* XXX */ + +#endif /* AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + SCRIPT( hani, HANI, + "CJKV ideographs", + HB_SCRIPT_HAN, + HINTING_BOTTOM_TO_TOP, + "\xE7\x94\xB0 \xE5\x9B\x97" ) /* 田 囗 */ + +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afshaper.c b/Dependencies/freetype/freetype/src/autofit/afshaper.c new file mode 100644 index 00000000..df0f46ad --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afshaper.c @@ -0,0 +1,690 @@ +/**************************************************************************** + * + * afshaper.c + * + * HarfBuzz interface for accessing OpenType features (body). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "afglobal.h" +#include "aftypes.h" +#include "afshaper.h" + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afshaper + + + /* + * We use `sets' (in the HarfBuzz sense, which comes quite near to the + * usual mathematical meaning) to manage both lookups and glyph indices. + * + * 1. For each coverage, collect lookup IDs in a set. Note that an + * auto-hinter `coverage' is represented by one `feature', and a + * feature consists of an arbitrary number of (font specific) `lookup's + * that actually do the mapping job. Please check the OpenType + * specification for more details on features and lookups. + * + * 2. Create glyph ID sets from the corresponding lookup sets. + * + * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed + * with all lookups specific to the OpenType script activated. It + * relies on the order of AF_DEFINE_STYLE_CLASS entries so that + * special coverages (like `oldstyle figures') don't get overwritten. + * + */ + + + /* load coverage tags */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + static const hb_tag_t name ## _coverage[] = \ + { \ + HB_TAG( tag1, tag2, tag3, tag4 ), \ + HB_TAG_NONE \ + }; + + +#include "afcover.h" + + + /* define mapping between coverage tags and AF_Coverage */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + name ## _coverage, + + + static const hb_tag_t* coverages[] = + { +#include "afcover.h" + + NULL /* AF_COVERAGE_DEFAULT */ + }; + + + /* load HarfBuzz script tags */ +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) h, + + + static const hb_script_t scripts[] = + { +#include "afscript.h" + }; + + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { + hb_face_t* face; + + hb_set_t* gsub_lookups = NULL; /* GSUB lookups for a given script */ + hb_set_t* gsub_glyphs = NULL; /* glyphs covered by GSUB lookups */ + hb_set_t* gpos_lookups = NULL; /* GPOS lookups for a given script */ + hb_set_t* gpos_glyphs = NULL; /* glyphs covered by GPOS lookups */ + + hb_script_t script; + const hb_tag_t* coverage_tags; + hb_tag_t script_tags[] = { HB_TAG_NONE, + HB_TAG_NONE, + HB_TAG_NONE, + HB_TAG_NONE }; + + hb_codepoint_t idx; +#ifdef FT_DEBUG_LEVEL_TRACE + int count; +#endif + + + if ( !globals || !style_class || !gstyles ) + return FT_THROW( Invalid_Argument ); + + face = hb_font_get_face( globals->hb_font ); + + coverage_tags = coverages[style_class->coverage]; + script = scripts[style_class->script]; + + /* Convert a HarfBuzz script tag into the corresponding OpenType */ + /* tag or tags -- some Indic scripts like Devanagari have an old */ + /* and a new set of features. */ + { + unsigned int tags_count = 3; + hb_tag_t tags[3]; + + + hb_ot_tags_from_script_and_language( script, + HB_LANGUAGE_INVALID, + &tags_count, + tags, + NULL, + NULL ); + script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE; + script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE; + script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE; + } + + /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ + /* HB_TAG_NONE except for the default script. */ + if ( default_script ) + { + if ( script_tags[0] == HB_TAG_NONE ) + script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT; + else + { + if ( script_tags[1] == HB_TAG_NONE ) + script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT; + else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT ) + script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT; + } + } + else + { + /* we use non-standard tags like `khms' for special purposes; */ + /* HarfBuzz maps them to `DFLT', which we don't want to handle here */ + if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT ) + goto Exit; + } + + gsub_lookups = hb_set_create(); + hb_ot_layout_collect_lookups( face, + HB_OT_TAG_GSUB, + script_tags, + NULL, + coverage_tags, + gsub_lookups ); + + if ( hb_set_is_empty( gsub_lookups ) ) + goto Exit; /* nothing to do */ + + FT_TRACE4(( "GSUB lookups (style `%s'):\n", + af_style_names[style_class->style] )); + FT_TRACE4(( " " )); + +#ifdef FT_DEBUG_LEVEL_TRACE + count = 0; +#endif + + gsub_glyphs = hb_set_create(); + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* get output coverage of GSUB feature */ + hb_ot_layout_lookup_collect_glyphs( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + gsub_glyphs ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + FT_TRACE4(( "GPOS lookups (style `%s'):\n", + af_style_names[style_class->style] )); + FT_TRACE4(( " " )); + + gpos_lookups = hb_set_create(); + hb_ot_layout_collect_lookups( face, + HB_OT_TAG_GPOS, + script_tags, + NULL, + coverage_tags, + gpos_lookups ); + +#ifdef FT_DEBUG_LEVEL_TRACE + count = 0; +#endif + + gpos_glyphs = hb_set_create(); + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* get input coverage of GPOS feature */ + hb_ot_layout_lookup_collect_glyphs( face, + HB_OT_TAG_GPOS, + idx, + NULL, + gpos_glyphs, + NULL, + NULL ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + /* + * We now check whether we can construct blue zones, using glyphs + * covered by the feature only. In case there is not a single zone + * (that is, not a single character is covered), we skip this coverage. + * + */ + if ( style_class->coverage != AF_COVERAGE_DEFAULT ) + { + AF_Blue_Stringset bss = style_class->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + + FT_Bool found = 0; + + + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) + { + const char* p = &af_blue_strings[bs->string]; + + + while ( *p ) + { + hb_codepoint_t ch; + + + GET_UTF8_CHAR( ch, p ); + + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, + &idx ); ) + { + hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch ); + + + if ( hb_ot_layout_lookup_would_substitute( face, idx, + &gidx, 1, 1 ) ) + { + found = 1; + break; + } + } + } + } + + if ( !found ) + { + FT_TRACE4(( " no blue characters found; style skipped\n" )); + goto Exit; + } + } + + /* + * Various OpenType features might use the same glyphs at different + * vertical positions; for example, superscript and subscript glyphs + * could be the same. However, the auto-hinter is completely + * agnostic of OpenType features after the feature analysis has been + * completed: The engine then simply receives a glyph index and returns a + * hinted and usually rendered glyph. + * + * Consider the superscript feature of font `pala.ttf': Some of the + * glyphs are `real', that is, they have a zero vertical offset, but + * most of them are small caps glyphs shifted up to the superscript + * position (that is, the `sups' feature is present in both the GSUB and + * GPOS tables). The code for blue zones computation actually uses a + * feature's y offset so that the `real' glyphs get correct hints. But + * later on it is impossible to decide whether a glyph index belongs to, + * say, the small caps or superscript feature. + * + * For this reason, we don't assign a style to a glyph if the current + * feature covers the glyph in both the GSUB and the GPOS tables. This + * is quite a broad condition, assuming that + * + * (a) glyphs that get used in multiple features are present in a + * feature without vertical shift, + * + * and + * + * (b) a feature's GPOS data really moves the glyph vertically. + * + * Not fulfilling condition (a) makes a font larger; it would also + * reduce the number of glyphs that could be addressed directly without + * using OpenType features, so this assumption is rather strong. + * + * Condition (b) is much weaker, and there might be glyphs which get + * missed. However, the OpenType features we are going to handle are + * primarily located in GSUB, and HarfBuzz doesn't provide an API to + * directly get the necessary information from the GPOS table. A + * possible solution might be to directly parse the GPOS table to find + * out whether a glyph gets shifted vertically, but this is something I + * would like to avoid if not really necessary. + * + * Note that we don't follow this logic for the default coverage. + * Complex scripts like Devanagari have mandatory GPOS features to + * position many glyph elements, using mark-to-base or mark-to-ligature + * tables; the number of glyphs missed due to condition (b) would be far + * too large. + * + */ + if ( style_class->coverage != AF_COVERAGE_DEFAULT ) + hb_set_subtract( gsub_glyphs, gpos_glyphs ); + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" )); + count = 0; +#endif + + for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( count % 10 ) ) + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " " )); + } + + FT_TRACE4(( " %d", idx )); + count++; +#endif + + /* glyph indices returned by `hb_ot_layout_lookup_collect_glyphs' */ + /* can be arbitrary: some fonts use fake indices for processing */ + /* internal to GSUB or GPOS, which is fully valid */ + if ( idx >= (hb_codepoint_t)globals->glyph_count ) + continue; + + if ( gstyles[idx] == AF_STYLE_UNASSIGNED ) + gstyles[idx] = (FT_UShort)style_class->style; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE4(( "*" )); +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " (none)" )); + } + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); +#endif + + Exit: + hb_set_destroy( gsub_lookups ); + hb_set_destroy( gsub_glyphs ); + hb_set_destroy( gpos_lookups ); + hb_set_destroy( gpos_glyphs ); + + return FT_Err_Ok; + } + + + /* construct HarfBuzz features */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + static const hb_feature_t name ## _feature[] = \ + { \ + { \ + HB_TAG( tag1, tag2, tag3, tag4 ), \ + 1, 0, (unsigned int)-1 \ + } \ + }; + + +#include "afcover.h" + + + /* define mapping between HarfBuzz features and AF_Coverage */ +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + name ## _feature, + + + static const hb_feature_t* features[] = + { +#include "afcover.h" + + NULL /* AF_COVERAGE_DEFAULT */ + }; + + + void* + af_shaper_buf_create( FT_Face face ) + { + FT_UNUSED( face ); + + return (void*)hb_buffer_create(); + } + + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_UNUSED( face ); + + hb_buffer_destroy( (hb_buffer_t*)buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + AF_StyleClass style_class; + const hb_feature_t* feature; + FT_Int upem; + const char* q; + int len; + + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_font_t* font; + hb_codepoint_t dummy; + + + upem = (FT_Int)metrics->globals->face->units_per_EM; + style_class = metrics->style_class; + feature = features[style_class->coverage]; + + font = metrics->globals->hb_font; + + /* we shape at a size of units per EM; this means font units */ + hb_font_set_scale( font, upem, upem ); + + while ( *p == ' ' ) + p++; + + /* count bytes up to next space (or end of buffer) */ + q = p; + while ( !( *q == ' ' || *q == '\0' ) ) + GET_UTF8_CHAR( dummy, q ); + len = (int)( q - p ); + + /* feed character(s) to the HarfBuzz buffer */ + hb_buffer_clear_contents( buf ); + hb_buffer_add_utf8( buf, p, len, 0, len ); + + /* we let HarfBuzz guess the script and writing direction */ + hb_buffer_guess_segment_properties( buf ); + + /* shape buffer, which means conversion from character codes to */ + /* glyph indices, possibly applying a feature */ + hb_shape( font, buf, feature, feature ? 1 : 0 ); + + if ( feature ) + { + hb_buffer_t* hb_buf = metrics->globals->hb_buf; + + unsigned int gcount; + hb_glyph_info_t* ginfo; + + unsigned int hb_gcount; + hb_glyph_info_t* hb_ginfo; + + + /* we have to check whether applying a feature does actually change */ + /* glyph indices; otherwise the affected glyph or glyphs aren't */ + /* available at all in the feature */ + + hb_buffer_clear_contents( hb_buf ); + hb_buffer_add_utf8( hb_buf, p, len, 0, len ); + hb_buffer_guess_segment_properties( hb_buf ); + hb_shape( font, hb_buf, NULL, 0 ); + + ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); + hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount ); + + if ( gcount == hb_gcount ) + { + unsigned int i; + + + for (i = 0; i < gcount; i++ ) + if ( ginfo[i].codepoint != hb_ginfo[i].codepoint ) + break; + + if ( i == gcount ) + { + /* both buffers have identical glyph indices */ + hb_buffer_clear_contents( buf ); + } + } + } + + *count = hb_buffer_get_length( buf ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( feature && *count > 1 ) + FT_TRACE1(( "af_shaper_get_cluster:" + " input character mapped to multiple glyphs\n" )); +#endif + + return q; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_glyph_info_t* ginfo; + hb_glyph_position_t* gpos; + unsigned int gcount; + + FT_UNUSED( metrics ); + + + ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); + gpos = hb_buffer_get_glyph_positions( buf, &gcount ); + + if ( idx >= gcount ) + return 0; + + if ( advance ) + *advance = gpos[idx].x_advance; + if ( y_offset ) + *y_offset = gpos[idx].y_offset; + + return ginfo[idx].codepoint; + } + + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { + FT_UNUSED( globals ); + FT_UNUSED( style_class ); + FT_UNUSED( gstyles ); + FT_UNUSED( default_script ); + + return FT_Err_Ok; + } + + + void* + af_shaper_buf_create( FT_Face face ) + { + FT_UNUSED( face ); + + return NULL; + } + + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_UNUSED( face ); + FT_UNUSED( buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + FT_Face face = metrics->globals->face; + FT_ULong ch, dummy = 0; + FT_ULong* buf = (FT_ULong*)buf_; + + + while ( *p == ' ' ) + p++; + + GET_UTF8_CHAR( ch, p ); + + /* since we don't have an engine to handle clusters, */ + /* we scan the characters but return zero */ + while ( !( *p == ' ' || *p == '\0' ) ) + GET_UTF8_CHAR( dummy, p ); + + if ( dummy ) + { + *buf = 0; + *count = 0; + } + else + { + *buf = FT_Get_Char_Index( face, ch ); + *count = 1; + } + + return p; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + FT_Face face = metrics->globals->face; + FT_ULong glyph_index = *(FT_ULong*)buf_; + + FT_UNUSED( idx ); + + + if ( advance ) + FT_Get_Advance( face, + glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + advance ); + + if ( y_offset ) + *y_offset = 0; + + return glyph_index; + } + + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afshaper.h b/Dependencies/freetype/freetype/src/autofit/afshaper.h new file mode 100644 index 00000000..2eb03bb5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afshaper.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * + * afshaper.h + * + * HarfBuzz interface for accessing OpenType features (specification). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFSHAPER_H_ +#define AFSHAPER_H_ + + +#include + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include +#include +#include "ft-hb.h" + +#endif + + +FT_BEGIN_HEADER + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ); + + + void* + af_shaper_buf_create( FT_Face face ); + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ); + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ); + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* x_advance, + FT_Long* y_offset ); + + /* */ + +FT_END_HEADER + +#endif /* AFSHAPER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afstyles.h b/Dependencies/freetype/freetype/src/autofit/afstyles.h new file mode 100644 index 00000000..7a33f37a --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afstyles.h @@ -0,0 +1,487 @@ +/**************************************************************************** + * + * afstyles.h + * + * Auto-fitter styles (specification only). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* The following part can be included multiple times. */ + /* Define `STYLE' as needed. */ + + + /* Add new styles here. The first and second arguments are the */ + /* style name in lowercase and uppercase, respectively, followed */ + /* by a description string. The next arguments are the */ + /* corresponding writing system, script, blue stringset, and */ + /* coverage. */ + /* */ + /* Note that styles using `AF_COVERAGE_DEFAULT' should always */ + /* come after styles with other coverages. Also note that */ + /* fallback scripts only use `AF_COVERAGE_DEFAULT' for its */ + /* style. */ + /* */ + /* Example: */ + /* */ + /* STYLE( cyrl_dflt, CYRL_DFLT, */ + /* "Cyrillic default style", */ + /* AF_WRITING_SYSTEM_LATIN, */ + /* AF_SCRIPT_CYRL, */ + /* AF_BLUE_STRINGSET_CYRL, */ + /* AF_COVERAGE_DEFAULT ) */ + +#undef STYLE_LATIN +#define STYLE_LATIN( s, S, f, F, ds, df, C ) \ + STYLE( s ## _ ## f, S ## _ ## F, \ + ds " " df " style", \ + AF_WRITING_SYSTEM_LATIN, \ + AF_SCRIPT_ ## S, \ + AF_BLUE_STRINGSET_ ## S, \ + AF_COVERAGE_ ## C ) + +#undef META_STYLE_LATIN +#define META_STYLE_LATIN( s, S, ds ) \ + STYLE_LATIN( s, S, c2cp, C2CP, ds, \ + "petite capitals from capitals", \ + PETITE_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, c2sc, C2SC, ds, \ + "small capitals from capitals", \ + SMALL_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, ordn, ORDN, ds, \ + "ordinals", \ + ORDINALS ) \ + STYLE_LATIN( s, S, pcap, PCAP, ds, \ + "petite capitals", \ + PETITE_CAPITALS ) \ + STYLE_LATIN( s, S, sinf, SINF, ds, \ + "scientific inferiors", \ + SCIENTIFIC_INFERIORS ) \ + STYLE_LATIN( s, S, smcp, SMCP, ds, \ + "small capitals", \ + SMALL_CAPITALS ) \ + STYLE_LATIN( s, S, subs, SUBS, ds, \ + "subscript", \ + SUBSCRIPT ) \ + STYLE_LATIN( s, S, sups, SUPS, ds, \ + "superscript", \ + SUPERSCRIPT ) \ + STYLE_LATIN( s, S, titl, TITL, ds, \ + "titling", \ + TITLING ) \ + STYLE_LATIN( s, S, dflt, DFLT, ds, \ + "default", \ + DEFAULT ) + + + STYLE( adlm_dflt, ADLM_DFLT, + "Adlam default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ADLM, + AF_BLUE_STRINGSET_ADLM, + AF_COVERAGE_DEFAULT ) + + STYLE( arab_dflt, ARAB_DFLT, + "Arabic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ARAB, + AF_BLUE_STRINGSET_ARAB, + AF_COVERAGE_DEFAULT ) + + STYLE( armn_dflt, ARMN_DFLT, + "Armenian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ARMN, + AF_BLUE_STRINGSET_ARMN, + AF_COVERAGE_DEFAULT ) + + STYLE( avst_dflt, AVST_DFLT, + "Avestan default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_AVST, + AF_BLUE_STRINGSET_AVST, + AF_COVERAGE_DEFAULT ) + + STYLE( bamu_dflt, BAMU_DFLT, + "Bamum default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BAMU, + AF_BLUE_STRINGSET_BAMU, + AF_COVERAGE_DEFAULT ) + + STYLE( beng_dflt, BENG_DFLT, + "Bengali default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BENG, + AF_BLUE_STRINGSET_BENG, + AF_COVERAGE_DEFAULT ) + + STYLE( buhd_dflt, BUHD_DFLT, + "Buhid default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_BUHD, + AF_BLUE_STRINGSET_BUHD, + AF_COVERAGE_DEFAULT ) + + STYLE( cakm_dflt, CAKM_DFLT, + "Chakma default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CAKM, + AF_BLUE_STRINGSET_CAKM, + AF_COVERAGE_DEFAULT ) + + STYLE( cans_dflt, CANS_DFLT, + "Canadian Syllabics default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CANS, + AF_BLUE_STRINGSET_CANS, + AF_COVERAGE_DEFAULT ) + + STYLE( cari_dflt, CARI_DFLT, + "Carian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CARI, + AF_BLUE_STRINGSET_CARI, + AF_COVERAGE_DEFAULT ) + + STYLE( cher_dflt, CHER_DFLT, + "Cherokee default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CHER, + AF_BLUE_STRINGSET_CHER, + AF_COVERAGE_DEFAULT ) + + STYLE( copt_dflt, COPT_DFLT, + "Coptic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_COPT, + AF_BLUE_STRINGSET_COPT, + AF_COVERAGE_DEFAULT ) + + STYLE( cprt_dflt, CPRT_DFLT, + "Cypriot default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_CPRT, + AF_BLUE_STRINGSET_CPRT, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( cyrl, CYRL, "Cyrillic" ) + + STYLE( deva_dflt, DEVA_DFLT, + "Devanagari default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_DEVA, + AF_BLUE_STRINGSET_DEVA, + AF_COVERAGE_DEFAULT ) + + STYLE( dsrt_dflt, DSRT_DFLT, + "Deseret default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_DSRT, + AF_BLUE_STRINGSET_DSRT, + AF_COVERAGE_DEFAULT ) + + STYLE( ethi_dflt, ETHI_DFLT, + "Ethiopic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ETHI, + AF_BLUE_STRINGSET_ETHI, + AF_COVERAGE_DEFAULT ) + + STYLE( geor_dflt, GEOR_DFLT, + "Georgian (Mkhedruli) default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GEOR, + AF_BLUE_STRINGSET_GEOR, + AF_COVERAGE_DEFAULT ) + + STYLE( geok_dflt, GEOK_DFLT, + "Georgian (Khutsuri) default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GEOK, + AF_BLUE_STRINGSET_GEOK, + AF_COVERAGE_DEFAULT ) + + STYLE( glag_dflt, GLAG_DFLT, + "Glagolitic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GLAG, + AF_BLUE_STRINGSET_GLAG, + AF_COVERAGE_DEFAULT ) + + STYLE( goth_dflt, GOTH_DFLT, + "Gothic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GOTH, + AF_BLUE_STRINGSET_GOTH, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( grek, GREK, "Greek" ) + + STYLE( gujr_dflt, GUJR_DFLT, + "Gujarati default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GUJR, + AF_BLUE_STRINGSET_GUJR, + AF_COVERAGE_DEFAULT ) + + STYLE( guru_dflt, GURU_DFLT, + "Gurmukhi default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_GURU, + AF_BLUE_STRINGSET_GURU, + AF_COVERAGE_DEFAULT ) + + STYLE( hebr_dflt, HEBR_DFLT, + "Hebrew default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_HEBR, + AF_BLUE_STRINGSET_HEBR, + AF_COVERAGE_DEFAULT ) + + STYLE( kali_dflt, KALI_DFLT, + "Kayah Li default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KALI, + AF_BLUE_STRINGSET_KALI, + AF_COVERAGE_DEFAULT ) + + STYLE( khmr_dflt, KHMR_DFLT, + "Khmer default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KHMR, + AF_BLUE_STRINGSET_KHMR, + AF_COVERAGE_DEFAULT ) + + STYLE( khms_dflt, KHMS_DFLT, + "Khmer Symbols default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KHMS, + AF_BLUE_STRINGSET_KHMS, + AF_COVERAGE_DEFAULT ) + + STYLE( knda_dflt, KNDA_DFLT, + "Kannada default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_KNDA, + AF_BLUE_STRINGSET_KNDA, + AF_COVERAGE_DEFAULT ) + + STYLE( lao_dflt, LAO_DFLT, + "Lao default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LAO, + AF_BLUE_STRINGSET_LAO, + AF_COVERAGE_DEFAULT ) + + META_STYLE_LATIN( latn, LATN, "Latin" ) + + STYLE( latb_dflt, LATB_DFLT, + "Latin subscript fallback default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LATB, + AF_BLUE_STRINGSET_LATB, + AF_COVERAGE_DEFAULT ) + + STYLE( latp_dflt, LATP_DFLT, + "Latin superscript fallback default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LATP, + AF_BLUE_STRINGSET_LATP, + AF_COVERAGE_DEFAULT ) + + STYLE( lisu_dflt, LISU_DFLT, + "Lisu default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_LISU, + AF_BLUE_STRINGSET_LISU, + AF_COVERAGE_DEFAULT ) + + STYLE( mlym_dflt, MLYM_DFLT, + "Malayalam default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MLYM, + AF_BLUE_STRINGSET_MLYM, + AF_COVERAGE_DEFAULT ) + + STYLE( medf_dflt, MEDF_DFLT, + "Medefaidrin default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MEDF, + AF_BLUE_STRINGSET_MEDF, + AF_COVERAGE_DEFAULT ) + + STYLE( mong_dflt, MONG_DFLT, + "Mongolian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MONG, + AF_BLUE_STRINGSET_MONG, + AF_COVERAGE_DEFAULT ) + + STYLE( mymr_dflt, MYMR_DFLT, + "Myanmar default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MYMR, + AF_BLUE_STRINGSET_MYMR, + AF_COVERAGE_DEFAULT ) + + STYLE( nkoo_dflt, NKOO_DFLT, + "N'Ko default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_NKOO, + AF_BLUE_STRINGSET_NKOO, + AF_COVERAGE_DEFAULT ) + + STYLE( none_dflt, NONE_DFLT, + "no style", + AF_WRITING_SYSTEM_DUMMY, + AF_SCRIPT_NONE, + AF_BLUE_STRINGSET_NONE, + AF_COVERAGE_DEFAULT ) + + STYLE( olck_dflt, OLCK_DFLT, + "Ol Chiki default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OLCK, + AF_BLUE_STRINGSET_OLCK, + AF_COVERAGE_DEFAULT ) + + STYLE( orkh_dflt, ORKH_DFLT, + "Old Turkic default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ORKH, + AF_BLUE_STRINGSET_ORKH, + AF_COVERAGE_DEFAULT ) + + STYLE( osge_dflt, OSGE_DFLT, + "Osage default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OSGE, + AF_BLUE_STRINGSET_OSGE, + AF_COVERAGE_DEFAULT ) + + STYLE( osma_dflt, OSMA_DFLT, + "Osmanya default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_OSMA, + AF_BLUE_STRINGSET_OSMA, + AF_COVERAGE_DEFAULT ) + + STYLE( rohg_dflt, ROHG_DFLT, + "Hanifi Rohingya default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ROHG, + AF_BLUE_STRINGSET_ROHG, + AF_COVERAGE_DEFAULT ) + + STYLE( saur_dflt, SAUR_DFLT, + "Saurashtra default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SAUR, + AF_BLUE_STRINGSET_SAUR, + AF_COVERAGE_DEFAULT ) + + STYLE( shaw_dflt, SHAW_DFLT, + "Shavian default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SHAW, + AF_BLUE_STRINGSET_SHAW, + AF_COVERAGE_DEFAULT ) + + STYLE( sinh_dflt, SINH_DFLT, + "Sinhala default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SINH, + AF_BLUE_STRINGSET_SINH, + AF_COVERAGE_DEFAULT ) + + STYLE( sund_dflt, SUND_DFLT, + "Sundanese default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_SUND, + AF_BLUE_STRINGSET_SUND, + AF_COVERAGE_DEFAULT ) + + STYLE( taml_dflt, TAML_DFLT, + "Tamil default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TAML, + AF_BLUE_STRINGSET_TAML, + AF_COVERAGE_DEFAULT ) + + STYLE( tavt_dflt, TAVT_DFLT, + "Tai Viet default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TAVT, + AF_BLUE_STRINGSET_TAVT, + AF_COVERAGE_DEFAULT ) + + STYLE( telu_dflt, TELU_DFLT, + "Telugu default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TELU, + AF_BLUE_STRINGSET_TELU, + AF_COVERAGE_DEFAULT ) + + STYLE( tfng_dflt, TFNG_DFLT, + "Tifinagh default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_TFNG, + AF_BLUE_STRINGSET_TFNG, + AF_COVERAGE_DEFAULT ) + + STYLE( thai_dflt, THAI_DFLT, + "Thai default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_THAI, + AF_BLUE_STRINGSET_THAI, + AF_COVERAGE_DEFAULT ) + + STYLE( vaii_dflt, VAII_DFLT, + "Vai default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_VAII, + AF_BLUE_STRINGSET_VAII, + AF_COVERAGE_DEFAULT ) + +#ifdef AF_CONFIG_OPTION_INDIC + + /* no blue stringset support for the Indic writing system yet */ +#undef STYLE_DEFAULT_INDIC +#define STYLE_DEFAULT_INDIC( s, S, d ) \ + STYLE( s ## _dflt, S ## _DFLT, \ + d " default style", \ + AF_WRITING_SYSTEM_INDIC, \ + AF_SCRIPT_ ## S, \ + (AF_Blue_Stringset)0, \ + AF_COVERAGE_DEFAULT ) + + STYLE_DEFAULT_INDIC( limb, LIMB, "Limbu" ) + STYLE_DEFAULT_INDIC( orya, ORYA, "Oriya" ) + STYLE_DEFAULT_INDIC( sylo, SYLO, "Syloti Nagri" ) + STYLE_DEFAULT_INDIC( tibt, TIBT, "Tibetan" ) + +#endif /* AF_CONFIG_OPTION_INDIC */ + +#ifdef AF_CONFIG_OPTION_CJK + + STYLE( hani_dflt, HANI_DFLT, + "CJKV ideographs default style", + AF_WRITING_SYSTEM_CJK, + AF_SCRIPT_HANI, + AF_BLUE_STRINGSET_HANI, + AF_COVERAGE_DEFAULT ) + +#endif /* AF_CONFIG_OPTION_CJK */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/aftypes.h b/Dependencies/freetype/freetype/src/autofit/aftypes.h new file mode 100644 index 00000000..27e4185e --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/aftypes.h @@ -0,0 +1,511 @@ +/**************************************************************************** + * + * aftypes.h + * + * Auto-fitter types (specification only). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************* + * + * The auto-fitter is a complete rewrite of the old auto-hinter. + * Its main feature is the ability to differentiate between different + * writing systems and scripts in order to apply specific rules. + * + * The code has also been compartmentalized into several entities that + * should make algorithmic experimentation easier than with the old + * code. + * + *************************************************************************/ + + +#ifndef AFTYPES_H_ +#define AFTYPES_H_ + + +#include +#include +#include +#include + +#include "afblue.h" + +#ifdef FT_DEBUG_AUTOFIT +#include FT_CONFIG_STANDARD_LIBRARY_H +#endif + + +FT_BEGIN_HEADER + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** D E B U G G I N G *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#ifdef FT_DEBUG_AUTOFIT + +extern int af_debug_disable_horz_hints_; +extern int af_debug_disable_vert_hints_; +extern int af_debug_disable_blue_hints_; +extern void* af_debug_hints_; + +#endif /* FT_DEBUG_AUTOFIT */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** U T I L I T Y S T U F F *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AF_WidthRec_ + { + FT_Pos org; /* original position/width in font units */ + FT_Pos cur; /* current/scaled position/width in device subpixels */ + FT_Pos fit; /* current/fitted position/width in device subpixels */ + + } AF_WidthRec, *AF_Width; + + + FT_LOCAL( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ); + + FT_LOCAL( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width widths, + FT_Pos threshold ); + + + /* + * opaque handle to glyph-specific hints -- see `afhints.h' for more + * details + */ + typedef struct AF_GlyphHintsRec_* AF_GlyphHints; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S C A L E R S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * A scaler models the target pixel device that will receive the + * auto-hinted glyph image. + */ + +#define AF_SCALER_FLAG_NO_HORIZONTAL 1U /* disable horizontal hinting */ +#define AF_SCALER_FLAG_NO_VERTICAL 2U /* disable vertical hinting */ +#define AF_SCALER_FLAG_NO_ADVANCE 4U /* disable advance hinting */ + + + typedef struct AF_ScalerRec_ + { + FT_Face face; /* source font face */ + FT_Fixed x_scale; /* from font units to 1/64 device pixels */ + FT_Fixed y_scale; /* from font units to 1/64 device pixels */ + FT_Pos x_delta; /* in 1/64 device pixels */ + FT_Pos y_delta; /* in 1/64 device pixels */ + FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */ + FT_UInt32 flags; /* additional control flags, see above */ + + } AF_ScalerRec, *AF_Scaler; + + +#define AF_SCALER_EQUAL_SCALES( a, b ) \ + ( (a)->x_scale == (b)->x_scale && \ + (a)->y_scale == (b)->y_scale && \ + (a)->x_delta == (b)->x_delta && \ + (a)->y_delta == (b)->y_delta ) + + + typedef struct AF_StyleMetricsRec_* AF_StyleMetrics; + + /* + * This function parses an FT_Face to compute global metrics for + * a specific style. + */ + typedef FT_Error + (*AF_WritingSystem_InitMetricsFunc)( AF_StyleMetrics metrics, + FT_Face face ); + + typedef void + (*AF_WritingSystem_ScaleMetricsFunc)( AF_StyleMetrics metrics, + AF_Scaler scaler ); + + typedef void + (*AF_WritingSystem_DoneMetricsFunc)( AF_StyleMetrics metrics ); + + typedef void + (*AF_WritingSystem_GetStdWidthsFunc)( AF_StyleMetrics metrics, + FT_Pos* stdHW, + FT_Pos* stdVW ); + + + typedef FT_Error + (*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints hints, + AF_StyleMetrics metrics ); + + typedef FT_Error + (*AF_WritingSystem_ApplyHintsFunc)( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** W R I T I N G S Y S T E M S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * For the auto-hinter, a writing system consists of multiple scripts that + * can be handled similarly *in a typographical way*; the relationship is + * not based on history. For example, both the Greek and the unrelated + * Armenian scripts share the same features like ascender, descender, + * x-height, etc. Essentially, a writing system is covered by a + * submodule of the auto-fitter; it contains + * + * - a specific global analyzer that computes global metrics specific to + * the script (based on script-specific characters to identify ascender + * height, x-height, etc.), + * + * - a specific glyph analyzer that computes segments and edges for each + * glyph covered by the script, + * + * - a specific grid-fitting algorithm that distorts the scaled glyph + * outline according to the results of the glyph analyzer. + */ + +#undef WRITING_SYSTEM +#define WRITING_SYSTEM( ws, WS ) \ + AF_WRITING_SYSTEM_ ## WS, + + /* The list of known writing systems. */ + typedef enum AF_WritingSystem_ + { + +#include "afws-iter.h" + + AF_WRITING_SYSTEM_MAX /* do not remove */ + + } AF_WritingSystem; + + + typedef struct AF_WritingSystemClassRec_ + { + AF_WritingSystem writing_system; + + FT_Offset style_metrics_size; + AF_WritingSystem_InitMetricsFunc style_metrics_init; + AF_WritingSystem_ScaleMetricsFunc style_metrics_scale; + AF_WritingSystem_DoneMetricsFunc style_metrics_done; + AF_WritingSystem_GetStdWidthsFunc style_metrics_getstdw; + + AF_WritingSystem_InitHintsFunc style_hints_init; + AF_WritingSystem_ApplyHintsFunc style_hints_apply; + + } AF_WritingSystemClassRec; + + typedef const AF_WritingSystemClassRec* AF_WritingSystemClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S C R I P T S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Each script is associated with two sets of Unicode ranges to test + * whether the font face supports the script, and which non-base + * characters the script contains. + * + * We use four-letter script tags from the OpenType specification, + * extended by `NONE', which indicates `no script'. + */ + +#undef SCRIPT +#define SCRIPT( s, S, d, h, H, ss ) \ + AF_SCRIPT_ ## S, + + /* The list of known scripts. */ + typedef enum AF_Script_ + { + +#include "afscript.h" + + AF_SCRIPT_MAX /* do not remove */ + + } AF_Script; + + + typedef struct AF_Script_UniRangeRec_ + { + FT_UInt32 first; + FT_UInt32 last; + + } AF_Script_UniRangeRec; + +#define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) } + + typedef const AF_Script_UniRangeRec* AF_Script_UniRange; + + + typedef struct AF_ScriptClassRec_ + { + AF_Script script; + + /* last element in the ranges must be { 0, 0 } */ + AF_Script_UniRange script_uni_ranges; + AF_Script_UniRange script_uni_nonbase_ranges; + + FT_Bool top_to_bottom_hinting; + + const char* standard_charstring; /* for default width and height */ + + } AF_ScriptClassRec; + + typedef const AF_ScriptClassRec* AF_ScriptClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** C O V E R A G E S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * Usually, a font contains more glyphs than can be addressed by its + * character map. + * + * In the PostScript font world, encoding vectors specific to a given + * task are used to select such glyphs, and these glyphs can be often + * recognized by having a suffix in its glyph names. For example, a + * superscript glyph `A' might be called `A.sup'. Unfortunately, this + * naming scheme is not standardized and thus unusable for us. + * + * In the OpenType world, a better solution was invented, namely + * `features', which cleanly separate a character's input encoding from + * the corresponding glyph's appearance, and which don't use glyph names + * at all. For our purposes, and slightly generalized, an OpenType + * feature is a name of a mapping that maps character codes to + * non-standard glyph indices (features get used for other things also). + * For example, the `sups' feature provides superscript glyphs, thus + * mapping character codes like `A' or `B' to superscript glyph + * representation forms. How this mapping happens is completely + * uninteresting to us. + * + * For the auto-hinter, a `coverage' represents all glyphs of an OpenType + * feature collected in a set (as listed below) that can be hinted + * together. To continue the above example, superscript glyphs must not + * be hinted together with normal glyphs because the blue zones + * completely differ. + * + * Note that FreeType itself doesn't compute coverages; it only provides + * the glyphs addressable by the default Unicode character map. Instead, + * we use the HarfBuzz library (if available), which has many functions + * exactly for this purpose. + * + * AF_COVERAGE_DEFAULT is special: It should cover everything that isn't + * listed separately (including the glyphs addressable by the character + * map). In case HarfBuzz isn't available, it exactly covers the glyphs + * addressable by the character map. + * + */ + +#undef COVERAGE +#define COVERAGE( name, NAME, description, \ + tag1, tag2, tag3, tag4 ) \ + AF_COVERAGE_ ## NAME, + + + typedef enum AF_Coverage_ + { +#include "afcover.h" + + AF_COVERAGE_DEFAULT + + } AF_Coverage; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S T Y L E S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * The topmost structure for modelling the auto-hinter glyph input data + * is a `style class', grouping everything together. + */ + +#undef STYLE +#define STYLE( s, S, d, ws, sc, ss, c ) \ + AF_STYLE_ ## S, + + /* The list of known styles. */ + typedef enum AF_Style_ + { + +#include "afstyles.h" + + AF_STYLE_MAX /* do not remove */ + + } AF_Style; + + + typedef struct AF_StyleClassRec_ + { + AF_Style style; + + AF_WritingSystem writing_system; + AF_Script script; + AF_Blue_Stringset blue_stringset; + AF_Coverage coverage; + + } AF_StyleClassRec; + + typedef const AF_StyleClassRec* AF_StyleClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** S T Y L E M E T R I C S *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + + /* This is the main structure that combines everything. Autofit modules */ + /* specific to writing systems derive their structures from it, for */ + /* example `AF_LatinMetrics'. */ + + typedef struct AF_StyleMetricsRec_ + { + AF_StyleClass style_class; + AF_ScalerRec scaler; + FT_Bool digits_have_same_width; + + AF_FaceGlobals globals; /* to access properties */ + + } AF_StyleMetricsRec; + + +#define AF_HINTING_BOTTOM_TO_TOP 0 +#define AF_HINTING_TOP_TO_BOTTOM 1 + + + /* Declare and define vtables for classes */ +#define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \ + FT_CALLBACK_TABLE const AF_WritingSystemClassRec \ + writing_system_class; + +#define AF_DEFINE_WRITING_SYSTEM_CLASS( \ + writing_system_class, \ + system, \ + m_size, \ + m_init, \ + m_scale, \ + m_done, \ + m_stdw, \ + h_init, \ + h_apply ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_WritingSystemClassRec writing_system_class = \ + { \ + system, \ + \ + m_size, \ + \ + m_init, \ + m_scale, \ + m_done, \ + m_stdw, \ + \ + h_init, \ + h_apply \ + }; + + +#define AF_DECLARE_SCRIPT_CLASS( script_class ) \ + FT_CALLBACK_TABLE const AF_ScriptClassRec \ + script_class; + +#define AF_DEFINE_SCRIPT_CLASS( \ + script_class, \ + script, \ + ranges, \ + nonbase_ranges, \ + top_to_bottom, \ + std_charstring ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_ScriptClassRec script_class = \ + { \ + script, \ + ranges, \ + nonbase_ranges, \ + top_to_bottom, \ + std_charstring, \ + }; + + +#define AF_DECLARE_STYLE_CLASS( style_class ) \ + FT_CALLBACK_TABLE const AF_StyleClassRec \ + style_class; + +#define AF_DEFINE_STYLE_CLASS( \ + style_class, \ + style, \ + writing_system, \ + script, \ + blue_stringset, \ + coverage ) \ + FT_CALLBACK_TABLE_DEF \ + const AF_StyleClassRec style_class = \ + { \ + style, \ + writing_system, \ + script, \ + blue_stringset, \ + coverage \ + }; + +/* */ + + +FT_END_HEADER + +#endif /* AFTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afws-decl.h b/Dependencies/freetype/freetype/src/autofit/afws-decl.h new file mode 100644 index 00000000..b78745af --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afws-decl.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * + * afws-decl.h + * + * Auto-fitter writing system declarations (specification only). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFWS_DECL_H_ +#define AFWS_DECL_H_ + + /* Since preprocessor directives can't create other preprocessor */ + /* directives, we have to include the header files manually. */ + +#include "afdummy.h" +#include "aflatin.h" +#include "afcjk.h" +#include "afindic.h" + +#endif /* AFWS_DECL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/afws-iter.h b/Dependencies/freetype/freetype/src/autofit/afws-iter.h new file mode 100644 index 00000000..c86d609a --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/afws-iter.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * afws-iter.h + * + * Auto-fitter writing systems iterator (specification only). + * + * Copyright (C) 2013-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* This header may be included multiple times. */ + /* Define `WRITING_SYSTEM' as needed. */ + + + /* Add new writing systems here. The arguments are the writing system */ + /* name in lowercase and uppercase, respectively. */ + + WRITING_SYSTEM( dummy, DUMMY ) + WRITING_SYSTEM( latin, LATIN ) + WRITING_SYSTEM( cjk, CJK ) + WRITING_SYSTEM( indic, INDIC ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/autofit.c b/Dependencies/freetype/freetype/src/autofit/autofit.c new file mode 100644 index 00000000..de5ec7c7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/autofit.c @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * autofit.c + * + * Auto-fitter module (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ft-hb.c" +#include "afblue.c" +#include "afcjk.c" +#include "afdummy.c" +#include "afglobal.c" +#include "afhints.c" +#include "afindic.c" +#include "aflatin.c" +#include "afloader.c" +#include "afmodule.c" +#include "afranges.c" +#include "afshaper.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/ft-hb.c b/Dependencies/freetype/freetype/src/autofit/ft-hb.c new file mode 100644 index 00000000..71aee045 --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/ft-hb.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#include +#include + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include "ft-hb.h" + +/* The following three functions are a more or less verbatim + * copy of corresponding HarfBuzz code from hb-ft.cc + */ + +static hb_blob_t * +hb_ft_reference_table_ (hb_face_t *face, hb_tag_t tag, void *user_data) +{ + FT_Face ft_face = (FT_Face) user_data; + FT_Byte *buffer; + FT_ULong length = 0; + FT_Error error; + + FT_UNUSED (face); + + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); + if (error) + return NULL; + + buffer = (FT_Byte *) ft_smalloc (length); + if (!buffer) + return NULL; + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); + if (error) + { + free (buffer); + return NULL; + } + + return hb_blob_create ((const char *) buffer, length, + HB_MEMORY_MODE_WRITABLE, + buffer, ft_sfree); +} + +static hb_face_t * +hb_ft_face_create_ (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_face_t *face; + + if (!ft_face->stream->read) { + hb_blob_t *blob; + + blob = hb_blob_create ((const char *) ft_face->stream->base, + (unsigned int) ft_face->stream->size, + HB_MEMORY_MODE_READONLY, + ft_face, destroy); + face = hb_face_create (blob, ft_face->face_index); + hb_blob_destroy (blob); + } else { + face = hb_face_create_for_tables (hb_ft_reference_table_, ft_face, destroy); + } + + hb_face_set_index (face, ft_face->face_index); + hb_face_set_upem (face, ft_face->units_per_EM); + + return face; +} + +FT_LOCAL_DEF(hb_font_t *) +hb_ft_font_create_ (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_font_t *font; + hb_face_t *face; + + face = hb_ft_face_create_ (ft_face, destroy); + font = hb_font_create (face); + hb_face_destroy (face); + return font; +} + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* ANSI C doesn't like empty source files */ +typedef int ft_hb_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* END */ diff --git a/Dependencies/freetype/freetype/src/autofit/ft-hb.h b/Dependencies/freetype/freetype/src/autofit/ft-hb.h new file mode 100644 index 00000000..92a5774b --- /dev/null +++ b/Dependencies/freetype/freetype/src/autofit/ft-hb.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#ifndef FT_HB_H +#define FT_HB_H + +#include + +#include +#include + + +FT_BEGIN_HEADER + +FT_LOCAL(hb_font_t *) +hb_ft_font_create_ (FT_Face ft_face, + hb_destroy_func_t destroy); + + +FT_END_HEADER + +#endif /* FT_HB_H */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftadvanc.c b/Dependencies/freetype/freetype/src/base/ftadvanc.c new file mode 100644 index 00000000..717f7d08 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftadvanc.c @@ -0,0 +1,174 @@ +/**************************************************************************** + * + * ftadvanc.c + * + * Quick computation of advance widths (body). + * + * Copyright (C) 2008-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include + + + static FT_Error + ft_face_scale_advances_( FT_Face face, + FT_Fixed* advances, + FT_UInt count, + FT_Int32 flags ) + { + FT_Fixed scale; + FT_UInt nn; + + + if ( flags & FT_LOAD_NO_SCALE ) + return FT_Err_Ok; + + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + scale = face->size->metrics.y_scale; + else + scale = face->size->metrics.x_scale; + + /* this must be the same scaling as to get linear{Hori,Vert}Advance */ + /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */ + + for ( nn = 0; nn < count; nn++ ) + advances[nn] = FT_MulDiv( advances[nn], scale, 64 ); + + return FT_Err_Ok; + } + + + /* at the moment, we can perform fast advance retrieval only in */ + /* the following cases: */ + /* */ + /* - unscaled load */ + /* - unhinted load */ + /* - light-hinted load */ + /* - if a variations font, it must have an `HVAR' or `VVAR' */ + /* table (thus the old MM or GX fonts don't qualify; this */ + /* gets checked by the driver-specific functions) */ + +#define LOAD_ADVANCE_FAST_CHECK( face, flags ) \ + ( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) || \ + FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT ) + + + /* documentation is in ftadvanc.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 flags, + FT_Fixed *padvance ) + { + FT_Face_GetAdvancesFunc func; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !padvance ) + return FT_THROW( Invalid_Argument ); + + if ( gindex >= (FT_UInt)face->num_glyphs ) + return FT_THROW( Invalid_Glyph_Index ); + + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) ) + { + FT_Error error; + + + error = func( face, gindex, 1, flags, padvance ); + if ( !error ) + return ft_face_scale_advances_( face, padvance, 1, flags ); + + if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) + return error; + } + + return FT_Get_Advances( face, gindex, 1, flags, padvance ); + } + + + /* documentation is in ftadvanc.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed *padvances ) + { + FT_Error error = FT_Err_Ok; + + FT_Face_GetAdvancesFunc func; + + FT_UInt num, end, nn; + FT_Int factor; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !padvances ) + return FT_THROW( Invalid_Argument ); + + num = (FT_UInt)face->num_glyphs; + end = start + count; + if ( start >= num || end < start || end > num ) + return FT_THROW( Invalid_Glyph_Index ); + + if ( count == 0 ) + return FT_Err_Ok; + + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) ) + { + error = func( face, start, count, flags, padvances ); + if ( !error ) + return ft_face_scale_advances_( face, padvances, count, flags ); + + if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) + return error; + } + + error = FT_Err_Ok; + + if ( flags & FT_ADVANCE_FLAG_FAST_ONLY ) + return FT_THROW( Unimplemented_Feature ); + + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024; + for ( nn = 0; nn < count; nn++ ) + { + error = FT_Load_Glyph( face, start + nn, flags ); + if ( error ) + break; + + /* scale from 26.6 to 16.16, unless NO_SCALE was requested */ + padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? face->glyph->advance.y * factor + : face->glyph->advance.x * factor; + } + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftbase.c b/Dependencies/freetype/freetype/src/base/ftbase.c new file mode 100644 index 00000000..50805cce --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftbase.c @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ftbase.c + * + * Single object library component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftadvanc.c" +#include "ftcalc.c" +#include "ftcolor.c" +#include "ftdbgmem.c" +#include "fterrors.c" +#include "ftfntfmt.c" +#include "ftgloadr.c" +#include "fthash.c" +#include "ftlcdfil.c" +#include "ftmac.c" +#include "ftobjs.c" +#include "ftoutln.c" +#include "ftpsprop.c" +#include "ftrfork.c" +#include "ftsnames.c" +#include "ftstream.c" +#include "fttrigon.c" +#include "ftutil.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftbase.h b/Dependencies/freetype/freetype/src/base/ftbase.h new file mode 100644 index 00000000..1d98b26d --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftbase.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * + * ftbase.h + * + * Private functions used in the `base' module (specification). + * + * Copyright (C) 2008-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTBASE_H_ +#define FTBASE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_GLYPH( ft_bitmap_glyph_class ) + FT_DECLARE_GLYPH( ft_outline_glyph_class ) + FT_DECLARE_GLYPH( ft_svg_glyph_class ) + + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + + /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */ + /* see https://support.microsoft.com/en-us/kb/130437 */ +#define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL + + + /* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */ + /* font, and try to load a face specified by the face_index. */ + FT_LOCAL( FT_Error ) + open_face_PS_from_sfnt_stream( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter *params, + FT_Face *aface ); + + + /* Create a new FT_Face given a buffer and a driver name. */ + /* From ftmac.c. */ + FT_LOCAL( FT_Error ) + open_face_from_buffer( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Long face_index, + const char* driver_name, + FT_Face *aface ); + + +#if defined( FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK ) && \ + !defined( FT_MACINTOSH ) + /* Mac OS X/Darwin kernel often changes recommended method to access */ + /* the resource fork and older methods makes the kernel issue the */ + /* warning of deprecated method. To calm it down, the methods based */ + /* on Darwin VFS should be grouped and skip the rest methods after */ + /* the case the resource is opened but found to lack a font in it. */ + FT_LOCAL( FT_Bool ) + ft_raccess_rule_by_darwin_vfs( FT_Library library, FT_UInt rule_index ); +#endif + +#endif /* FT_CONFIG_OPTION_MAC_FONTS */ + + +FT_END_HEADER + +#endif /* FTBASE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftbbox.c b/Dependencies/freetype/freetype/src/base/ftbbox.c new file mode 100644 index 00000000..d6aa5d56 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftbbox.c @@ -0,0 +1,542 @@ +/**************************************************************************** + * + * ftbbox.c + * + * FreeType bbox computation (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component has a _single_ role: to compute exact outline bounding + * boxes. + * + */ + + +#include + +#include +#include +#include +#include +#include + + + typedef struct TBBox_Rec_ + { + FT_Vector last; + FT_BBox bbox; + + } TBBox_Rec; + + +#define FT_UPDATE_BBOX( p, bbox ) \ + FT_BEGIN_STMNT \ + if ( p->x < bbox.xMin ) \ + bbox.xMin = p->x; \ + if ( p->x > bbox.xMax ) \ + bbox.xMax = p->x; \ + if ( p->y < bbox.yMin ) \ + bbox.yMin = p->y; \ + if ( p->y > bbox.yMax ) \ + bbox.yMax = p->y; \ + FT_END_STMNT + +#define CHECK_X( p, bbox ) \ + ( p->x < bbox.xMin || p->x > bbox.xMax ) + +#define CHECK_Y( p, bbox ) \ + ( p->y < bbox.yMin || p->y > bbox.yMax ) + + + /************************************************************************** + * + * @Function: + * BBox_Move_To + * + * @Description: + * This function is used as a `move_to' emitter during + * FT_Outline_Decompose(). It simply records the destination point + * in `user->last'. We also update bbox in case contour starts with + * an implicit `on' point. + * + * @Input: + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * A pointer to the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + */ + FT_CALLBACK_DEF( int ) + BBox_Move_To( const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + FT_UPDATE_BBOX( to, user->bbox ); + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Line_To + * + * @Description: + * This function is used as a `line_to' emitter during + * FT_Outline_Decompose(). It simply records the destination point + * in `user->last'; no further computations are necessary because + * bbox already contains both explicit ends of the line segment. + * + * @Input: + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * A pointer to the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + */ + FT_CALLBACK_DEF( int ) + BBox_Line_To( const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Conic_Check + * + * @Description: + * Find the extrema of a 1-dimensional conic Bezier curve and update + * a bounding range. This version uses direct computation, as it + * doesn't need square roots. + * + * @Input: + * y1 :: + * The start coordinate. + * + * y2 :: + * The coordinate of the control point. + * + * y3 :: + * The end coordinate. + * + * @InOut: + * min :: + * The address of the current minimum. + * + * max :: + * The address of the current maximum. + */ + static void + BBox_Conic_Check( FT_Pos y1, + FT_Pos y2, + FT_Pos y3, + FT_Pos* min, + FT_Pos* max ) + { + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. It finds a local extremum */ + /* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */ + /* Or, offsetting from y2, we get */ + + y1 -= y2; + y3 -= y2; + y2 += FT_MulDiv( y1, y3, y1 + y3 ); + + if ( y2 < *min ) + *min = y2; + if ( y2 > *max ) + *max = y2; + } + + + /************************************************************************** + * + * @Function: + * BBox_Conic_To + * + * @Description: + * This function is used as a `conic_to' emitter during + * FT_Outline_Decompose(). It checks a conic Bezier curve with the + * current bounding box, and computes its extrema if necessary to + * update it. + * + * @Input: + * control :: + * A pointer to a control point. + * + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * The address of the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + * + * @Note: + * In the case of a non-monotonous arc, we compute directly the + * extremum coordinates, as it is sufficiently fast. + */ + FT_CALLBACK_DEF( int ) + BBox_Conic_To( const FT_Vector* control, + const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + /* in case `to' is implicit and not included in bbox yet */ + FT_UPDATE_BBOX( to, user->bbox ); + + if ( CHECK_X( control, user->bbox ) ) + BBox_Conic_Check( user->last.x, + control->x, + to->x, + &user->bbox.xMin, + &user->bbox.xMax ); + + if ( CHECK_Y( control, user->bbox ) ) + BBox_Conic_Check( user->last.y, + control->y, + to->y, + &user->bbox.yMin, + &user->bbox.yMax ); + + user->last = *to; + + return 0; + } + + + /************************************************************************** + * + * @Function: + * BBox_Cubic_Check + * + * @Description: + * Find the extrema of a 1-dimensional cubic Bezier curve and + * update a bounding range. This version uses iterative splitting + * because it is faster than the exact solution with square roots. + * + * @Input: + * p1 :: + * The start coordinate. + * + * p2 :: + * The coordinate of the first control point. + * + * p3 :: + * The coordinate of the second control point. + * + * p4 :: + * The end coordinate. + * + * @InOut: + * min :: + * The address of the current minimum. + * + * max :: + * The address of the current maximum. + */ + static FT_Pos + cubic_peak( FT_Pos q1, + FT_Pos q2, + FT_Pos q3, + FT_Pos q4 ) + { + FT_Pos peak = 0; + FT_Int shift; + + + /* This function finds a peak of a cubic segment if it is above 0 */ + /* using iterative bisection of the segment, or returns 0. */ + /* The fixed-point arithmetic of bisection is inherently stable */ + /* but may loose accuracy in the two lowest bits. To compensate, */ + /* we upscale the segment if there is room. Large values may need */ + /* to be downscaled to avoid overflows during bisection. */ + /* It is called with either q2 or q3 positive, which is necessary */ + /* for the peak to exist and avoids undefined FT_MSB. */ + + shift = 27 - FT_MSB( (FT_UInt32)( FT_ABS( q1 ) | + FT_ABS( q2 ) | + FT_ABS( q3 ) | + FT_ABS( q4 ) ) ); + + if ( shift > 0 ) + { + /* upscaling too much just wastes time */ + if ( shift > 2 ) + shift = 2; + + q1 *= 1 << shift; + q2 *= 1 << shift; + q3 *= 1 << shift; + q4 *= 1 << shift; + } + else + { + q1 >>= -shift; + q2 >>= -shift; + q3 >>= -shift; + q4 >>= -shift; + } + + /* for a peak to exist above 0, the cubic segment must have */ + /* at least one of its control off-points above 0. */ + while ( q2 > 0 || q3 > 0 ) + { + /* determine which half contains the maximum and split */ + if ( q1 + q2 > q3 + q4 ) /* first half */ + { + q4 = q4 + q3; + q3 = q3 + q2; + q2 = q2 + q1; + q4 = q4 + q3; + q3 = q3 + q2; + q4 = ( q4 + q3 ) >> 3; + q3 = q3 >> 2; + q2 = q2 >> 1; + } + else /* second half */ + { + q1 = q1 + q2; + q2 = q2 + q3; + q3 = q3 + q4; + q1 = q1 + q2; + q2 = q2 + q3; + q1 = ( q1 + q2 ) >> 3; + q2 = q2 >> 2; + q3 = q3 >> 1; + } + + /* check whether either end reached the maximum */ + if ( q1 == q2 && q1 >= q3 ) + { + peak = q1; + break; + } + if ( q3 == q4 && q2 <= q4 ) + { + peak = q4; + break; + } + } + + if ( shift > 0 ) + peak >>= shift; + else + peak <<= -shift; + + return peak; + } + + + static void + BBox_Cubic_Check( FT_Pos p1, + FT_Pos p2, + FT_Pos p3, + FT_Pos p4, + FT_Pos* min, + FT_Pos* max ) + { + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. So at least one of the */ + /* conditions below holds and cubic_peak is called with at least one */ + /* non-zero argument. */ + + if ( p2 > *max || p3 > *max ) + *max += cubic_peak( p1 - *max, p2 - *max, p3 - *max, p4 - *max ); + + /* now flip the signs to update the minimum */ + if ( p2 < *min || p3 < *min ) + *min -= cubic_peak( *min - p1, *min - p2, *min - p3, *min - p4 ); + } + + + /************************************************************************** + * + * @Function: + * BBox_Cubic_To + * + * @Description: + * This function is used as a `cubic_to' emitter during + * FT_Outline_Decompose(). It checks a cubic Bezier curve with the + * current bounding box, and computes its extrema if necessary to + * update it. + * + * @Input: + * control1 :: + * A pointer to the first control point. + * + * control2 :: + * A pointer to the second control point. + * + * to :: + * A pointer to the destination vector. + * + * @InOut: + * user :: + * The address of the current walk context. + * + * @Return: + * Always 0. Needed for the interface only. + * + * @Note: + * In the case of a non-monotonous arc, we don't compute directly + * extremum coordinates, we subdivide instead. + */ + FT_CALLBACK_DEF( int ) + BBox_Cubic_To( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user_ ) + { + TBBox_Rec* user = (TBBox_Rec*)user_; + + + /* We don't need to check `to' since it is always an on-point, */ + /* thus within the bbox. Only segments with an off-point outside */ + /* the bbox can possibly reach new extreme values. */ + + if ( CHECK_X( control1, user->bbox ) || + CHECK_X( control2, user->bbox ) ) + BBox_Cubic_Check( user->last.x, + control1->x, + control2->x, + to->x, + &user->bbox.xMin, + &user->bbox.xMax ); + + if ( CHECK_Y( control1, user->bbox ) || + CHECK_Y( control2, user->bbox ) ) + BBox_Cubic_Check( user->last.y, + control1->y, + control2->y, + to->y, + &user->bbox.yMin, + &user->bbox.yMax ); + + user->last = *to; + + return 0; + } + + + FT_DEFINE_OUTLINE_FUNCS( + bbox_interface, + + (FT_Outline_MoveTo_Func) BBox_Move_To, /* move_to */ + (FT_Outline_LineTo_Func) BBox_Line_To, /* line_to */ + (FT_Outline_ConicTo_Func)BBox_Conic_To, /* conic_to */ + (FT_Outline_CubicTo_Func)BBox_Cubic_To, /* cubic_to */ + 0, /* shift */ + 0 /* delta */ + ) + + + /* documentation is in ftbbox.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ) + { + FT_BBox cbox = { 0x7FFFFFFFL, 0x7FFFFFFFL, + -0x7FFFFFFFL, -0x7FFFFFFFL }; + FT_BBox bbox = { 0x7FFFFFFFL, 0x7FFFFFFFL, + -0x7FFFFFFFL, -0x7FFFFFFFL }; + FT_Vector* vec; + FT_UShort n; + + + if ( !abbox ) + return FT_THROW( Invalid_Argument ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* if outline is empty, return (0,0,0,0) */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + { + abbox->xMin = abbox->xMax = 0; + abbox->yMin = abbox->yMax = 0; + + return 0; + } + + /* We compute the control box as well as the bounding box of */ + /* all `on' points in the outline. Then, if the two boxes */ + /* coincide, we exit immediately. */ + + vec = outline->points; + + for ( n = 0; n < outline->n_points; n++ ) + { + FT_UPDATE_BBOX( vec, cbox ); + + if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON ) + FT_UPDATE_BBOX( vec, bbox ); + + vec++; + } + + /* test two boxes for equality */ + if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax || + cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax ) + { + /* the two boxes are different, now walk over the outline to */ + /* get the Bezier arc extrema. */ + + FT_Error error; + TBBox_Rec user; + + + user.bbox = bbox; + + error = FT_Outline_Decompose( outline, &bbox_interface, &user ); + if ( error ) + return error; + + *abbox = user.bbox; + } + else + *abbox = bbox; + + return FT_Err_Ok; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftbdf.c b/Dependencies/freetype/freetype/src/base/ftbdf.c new file mode 100644 index 00000000..d8e9fd7e --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftbdf.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * ftbdf.c + * + * FreeType API for accessing BDF-specific strings (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include + + + /* documentation is in ftbdf.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + FT_Error error; + const char* encoding = NULL; + const char* registry = NULL; + + FT_Service_BDF service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, BDF ); + + if ( service && service->get_charset_id ) + error = service->get_charset_id( face, &encoding, ®istry ); + else + error = FT_THROW( Invalid_Argument ); + + if ( acharset_encoding ) + *acharset_encoding = encoding; + + if ( acharset_registry ) + *acharset_registry = registry; + + return error; + } + + + /* documentation is in ftbdf.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + FT_Error error; + + FT_Service_BDF service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !aproperty ) + return FT_THROW( Invalid_Argument ); + + aproperty->type = BDF_PROPERTY_TYPE_NONE; + + FT_FACE_FIND_SERVICE( face, service, BDF ); + + if ( service && service->get_property ) + error = service->get_property( face, prop_name, aproperty ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftbitmap.c b/Dependencies/freetype/freetype/src/base/ftbitmap.c new file mode 100644 index 00000000..4be14567 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftbitmap.c @@ -0,0 +1,1144 @@ +/**************************************************************************** + * + * ftbitmap.c + * + * FreeType utility functions for bitmaps (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bitmap + + + static + const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL }; + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( void ) + FT_Bitmap_Init( FT_Bitmap *abitmap ) + { + if ( abitmap ) + *abitmap = null_bitmap; + } + + + /* deprecated function name; retained for ABI compatibility */ + + FT_EXPORT_DEF( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ) + { + if ( abitmap ) + *abitmap = null_bitmap; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target) + { + FT_Memory memory; + FT_Error error = FT_Err_Ok; + FT_Int pitch; + FT_Int flip; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !source || !target ) + return FT_THROW( Invalid_Argument ); + + if ( source == target ) + return FT_Err_Ok; + + flip = ( source->pitch < 0 && target->pitch > 0 ) || + ( source->pitch > 0 && target->pitch < 0 ); + + memory = library->memory; + FT_FREE( target->buffer ); + + *target = *source; + + if ( flip ) + target->pitch = -target->pitch; + + if ( !source->buffer ) + return FT_Err_Ok; + + pitch = source->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + FT_MEM_QALLOC_MULT( target->buffer, target->rows, pitch ); + + if ( !error ) + { + if ( flip ) + { + /* take care of bitmap flow */ + FT_UInt i; + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + + + t += (FT_ULong)pitch * ( target->rows - 1 ); + + for ( i = target->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, pitch ); + + s += pitch; + t -= pitch; + } + } + else + FT_MEM_COPY( target->buffer, source->buffer, + (FT_Long)source->rows * pitch ); + } + + return error; + } + + + /* Enlarge `bitmap' horizontally and vertically by `xpixels' */ + /* and `ypixels', respectively. */ + + static FT_Error + ft_bitmap_assure_buffer( FT_Memory memory, + FT_Bitmap* bitmap, + FT_UInt xpixels, + FT_UInt ypixels ) + { + FT_Error error; + unsigned int pitch; + unsigned int new_pitch; + FT_UInt bpp; + FT_UInt width, height; + unsigned char* buffer = NULL; + + + width = bitmap->width; + height = bitmap->rows; + pitch = (unsigned int)FT_ABS( bitmap->pitch ); + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + bpp = 1; + new_pitch = ( width + xpixels + 7 ) >> 3; + break; + case FT_PIXEL_MODE_GRAY2: + bpp = 2; + new_pitch = ( width + xpixels + 3 ) >> 2; + break; + case FT_PIXEL_MODE_GRAY4: + bpp = 4; + new_pitch = ( width + xpixels + 1 ) >> 1; + break; + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + bpp = 8; + new_pitch = width + xpixels; + break; + default: + return FT_THROW( Invalid_Glyph_Format ); + } + + /* if no need to allocate memory */ + if ( ypixels == 0 && new_pitch <= pitch ) + { + /* zero the padding */ + FT_UInt bit_width = pitch * 8; + FT_UInt bit_last = ( width + xpixels ) * bpp; + + + if ( bit_last < bit_width ) + { + FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); + FT_Byte* end = bitmap->buffer + pitch; + FT_UInt shift = bit_last & 7; + FT_UInt mask = 0xFF00U >> shift; + FT_UInt count = height; + + + for ( ; count > 0; count--, line += pitch, end += pitch ) + { + FT_Byte* write = line; + + + if ( shift > 0 ) + { + write[0] = (FT_Byte)( write[0] & mask ); + write++; + } + if ( write < end ) + FT_MEM_ZERO( write, end - write ); + } + } + + return FT_Err_Ok; + } + + /* otherwise allocate new buffer */ + if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) ) + return error; + + /* new rows get added at the top of the bitmap, */ + /* thus take care of the flow direction */ + if ( bitmap->pitch > 0 ) + { + FT_UInt len = ( width * bpp + 7 ) >> 3; + + unsigned char* in = bitmap->buffer; + unsigned char* out = buffer; + + unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; + unsigned int delta = new_pitch - len; + + + FT_MEM_ZERO( out, new_pitch * ypixels ); + out += new_pitch * ypixels; + + while ( in < limit ) + { + FT_MEM_COPY( out, in, len ); + in += pitch; + out += len; + + /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */ + /* consequently, we have to manually zero out the remaining bytes */ + FT_MEM_ZERO( out, delta ); + out += delta; + } + } + else + { + FT_UInt len = ( width * bpp + 7 ) >> 3; + + unsigned char* in = bitmap->buffer; + unsigned char* out = buffer; + + unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; + unsigned int delta = new_pitch - len; + + + while ( in < limit ) + { + FT_MEM_COPY( out, in, len ); + in += pitch; + out += len; + + FT_MEM_ZERO( out, delta ); + out += delta; + } + + FT_MEM_ZERO( out, new_pitch * ypixels ); + } + + FT_FREE( bitmap->buffer ); + bitmap->buffer = buffer; + + /* set pitch only, width and height are left untouched */ + if ( bitmap->pitch < 0 ) + bitmap->pitch = -(int)new_pitch; + else + bitmap->pitch = (int)new_pitch; + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ) + { + FT_Error error; + unsigned char* p; + FT_Int i, x, pitch; + FT_UInt y; + FT_Int xstr, ystr; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !bitmap || !bitmap->buffer ) + return FT_THROW( Invalid_Argument ); + + if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || + ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) + return FT_THROW( Invalid_Argument ); + + xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; + ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; + + if ( xstr == 0 && ystr == 0 ) + return FT_Err_Ok; + else if ( xstr < 0 || ystr < 0 ) + return FT_THROW( Invalid_Argument ); + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + { + FT_Bitmap tmp; + + + /* convert to 8bpp */ + FT_Bitmap_Init( &tmp ); + error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 ); + if ( error ) + return error; + + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + } + break; + + case FT_PIXEL_MODE_MONO: + if ( xstr > 8 ) + xstr = 8; + break; + + case FT_PIXEL_MODE_LCD: + xstr *= 3; + break; + + case FT_PIXEL_MODE_LCD_V: + ystr *= 3; + break; + + case FT_PIXEL_MODE_BGRA: + /* We don't embolden color glyphs. */ + return FT_Err_Ok; + } + + error = ft_bitmap_assure_buffer( library->memory, bitmap, + (FT_UInt)xstr, (FT_UInt)ystr ); + if ( error ) + return error; + + /* take care of bitmap flow */ + pitch = bitmap->pitch; + if ( pitch > 0 ) + p = bitmap->buffer + pitch * ystr; + else + { + pitch = -pitch; + p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 ); + } + + /* for each row */ + for ( y = 0; y < bitmap->rows; y++ ) + { + /* + * Horizontally: + * + * From the last pixel on, make each pixel or'ed with the + * `xstr' pixels before it. + */ + for ( x = pitch - 1; x >= 0; x-- ) + { + unsigned char tmp; + + + tmp = p[x]; + for ( i = 1; i <= xstr; i++ ) + { + if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) + { + p[x] |= tmp >> i; + + /* the maximum value of 8 for `xstr' comes from here */ + if ( x > 0 ) + p[x] |= p[x - 1] << ( 8 - i ); + +#if 0 + if ( p[x] == 0xFF ) + break; +#endif + } + else + { + if ( x - i >= 0 ) + { + if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) + { + p[x] = (unsigned char)( bitmap->num_grays - 1 ); + break; + } + else + { + p[x] = (unsigned char)( p[x] + p[x - i] ); + if ( p[x] == bitmap->num_grays - 1 ) + break; + } + } + else + break; + } + } + } + + /* + * Vertically: + * + * Make the above `ystr' rows or'ed with it. + */ + for ( x = 1; x <= ystr; x++ ) + { + unsigned char* q; + + + q = p - bitmap->pitch * x; + for ( i = 0; i < pitch; i++ ) + q[i] |= p[i]; + } + + p += bitmap->pitch; + } + + bitmap->width += (FT_UInt)xstr; + bitmap->rows += (FT_UInt)ystr; + + return FT_Err_Ok; + } + + + static FT_Byte + ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) + { + FT_UInt a = bgra[3]; + FT_UInt l; + + + /* Short-circuit transparent color to avoid division by zero. */ + if ( !a ) + return 0; + + /* + * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 + * coefficients for RGB channels *on the linear colors*. + * A gamma of 2.2 is fair to assume. And then, we need to + * undo the premultiplication too. + * + * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes + * + * We do the computation with integers only, applying a gamma of 2.0. + * We guarantee 32-bit arithmetic to avoid overflow but the resulting + * luminosity fits into 16 bits. + * + */ + + l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] + + 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] + + 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16; + + /* + * Final transparency can be determined as follows. + * + * - If alpha is zero, we want 0. + * - If alpha is zero and luminosity is zero, we want 255. + * - If alpha is zero and luminosity is one, we want 0. + * + * So the formula is a * (1 - l) = a - l * a. + * + * We still need to undo premultiplication by dividing l by a*a. + * + */ + + return (FT_Byte)( a - l / a ); + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + FT_Byte* s; + FT_Byte* t; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !source || !target ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + case FT_PIXEL_MODE_BGRA: + { + FT_Int width = (FT_Int)source->width; + FT_Int neg = ( target->pitch == 0 && source->pitch < 0 ) || + target->pitch < 0; + + + FT_Bitmap_Done( library, target ); + + target->pixel_mode = FT_PIXEL_MODE_GRAY; + target->rows = source->rows; + target->width = source->width; + + if ( alignment ) + { + FT_Int rem = width % alignment; + + + if ( rem ) + width = alignment > 0 ? width - rem + alignment + : width - rem - alignment; + } + + if ( FT_QALLOC_MULT( target->buffer, target->rows, width ) ) + return error; + + target->pitch = neg ? -width : width; + } + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + s = source->buffer; + t = target->buffer; + + /* take care of bitmap flow */ + if ( source->pitch < 0 ) + s -= source->pitch * (FT_Int)( source->rows - 1 ); + if ( target->pitch < 0 ) + t -= target->pitch * (FT_Int)( target->rows - 1 ); + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_UInt i; + + + target->num_grays = 2; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 3; j > 0; j-- ) + { + FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ + + + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); + tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); + tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); + tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); + tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); + tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); + tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); + tt[7] = (FT_Byte)( val & 0x01 ); + + tt += 8; + ss += 1; + } + + /* get remaining pixels (if any) */ + j = source->width & 7; + if ( j > 0 ) + { + FT_Int val = *ss; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + val <<= 1; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + { + FT_UInt width = source->width; + FT_UInt i; + + + target->num_grays = 256; + + for ( i = source->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, width ); + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY2: + { + FT_UInt i; + + + target->num_grays = 4; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 2; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); + tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); + tt[3] = (FT_Byte)( ( val & 0x03 ) ); + + ss += 1; + tt += 4; + } + + j = source->width & 3; + if ( j > 0 ) + { + FT_Int val = ss[0]; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + val <<= 2; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY4: + { + FT_UInt i; + + + target->num_grays = 16; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + /* get the full bytes */ + for ( j = source->width >> 1; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); + tt[1] = (FT_Byte)( ( val & 0x0F ) ); + + ss += 1; + tt += 2; + } + + if ( source->width & 1 ) + tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_BGRA: + { + FT_UInt i; + + + target->num_grays = 256; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_UInt j; + + + for ( j = source->width; j > 0; j-- ) + { + tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); + + ss += 4; + tt += 1; + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + default: + ; + } + + return error; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Blend( FT_Library library, + const FT_Bitmap* source_, + const FT_Vector source_offset_, + FT_Bitmap* target, + FT_Vector *atarget_offset, + FT_Color color ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + FT_Bitmap source_bitmap; + const FT_Bitmap* source; + + FT_Vector source_offset; + FT_Vector target_offset; + + FT_Bool free_source_bitmap = 0; + FT_Bool free_target_bitmap_on_error = 0; + + FT_Pos source_llx, source_lly, source_urx, source_ury; + FT_Pos target_llx, target_lly, target_urx, target_ury; + FT_Pos final_llx, final_lly, final_urx, final_ury; + + unsigned int final_rows, final_width; + long x, y; + + + if ( !library || !target || !source_ || !atarget_offset ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE || + ( target->pixel_mode == FT_PIXEL_MODE_BGRA && + target->buffer ) ) ) + return FT_THROW( Invalid_Argument ); + + if ( source_->pixel_mode == FT_PIXEL_MODE_NONE ) + return FT_Err_Ok; /* nothing to do */ + + /* pitches must have the same sign */ + if ( target->pixel_mode == FT_PIXEL_MODE_BGRA && + ( source_->pitch ^ target->pitch ) < 0 ) + return FT_THROW( Invalid_Argument ); + + if ( !( source_->width && source_->rows ) ) + return FT_Err_Ok; /* nothing to do */ + + /* assure integer pixel offsets */ + source_offset.x = FT_PIX_FLOOR( source_offset_.x ); + source_offset.y = FT_PIX_FLOOR( source_offset_.y ); + target_offset.x = FT_PIX_FLOOR( atarget_offset->x ); + target_offset.y = FT_PIX_FLOOR( atarget_offset->y ); + + /* get source bitmap dimensions */ + source_llx = source_offset.x; + if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + source_lly = source_offset.y - ( source_->rows << 6 ); + + if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + source_urx = source_llx + ( source_->width << 6 ); + source_ury = source_offset.y; + + /* get target bitmap dimensions */ + if ( target->width && target->rows ) + { + target_llx = target_offset.x; + if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + target_lly = target_offset.y - ( target->rows << 6 ); + + if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx ) + { + FT_TRACE5(( + "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" )); + return FT_THROW( Invalid_Argument ); + } + target_urx = target_llx + ( target->width << 6 ); + target_ury = target_offset.y; + } + else + { + target_llx = FT_LONG_MAX; + target_lly = FT_LONG_MAX; + target_urx = FT_LONG_MIN; + target_ury = FT_LONG_MIN; + } + + /* compute final bitmap dimensions */ + final_llx = FT_MIN( source_llx, target_llx ); + final_lly = FT_MIN( source_lly, target_lly ); + final_urx = FT_MAX( source_urx, target_urx ); + final_ury = FT_MAX( source_ury, target_ury ); + + final_width = ( final_urx - final_llx ) >> 6; + final_rows = ( final_ury - final_lly ) >> 6; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( "FT_Bitmap_Blend:\n" )); + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + source_llx / 64, source_lly / 64, + source_urx / 64, source_ury / 64, + source_->width, source_->rows )); + + if ( target->width && target->rows ) + FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + target_llx / 64, target_lly / 64, + target_urx / 64, target_ury / 64, + target->width, target->rows )); + else + FT_TRACE5(( " target bitmap: empty\n" )); + + if ( final_width && final_rows ) + FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + final_llx / 64, final_lly / 64, + final_urx / 64, final_ury / 64, + final_width, final_rows )); + else + FT_TRACE5(( " final bitmap: empty\n" )); +#endif /* FT_DEBUG_LEVEL_TRACE */ + + if ( !( final_width && final_rows ) ) + return FT_Err_Ok; /* nothing to do */ + + /* for blending, set offset vector of final bitmap */ + /* temporarily to (0,0) */ + source_llx -= final_llx; + source_lly -= final_lly; + + if ( target->width && target->rows ) + { + target_llx -= final_llx; + target_lly -= final_lly; + } + + /* set up target bitmap */ + if ( target->pixel_mode == FT_PIXEL_MODE_NONE ) + { + /* create new empty bitmap */ + target->width = final_width; + target->rows = final_rows; + target->pixel_mode = FT_PIXEL_MODE_BGRA; + target->pitch = (int)final_width * 4; + target->num_grays = 256; + + if ( FT_LONG_MAX / target->pitch < (int)target->rows ) + { + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + final_width, final_rows )); + return FT_THROW( Invalid_Argument ); + } + + if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) ) + return error; + + free_target_bitmap_on_error = 1; + } + else if ( target->width != final_width || + target->rows != final_rows ) + { + /* adjust old bitmap to enlarged size */ + int pitch, new_pitch; + + unsigned char* buffer = NULL; + + + pitch = target->pitch; + + if ( pitch < 0 ) + pitch = -pitch; + + new_pitch = (int)final_width * 4; + + if ( FT_LONG_MAX / new_pitch < (int)final_rows ) + { + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + final_width, final_rows )); + return FT_THROW( Invalid_Argument ); + } + + /* TODO: provide an in-buffer solution for large bitmaps */ + /* to avoid allocation of a new buffer */ + if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) ) + goto Error; + + /* copy data to new buffer */ + x = target_llx >> 6; + y = target_lly >> 6; + + /* the bitmap flow is from top to bottom, */ + /* but y is measured from bottom to top */ + if ( target->pitch < 0 ) + { + /* XXX */ + } + else + { + unsigned char* p = + target->buffer; + unsigned char* q = + buffer + + ( final_rows - y - target->rows ) * new_pitch + + x * 4; + unsigned char* limit_p = + p + pitch * (int)target->rows; + + + while ( p < limit_p ) + { + FT_MEM_COPY( q, p, pitch ); + + p += pitch; + q += new_pitch; + } + } + + FT_FREE( target->buffer ); + + target->width = final_width; + target->rows = final_rows; + + if ( target->pitch < 0 ) + target->pitch = -new_pitch; + else + target->pitch = new_pitch; + + target->buffer = buffer; + } + + /* adjust source bitmap if necessary */ + if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY ) + { + FT_Bitmap_Init( &source_bitmap ); + error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 ); + if ( error ) + goto Error; + + source = &source_bitmap; + free_source_bitmap = 1; + } + else + source = source_; + + /* do blending; the code below returns pre-multiplied channels, */ + /* similar to what FreeType gets from `CBDT' tables */ + x = source_llx >> 6; + y = source_lly >> 6; + + /* the bitmap flow is from top to bottom, */ + /* but y is measured from bottom to top */ + if ( target->pitch < 0 ) + { + /* XXX */ + } + else + { + unsigned char* p = + source->buffer; + unsigned char* q = + target->buffer + + ( target->rows - y - source->rows ) * target->pitch + + x * 4; + unsigned char* limit_p = + p + source->pitch * (int)source->rows; + + + while ( p < limit_p ) + { + unsigned char* r = p; + unsigned char* s = q; + unsigned char* limit_r = r + source->width; + + + while ( r < limit_r ) + { + int aa = *r++; + int fa = color.alpha * aa / 255; + + int fb = color.blue * fa / 255; + int fg = color.green * fa / 255; + int fr = color.red * fa / 255; + + int ba2 = 255 - fa; + + int bb = s[0]; + int bg = s[1]; + int br = s[2]; + int ba = s[3]; + + + *s++ = (unsigned char)( bb * ba2 / 255 + fb ); + *s++ = (unsigned char)( bg * ba2 / 255 + fg ); + *s++ = (unsigned char)( br * ba2 / 255 + fr ); + *s++ = (unsigned char)( ba * ba2 / 255 + fa ); + } + + p += source->pitch; + q += target->pitch; + } + } + + atarget_offset->x = final_llx; + atarget_offset->y = final_lly + ( final_rows << 6 ); + + Error: + if ( error && free_target_bitmap_on_error ) + FT_Bitmap_Done( library, target ); + + if ( free_source_bitmap ) + FT_Bitmap_Done( library, &source_bitmap ); + + return error; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) + { + if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && + !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Bitmap bitmap; + FT_Error error; + + + FT_Bitmap_Init( &bitmap ); + error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); + if ( error ) + return error; + + slot->bitmap = bitmap; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !bitmap ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + FT_FREE( bitmap->buffer ); + *bitmap = null_bitmap; + + return FT_Err_Ok; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftcalc.c b/Dependencies/freetype/freetype/src/base/ftcalc.c new file mode 100644 index 00000000..92de09ed --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftcalc.c @@ -0,0 +1,1126 @@ +/**************************************************************************** + * + * ftcalc.c + * + * Arithmetic computations (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * Support for 1-complement arithmetic has been totally dropped in this + * release. You can still write your own code if you need it. + * + */ + + /************************************************************************** + * + * Implementing basic computation routines. + * + * FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), + * and FT_FloorFix() are declared in freetype.h. + * + */ + + +#include +#include +#include +#include +#include + + +#ifdef FT_MULFIX_ASSEMBLER +#undef FT_MulFix +#endif + +/* we need to emulate a 64-bit data type if a real one isn't available */ + +#ifndef FT_INT64 + + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_Int64; + +#endif /* !FT_INT64 */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT calc + + + /* transfer sign, leaving a positive number; */ + /* we need an unsigned value to safely negate INT_MIN (or LONG_MIN) */ +#define FT_MOVE_SIGN( utype, x, x_unsigned, s ) \ + FT_BEGIN_STMNT \ + if ( x < 0 ) \ + { \ + x_unsigned = 0U - (utype)x; \ + s = -s; \ + } \ + else \ + x_unsigned = (utype)x; \ + FT_END_STMNT + + /* The following three functions are available regardless of whether */ + /* FT_INT64 is defined. */ + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_RoundFix( FT_Fixed a ) + { + return ( ADD_LONG( a, 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_CeilFix( FT_Fixed a ) + { + return ( ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_FloorFix( FT_Fixed a ) + { + return a & ~0xFFFFL; + } + +#ifndef FT_MSB + + FT_BASE_DEF( FT_Int ) + FT_MSB( FT_UInt32 z ) + { + FT_Int shift = 0; + + + /* determine msb bit index in `shift' */ + if ( z & 0xFFFF0000UL ) + { + z >>= 16; + shift += 16; + } + if ( z & 0x0000FF00UL ) + { + z >>= 8; + shift += 8; + } + if ( z & 0x000000F0UL ) + { + z >>= 4; + shift += 4; + } + if ( z & 0x0000000CUL ) + { + z >>= 2; + shift += 2; + } + if ( z & 0x00000002UL ) + { + /* z >>= 1; */ + shift += 1; + } + + return shift; + } + +#endif /* !FT_MSB */ + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Fixed ) + FT_Hypot( FT_Fixed x, + FT_Fixed y ) + { + FT_Vector v; + + + v.x = x; + v.y = y; + + return FT_Vector_Length( &v ); + } + + +#ifdef FT_INT64 + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, c, d; + FT_Long d_; + + + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); + + d = c > 0 ? ( a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFUL; + + d_ = (FT_Long)d; + + return s < 0 ? NEG_LONG( d_ ) : d_; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, c, d; + FT_Long d_; + + + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); + + d = c > 0 ? a * b / c + : 0x7FFFFFFFUL; + + d_ = (FT_Long)d; + + return s < 0 ? NEG_LONG( d_ ) : d_; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a_, + FT_Long b_ ) + { +#ifdef FT_MULFIX_ASSEMBLER + + return FT_MULFIX_ASSEMBLER( (FT_Int32)a_, (FT_Int32)b_ ); + +#else + + FT_Int64 ab = (FT_Int64)a_ * (FT_Int64)b_; + + /* this requires arithmetic right shift of signed numbers */ + return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 ); + +#endif /* FT_MULFIX_ASSEMBLER */ + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a_, + FT_Long b_ ) + { + FT_Int s = 1; + FT_UInt64 a, b, q; + FT_Long q_; + + + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + + q = b > 0 ? ( ( a << 16 ) + ( b >> 1 ) ) / b + : 0x7FFFFFFFUL; + + q_ = (FT_Long)q; + + return s < 0 ? NEG_LONG( q_ ) : q_; + } + + +#else /* !FT_INT64 */ + + + static void + ft_multo64( FT_UInt32 x, + FT_UInt32 y, + FT_Int64 *z ) + { + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + lo1 = x & 0x0000FFFFU; hi1 = x >> 16; + lo2 = y & 0x0000FFFFU; hi2 = y >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + z->lo = lo; + z->hi = hi; + } + + + static FT_UInt32 + ft_div64by32( FT_UInt32 hi, + FT_UInt32 lo, + FT_UInt32 y ) + { + FT_UInt32 r, q; + FT_Int i; + + + if ( hi >= y ) + return (FT_UInt32)0x7FFFFFFFL; + + /* We shift as many bits as we can into the high register, perform */ + /* 32-bit division with modulo there, then work through the remaining */ + /* bits with long division. This optimization is especially noticeable */ + /* for smaller dividends that barely use the high register. */ + + i = 31 - FT_MSB( hi ); + r = ( hi << i ) | ( lo >> ( 32 - i ) ); lo <<= i; /* left 64-bit shift */ + q = r / y; + r -= q * y; /* remainder */ + + i = 32 - i; /* bits remaining in low register */ + do + { + q <<= 1; + r = ( r << 1 ) | ( lo >> 31 ); lo <<= 1; + + if ( r >= y ) + { + r -= y; + q |= 1; + } + } while ( --i ); + + return q; + } + + + static void + FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64 *z ) + { + FT_UInt32 lo, hi; + + + lo = x->lo + y->lo; + hi = x->hi + y->hi + ( lo < x->lo ); + + z->lo = lo; + z->hi = hi; + } + + + /* The FT_MulDiv function has been optimized thanks to ideas from */ + /* Graham Asher and Alexei Podtelezhnikov. The trick is to optimize */ + /* a rather common case when everything fits within 32-bits. */ + /* */ + /* We compute 'a*b+c/2', then divide it by 'c' (all positive values). */ + /* */ + /* The product of two positive numbers never exceeds the square of */ + /* its mean values. Therefore, we always avoid the overflow by */ + /* imposing */ + /* */ + /* (a + b) / 2 <= sqrt(X - c/2) , */ + /* */ + /* where X = 2^32 - 1, the maximum unsigned 32-bit value, and using */ + /* unsigned arithmetic. Now we replace `sqrt' with a linear function */ + /* that is smaller or equal for all values of c in the interval */ + /* [0;X/2]; it should be equal to sqrt(X) and sqrt(3X/4) at the */ + /* endpoints. Substituting the linear solution and explicit numbers */ + /* we get */ + /* */ + /* a + b <= 131071.99 - c / 122291.84 . */ + /* */ + /* In practice, we should use a faster and even stronger inequality */ + /* */ + /* a + b <= 131071 - (c >> 16) */ + /* */ + /* or, alternatively, */ + /* */ + /* a + b <= 129894 - (c >> 17) . */ + /* */ + /* FT_MulFix, on the other hand, is optimized for a small value of */ + /* the first argument, when the second argument can be much larger. */ + /* This can be achieved by scaling the second argument and the limit */ + /* in the above inequalities. For example, */ + /* */ + /* a + (b >> 8) <= (131071 >> 4) */ + /* */ + /* covers the practical range of use. The actual test below is a bit */ + /* tighter to avoid the border case overflows. */ + /* */ + /* In the case of FT_DivFix, the exact overflow check */ + /* */ + /* a << 16 <= X - c/2 */ + /* */ + /* is scaled down by 2^16 and we use */ + /* */ + /* a <= 65535 - (c >> 17) . */ + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, c; + + + /* XXX: this function does not allow 64-bit arguments */ + + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); + + if ( c == 0 ) + a = 0x7FFFFFFFUL; + + else if ( a + b <= 129894UL - ( c >> 17 ) ) + a = ( a * b + ( c >> 1 ) ) / c; + + else + { + FT_Int64 temp, temp2; + + + ft_multo64( a, b, &temp ); + + temp2.hi = 0; + temp2.lo = c >> 1; + + FT_Add64( &temp, &temp2, &temp ); + + /* last attempt to ditch long division */ + a = ( temp.hi == 0 ) ? temp.lo / c + : ft_div64by32( temp.hi, temp.lo, c ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + } + + + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a_, + FT_Long b_, + FT_Long c_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, c; + + + /* XXX: this function does not allow 64-bit arguments */ + + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); + + if ( c == 0 ) + a = 0x7FFFFFFFUL; + + else if ( a + b <= 131071UL ) + a = a * b / c; + + else + { + FT_Int64 temp; + + + ft_multo64( a, b, &temp ); + + /* last attempt to ditch long division */ + a = ( temp.hi == 0 ) ? temp.lo / c + : ft_div64by32( temp.hi, temp.lo, c ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a_, + FT_Long b_ ) + { +#ifdef FT_MULFIX_ASSEMBLER + + return FT_MULFIX_ASSEMBLER( a_, b_ ); + +#elif 0 + + /* + * This code is nonportable. See comment below. + * + * However, on a platform where right-shift of a signed quantity fills + * the leftmost bits by copying the sign bit, it might be faster. + */ + + FT_Long sa, sb; + FT_UInt32 a, b; + + + /* + * This is a clever way of converting a signed number `a' into its + * absolute value (stored back into `a') and its sign. The sign is + * stored in `sa'; 0 means `a' was positive or zero, and -1 means `a' + * was negative. (Similarly for `b' and `sb'). + * + * Unfortunately, it doesn't work (at least not portably). + * + * It makes the assumption that right-shift on a negative signed value + * fills the leftmost bits by copying the sign bit. This is wrong. + * According to K&R 2nd ed, section `A7.8 Shift Operators' on page 206, + * the result of right-shift of a negative signed value is + * implementation-defined. At least one implementation fills the + * leftmost bits with 0s (i.e., it is exactly the same as an unsigned + * right shift). This means that when `a' is negative, `sa' ends up + * with the value 1 rather than -1. After that, everything else goes + * wrong. + */ + sa = ( a_ >> ( sizeof ( a_ ) * 8 - 1 ) ); + a = ( a_ ^ sa ) - sa; + sb = ( b_ >> ( sizeof ( b_ ) * 8 - 1 ) ); + b = ( b_ ^ sb ) - sb; + + a = (FT_UInt32)a_; + b = (FT_UInt32)b_; + + if ( a + ( b >> 8 ) <= 8190UL ) + a = ( a * b + 0x8000U ) >> 16; + else + { + FT_UInt32 al = a & 0xFFFFUL; + + + a = ( a >> 16 ) * b + al * ( b >> 16 ) + + ( ( al * ( b & 0xFFFFUL ) + 0x8000UL ) >> 16 ); + } + + sa ^= sb; + a = ( a ^ sa ) - sa; + + return (FT_Long)a; + +#else /* 0 */ + + FT_Int s = 1; + FT_UInt32 a, b; + + + /* XXX: this function does not allow 64-bit arguments */ + + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + + if ( a + ( b >> 8 ) <= 8190UL ) + a = ( a * b + 0x8000UL ) >> 16; + else + { + FT_UInt32 al = a & 0xFFFFUL; + + + a = ( a >> 16 ) * b + al * ( b >> 16 ) + + ( ( al * ( b & 0xFFFFUL ) + 0x8000UL ) >> 16 ); + } + + a_ = (FT_Long)a; + + return s < 0 ? NEG_LONG( a_ ) : a_; + +#endif /* 0 */ + + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a_, + FT_Long b_ ) + { + FT_Int s = 1; + FT_UInt32 a, b, q; + FT_Long q_; + + + /* XXX: this function does not allow 64-bit arguments */ + + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + + if ( b == 0 ) + { + /* check for division by 0 */ + q = 0x7FFFFFFFUL; + } + else if ( a <= 65535UL - ( b >> 17 ) ) + { + /* compute result directly */ + q = ( ( a << 16 ) + ( b >> 1 ) ) / b; + } + else + { + /* we need more bits; we have to do it by hand */ + FT_Int64 temp, temp2; + + + temp.hi = a >> 16; + temp.lo = a << 16; + temp2.hi = 0; + temp2.lo = b >> 1; + + FT_Add64( &temp, &temp2, &temp ); + q = ft_div64by32( temp.hi, temp.lo, b ); + } + + q_ = (FT_Long)q; + + return s < 0 ? NEG_LONG( q_ ) : q_; + } + + +#endif /* !FT_INT64 */ + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix *b ) + { + FT_Fixed xx, xy, yx, yy; + + + if ( !a || !b ) + return; + + xx = ADD_LONG( FT_MulFix( a->xx, b->xx ), + FT_MulFix( a->xy, b->yx ) ); + xy = ADD_LONG( FT_MulFix( a->xx, b->xy ), + FT_MulFix( a->xy, b->yy ) ); + yx = ADD_LONG( FT_MulFix( a->yx, b->xx ), + FT_MulFix( a->yy, b->yx ) ); + yy = ADD_LONG( FT_MulFix( a->yx, b->xy ), + FT_MulFix( a->yy, b->yy ) ); + + b->xx = xx; + b->xy = xy; + b->yx = yx; + b->yy = yy; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ) + { + FT_Pos delta, xx, yy; + + + if ( !matrix ) + return FT_THROW( Invalid_Argument ); + + /* compute discriminant */ + delta = FT_MulFix( matrix->xx, matrix->yy ) - + FT_MulFix( matrix->xy, matrix->yx ); + + if ( !delta ) + return FT_THROW( Invalid_Argument ); /* matrix can't be inverted */ + + matrix->xy = -FT_DivFix( matrix->xy, delta ); + matrix->yx = -FT_DivFix( matrix->yx, delta ); + + xx = matrix->xx; + yy = matrix->yy; + + matrix->xx = FT_DivFix( yy, delta ); + matrix->yy = FT_DivFix( xx, delta ); + + return FT_Err_Ok; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ) + { + FT_Fixed xx, xy, yx, yy; + + FT_Long val = 0x10000L * scaling; + + + if ( !a || !b ) + return; + + xx = ADD_LONG( FT_MulDiv( a->xx, b->xx, val ), + FT_MulDiv( a->xy, b->yx, val ) ); + xy = ADD_LONG( FT_MulDiv( a->xx, b->xy, val ), + FT_MulDiv( a->xy, b->yy, val ) ); + yx = ADD_LONG( FT_MulDiv( a->yx, b->xx, val ), + FT_MulDiv( a->yy, b->yx, val ) ); + yy = ADD_LONG( FT_MulDiv( a->yx, b->xy, val ), + FT_MulDiv( a->yy, b->yy, val ) ); + + b->xx = xx; + b->xy = xy; + b->yx = yx; + b->yy = yy; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Bool ) + FT_Matrix_Check( const FT_Matrix* matrix ) + { + FT_Fixed xx, xy, yx, yy; + FT_Fixed val; + FT_Int shift; + FT_ULong temp1, temp2; + + + if ( !matrix ) + return 0; + + xx = matrix->xx; + xy = matrix->xy; + yx = matrix->yx; + yy = matrix->yy; + val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy ); + + /* we only handle non-zero 32-bit values */ + if ( !val || val > 0x7FFFFFFFL ) + return 0; + + /* Scale matrix to avoid the temp1 overflow, which is */ + /* more stringent than avoiding the temp2 overflow. */ + + shift = FT_MSB( val ) - 12; + + if ( shift > 0 ) + { + xx >>= shift; + xy >>= shift; + yx >>= shift; + yy >>= shift; + } + + temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx ); + temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) + + (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy ); + + if ( temp1 <= temp2 ) + return 0; + + return 1; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ) + { + FT_Pos xz, yz; + + FT_Long val = 0x10000L * scaling; + + + if ( !vector || !matrix ) + return; + + xz = ADD_LONG( FT_MulDiv( vector->x, matrix->xx, val ), + FT_MulDiv( vector->y, matrix->xy, val ) ); + yz = ADD_LONG( FT_MulDiv( vector->x, matrix->yx, val ), + FT_MulDiv( vector->y, matrix->yy, val ) ); + + vector->x = xz; + vector->y = yz; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_UInt32 ) + FT_Vector_NormLen( FT_Vector* vector ) + { + FT_Int32 x_ = vector->x; + FT_Int32 y_ = vector->y; + FT_Int32 b, z; + FT_UInt32 x, y, u, v, l; + FT_Int sx = 1, sy = 1, shift; + + + FT_MOVE_SIGN( FT_UInt32, x_, x, sx ); + FT_MOVE_SIGN( FT_UInt32, y_, y, sy ); + + /* trivial cases */ + if ( x == 0 ) + { + if ( y > 0 ) + vector->y = sy * 0x10000; + return y; + } + else if ( y == 0 ) + { + if ( x > 0 ) + vector->x = sx * 0x10000; + return x; + } + + /* Estimate length and prenormalize by shifting so that */ + /* the new approximate length is between 2/3 and 4/3. */ + /* The magic constant 0xAAAAAAAAUL (2/3 of 2^32) helps */ + /* achieve this in 16.16 fixed-point representation. */ + l = x > y ? x + ( y >> 1 ) + : y + ( x >> 1 ); + + shift = 31 - FT_MSB( l ); + shift -= 15 + ( l >= ( 0xAAAAAAAAUL >> shift ) ); + + if ( shift > 0 ) + { + x <<= shift; + y <<= shift; + + /* re-estimate length for tiny vectors */ + l = x > y ? x + ( y >> 1 ) + : y + ( x >> 1 ); + } + else + { + x >>= -shift; + y >>= -shift; + l >>= -shift; + } + + /* lower linear approximation for reciprocal length minus one */ + b = 0x10000 - (FT_Int32)l; + + x_ = (FT_Int32)x; + y_ = (FT_Int32)y; + + /* Newton's iterations */ + do + { + u = (FT_UInt32)( x_ + ( x_ * b >> 16 ) ); + v = (FT_UInt32)( y_ + ( y_ * b >> 16 ) ); + + /* Normalized squared length in the parentheses approaches 2^32. */ + /* On two's complement systems, converting to signed gives the */ + /* difference with 2^32 even if the expression wraps around. */ + z = -(FT_Int32)( u * u + v * v ) / 0x200; + z = z * ( ( 0x10000 + b ) >> 8 ) / 0x10000; + + b += z; + + } while ( z > 0 ); + + vector->x = sx < 0 ? -(FT_Pos)u : (FT_Pos)u; + vector->y = sy < 0 ? -(FT_Pos)v : (FT_Pos)v; + + /* Conversion to signed helps to recover from likely wrap around */ + /* in calculating the prenormalized length, because it gives the */ + /* correct difference with 2^32 on two's complement systems. */ + l = (FT_UInt32)( 0x10000 + (FT_Int32)( u * x + v * y ) / 0x10000 ); + if ( shift > 0 ) + l = ( l + ( 1 << ( shift - 1 ) ) ) >> shift; + else + l <<= -shift; + + return l; + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 v ) + { + if ( v == 0 ) + return 0; + +#ifndef FT_INT64 + + /* Algorithm by Christophe Meessen (1993) with overflow fixed and */ + /* rounding added. Any unsigned fixed 16.16 argument is acceptable. */ + /* However, this algorithm is slower than the Babylonian method with */ + /* a good initial guess. We only use it for large 32-bit values when */ + /* 64-bit computations are not desirable. */ + else if ( v > 0x10000U ) + { + FT_UInt32 r = v >> 1; + FT_UInt32 q = ( v & 1 ) << 15; + FT_UInt32 b = 0x20000000; + FT_UInt32 t; + + + do + { + t = q + b; + if ( r >= t ) + { + r -= t; + q = t + b; /* equivalent to q += 2*b */ + } + r <<= 1; + b >>= 1; + + } while ( b > 0x10 ); /* exactly 25 cycles */ + + return ( q + 0x40 ) >> 7; + } + else + { + FT_UInt32 r = ( v << 16 ) - 1; + +#else /* FT_INT64 */ + + else + { + FT_UInt64 r = ( (FT_UInt64)v << 16 ) - 1; + +#endif /* FT_INT64 */ + + FT_UInt32 q = 1 << ( ( 17 + FT_MSB( v ) ) >> 1 ); + FT_UInt32 t; + + + /* Babylonian method with rounded-up division */ + do + { + t = q; + q = ( t + (FT_UInt32)( r / t ) + 1 ) >> 1; + + } while ( q != t ); /* less than 6 cycles */ + + return q; + } + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + /* we silently ignore overflow errors since such large values */ + /* lead to even more (harmless) rendering errors later on */ + +#ifdef FT_INT64 + + FT_Int64 delta = SUB_INT64( MUL_INT64( in_x, out_y ), + MUL_INT64( in_y, out_x ) ); + + + return ( delta > 0 ) - ( delta < 0 ); + +#else + + FT_Int result; + + + if ( ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L && + ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L ) + { + FT_Long z1 = MUL_LONG( in_x, out_y ); + FT_Long z2 = MUL_LONG( in_y, out_x ); + + + if ( z1 > z2 ) + result = +1; + else if ( z1 < z2 ) + result = -1; + else + result = 0; + } + else /* products might overflow 32 bits */ + { + FT_Int64 z1, z2; + + + /* XXX: this function does not allow 64-bit arguments */ + ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 ); + ft_multo64( (FT_UInt32)in_y, (FT_UInt32)out_x, &z2 ); + + if ( z1.hi > z2.hi ) + result = +1; + else if ( z1.hi < z2.hi ) + result = -1; + else if ( z1.lo > z2.lo ) + result = +1; + else if ( z1.lo < z2.lo ) + result = -1; + else + result = 0; + } + + /* XXX: only the sign of return value, +1/0/-1 must be used */ + return result; + +#endif + } + + + /* documentation is in ftcalc.h */ + + FT_BASE_DEF( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + FT_Pos ax = in_x + out_x; + FT_Pos ay = in_y + out_y; + + FT_Pos d_in, d_out, d_hypot; + + + /* The idea of this function is to compare the length of the */ + /* hypotenuse with the `in' and `out' length. The `corner' */ + /* represented by `in' and `out' is flat if the hypotenuse's */ + /* length isn't too large. */ + /* */ + /* This approach has the advantage that the angle between */ + /* `in' and `out' is not checked. In case one of the two */ + /* vectors is `dominant', that is, much larger than the */ + /* other vector, we thus always have a flat corner. */ + /* */ + /* hypotenuse */ + /* x---------------------------x */ + /* \ / */ + /* \ / */ + /* in \ / out */ + /* \ / */ + /* o */ + /* Point */ + + d_in = FT_HYPOT( in_x, in_y ); + d_out = FT_HYPOT( out_x, out_y ); + d_hypot = FT_HYPOT( ax, ay ); + + /* now do a simple length comparison: */ + /* */ + /* d_in + d_out < 17/16 d_hypot */ + + return ( d_in + d_out - d_hypot ) < ( d_hypot >> 4 ); + } + + + FT_BASE_DEF( FT_Int32 ) + FT_MulAddFix( FT_Fixed* s, + FT_Int32* f, + FT_UInt count ) + { + FT_UInt i; + FT_Int64 temp; + + +#ifdef FT_INT64 + temp = 0; + + for ( i = 0; i < count; ++i ) + temp += (FT_Int64)s[i] * f[i]; + + return (FT_Int32)( ( temp + 0x8000 ) >> 16 ); +#else + temp.hi = 0; + temp.lo = 0; + + for ( i = 0; i < count; ++i ) + { + FT_Int64 multResult; + + FT_Int sign = 1; + FT_UInt32 carry = 0; + + FT_UInt32 scalar; + FT_UInt32 factor; + + + FT_MOVE_SIGN( FT_UInt32, s[i], scalar, sign ); + FT_MOVE_SIGN( FT_UInt32, f[i], factor, sign ); + + ft_multo64( scalar, factor, &multResult ); + + if ( sign < 0 ) + { + /* Emulated `FT_Int64` negation. */ + carry = ( multResult.lo == 0 ); + + multResult.lo = ~multResult.lo + 1; + multResult.hi = ~multResult.hi + carry; + } + + FT_Add64( &temp, &multResult, &temp ); + } + + /* Shift and round value. */ + return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) ) + + ( 1 & ( temp.lo >> 15 ) ) ); + + +#endif /* !FT_INT64 */ + + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftcid.c b/Dependencies/freetype/freetype/src/base/ftcid.c new file mode 100644 index 00000000..4f2deb19 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftcid.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * + * ftcid.c + * + * FreeType API for accessing CID font information. + * + * Copyright (C) 2007-2024 by + * Derek Clegg and Michael Toftdal. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + + + /* documentation is in ftcid.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement) + { + FT_Error error; + const char* r = NULL; + const char* o = NULL; + FT_Int s = 0; + + + error = FT_ERR( Invalid_Argument ); + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_ros ) + error = service->get_ros( face, &r, &o, &s ); + } + + if ( registry ) + *registry = r; + + if ( ordering ) + *ordering = o; + + if ( supplement ) + *supplement = s; + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Bool ic = 0; + + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_is_cid ) + error = service->get_is_cid( face, &ic); + } + + if ( is_cid ) + *is_cid = ic; + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_UInt c = 0; + + + if ( face ) + { + FT_Service_CID service; + + + FT_FACE_FIND_SERVICE( face, service, CID ); + + if ( service && service->get_cid_from_glyph_index ) + error = service->get_cid_from_glyph_index( face, glyph_index, &c); + } + + if ( cid ) + *cid = c; + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftcolor.c b/Dependencies/freetype/freetype/src/base/ftcolor.c new file mode 100644 index 00000000..c6bf2a3c --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftcolor.c @@ -0,0 +1,156 @@ +/**************************************************************************** + * + * ftcolor.c + * + * FreeType's glyph color management (body). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + + static + const FT_Palette_Data null_palette_data = { 0, NULL, NULL, 0, NULL }; + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette_data ) + { + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + if ( !apalette_data) + return FT_THROW( Invalid_Argument ); + + if ( FT_IS_SFNT( face ) ) + *apalette_data = ( (TT_Face)face )->palette_data; + else + *apalette_data = null_palette_data; + + return FT_Err_Ok; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ) + { + FT_Error error; + + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !FT_IS_SFNT( face ) ) + { + if ( apalette ) + *apalette = NULL; + + return FT_Err_Ok; + } + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + error = sfnt->set_palette( ttface, palette_index ); + if ( error ) + return error; + + ttface->palette_index = palette_index; + + if ( apalette ) + *apalette = ttface->palette; + + return FT_Err_Ok; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ) + { + TT_Face ttface; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !FT_IS_SFNT( face ) ) + return FT_Err_Ok; + + ttface = (TT_Face)face; + + ttface->foreground_color = foreground_color; + ttface->have_foreground_color = 1; + + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Data_Get( FT_Face face, + FT_Palette_Data *apalette_data ) + { + FT_UNUSED( face ); + FT_UNUSED( apalette_data ); + + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Select( FT_Face face, + FT_UShort palette_index, + FT_Color* *apalette ) + { + FT_UNUSED( face ); + FT_UNUSED( palette_index ); + FT_UNUSED( apalette ); + + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set_Foreground_Color( FT_Face face, + FT_Color foreground_color ) + { + FT_UNUSED( face ); + FT_UNUSED( foreground_color ); + + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftdbgmem.c b/Dependencies/freetype/freetype/src/base/ftdbgmem.c new file mode 100644 index 00000000..902a5dc8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftdbgmem.c @@ -0,0 +1,971 @@ +/**************************************************************************** + * + * ftdbgmem.c + * + * Memory debugger (body). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + +#ifdef FT_DEBUG_MEMORY + +#define KEEPALIVE /* `Keep alive' means that freed blocks aren't released + * to the heap. This is useful to detect double-frees + * or weird heap corruption, but it uses large amounts of + * memory, however. + */ + +#include FT_CONFIG_STANDARD_LIBRARY_H + + FT_BASE_DEF( const char* ) ft_debug_file_ = NULL; + FT_BASE_DEF( long ) ft_debug_lineno_ = 0; + + extern void + FT_DumpMemory( FT_Memory memory ); + + + typedef struct FT_MemSourceRec_* FT_MemSource; + typedef struct FT_MemNodeRec_* FT_MemNode; + typedef struct FT_MemTableRec_* FT_MemTable; + + +#define FT_MEM_VAL( addr ) ( (FT_PtrDist)(FT_Pointer)( addr ) ) + + /* + * This structure holds statistics for a single allocation/release + * site. This is useful to know where memory operations happen the + * most. + */ + typedef struct FT_MemSourceRec_ + { + const char* file_name; + long line_no; + + FT_Long cur_blocks; /* current number of allocated blocks */ + FT_Long max_blocks; /* max. number of allocated blocks */ + FT_Long all_blocks; /* total number of blocks allocated */ + + FT_Long cur_size; /* current cumulative allocated size */ + FT_Long max_size; /* maximum cumulative allocated size */ + FT_Long all_size; /* total cumulative allocated size */ + + FT_Long cur_max; /* current maximum allocated size */ + + FT_UInt32 hash; + FT_MemSource link; + + } FT_MemSourceRec; + + + /* + * We don't need a resizable array for the memory sources because + * their number is pretty limited within FreeType. + */ +#define FT_MEM_SOURCE_BUCKETS 128 + + /* + * This structure holds information related to a single allocated + * memory block. If KEEPALIVE is defined, blocks that are freed by + * FreeType are never released to the system. Instead, their `size' + * field is set to `-size'. This is mainly useful to detect double + * frees, at the price of a large memory footprint during execution. + */ + typedef struct FT_MemNodeRec_ + { + FT_Byte* address; + FT_Long size; /* < 0 if the block was freed */ + + FT_MemSource source; + +#ifdef KEEPALIVE + const char* free_file_name; + FT_Long free_line_no; +#endif + + FT_MemNode link; + + } FT_MemNodeRec; + + + /* + * The global structure, containing compound statistics and all hash + * tables. + */ + typedef struct FT_MemTableRec_ + { + FT_Long size; + FT_Long nodes; + FT_MemNode* buckets; + + FT_Long alloc_total; + FT_Long alloc_current; + FT_Long alloc_max; + FT_Long alloc_count; + + FT_Bool bound_total; + FT_Long alloc_total_max; + + FT_Bool bound_count; + FT_Long alloc_count_max; + + FT_MemSource sources[FT_MEM_SOURCE_BUCKETS]; + + FT_Bool keep_alive; + + FT_Memory memory; + FT_Pointer memory_user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + + } FT_MemTableRec; + + +#define FT_MEM_SIZE_MIN 7 +#define FT_MEM_SIZE_MAX 13845163 + +#define FT_FILENAME( x ) ( (x) ? (x) : "unknown file" ) + + + /* + * Prime numbers are ugly to handle. It would be better to implement + * L-Hashing, which is 10% faster and doesn't require divisions. + */ + static const FT_Int ft_mem_primes[] = + { + 7, + 11, + 19, + 37, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, + }; + + + static FT_Long + ft_mem_closest_prime( FT_Long num ) + { + size_t i; + + + for ( i = 0; + i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ ) + if ( ft_mem_primes[i] > num ) + return ft_mem_primes[i]; + + return FT_MEM_SIZE_MAX; + } + + + static void + ft_mem_debug_panic( const char* fmt, + ... ) + { + va_list ap; + + + printf( "FreeType.Debug: " ); + + va_start( ap, fmt ); + vprintf( fmt, ap ); + va_end( ap ); + + printf( "\n" ); + exit( EXIT_FAILURE ); + } + + + static FT_Pointer + ft_mem_table_alloc( FT_MemTable table, + FT_Long size ) + { + FT_Memory memory = table->memory; + FT_Pointer block; + + + memory->user = table->memory_user; + block = table->alloc( memory, size ); + memory->user = table; + + return block; + } + + + static void + ft_mem_table_free( FT_MemTable table, + FT_Pointer block ) + { + FT_Memory memory = table->memory; + + + memory->user = table->memory_user; + table->free( memory, block ); + memory->user = table; + } + + + static void + ft_mem_table_resize( FT_MemTable table ) + { + FT_Long new_size; + + + new_size = ft_mem_closest_prime( table->nodes ); + if ( new_size != table->size ) + { + FT_MemNode* new_buckets; + FT_Long i; + + + new_buckets = (FT_MemNode *) + ft_mem_table_alloc( + table, + new_size * (FT_Long)sizeof ( FT_MemNode ) ); + if ( !new_buckets ) + return; + + FT_ARRAY_ZERO( new_buckets, new_size ); + + for ( i = 0; i < table->size; i++ ) + { + FT_MemNode node, next, *pnode; + FT_PtrDist hash; + + + node = table->buckets[i]; + while ( node ) + { + next = node->link; + hash = FT_MEM_VAL( node->address ) % (FT_PtrDist)new_size; + pnode = new_buckets + hash; + + node->link = pnode[0]; + pnode[0] = node; + + node = next; + } + } + + if ( table->buckets ) + ft_mem_table_free( table, table->buckets ); + + table->buckets = new_buckets; + table->size = new_size; + } + } + + + static void + ft_mem_table_destroy( FT_MemTable table ) + { + FT_Long i; + FT_Long leak_count = 0; + FT_Long leaks = 0; + + + /* remove all blocks from the table, revealing leaked ones */ + for ( i = 0; i < table->size; i++ ) + { + FT_MemNode *pnode = table->buckets + i, next, node = *pnode; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + if ( node->size > 0 ) + { + printf( + "leaked memory block at address %p, size %8ld in (%s:%ld)\n", + (void*)node->address, + node->size, + FT_FILENAME( node->source->file_name ), + node->source->line_no ); + + leak_count++; + leaks += node->size; + + ft_mem_table_free( table, node->address ); + } + + node->address = NULL; + node->size = 0; + + ft_mem_table_free( table, node ); + node = next; + } + table->buckets[i] = NULL; + } + + ft_mem_table_free( table, table->buckets ); + table->buckets = NULL; + + table->size = 0; + table->nodes = 0; + + /* remove all sources */ + for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ ) + { + FT_MemSource source, next; + + + for ( source = table->sources[i]; source != NULL; source = next ) + { + next = source->link; + ft_mem_table_free( table, source ); + } + + table->sources[i] = NULL; + } + + printf( "FreeType: total memory allocations = %ld\n", + table->alloc_total ); + printf( "FreeType: maximum memory footprint = %ld\n", + table->alloc_max ); + + if ( leak_count > 0 ) + ft_mem_debug_panic( + "FreeType: %ld bytes of memory leaked in %ld blocks\n", + leaks, leak_count ); + + printf( "FreeType: no memory leaks detected\n" ); + } + + + static FT_MemNode* + ft_mem_table_get_nodep( FT_MemTable table, + FT_Byte* address ) + { + FT_PtrDist hash; + FT_MemNode *pnode, node; + + + hash = FT_MEM_VAL( address ); + pnode = table->buckets + ( hash % (FT_PtrDist)table->size ); + + for (;;) + { + node = pnode[0]; + if ( !node ) + break; + + if ( node->address == address ) + break; + + pnode = &node->link; + } + return pnode; + } + + + static FT_MemSource + ft_mem_table_get_source( FT_MemTable table ) + { + FT_UInt32 hash; + FT_MemSource node, *pnode; + + + /* cast to FT_PtrDist first since void* can be larger */ + /* than FT_UInt32 and GCC 4.1.1 emits a warning */ + hash = (FT_UInt32)(FT_PtrDist)(void*)ft_debug_file_ + + (FT_UInt32)( 5 * ft_debug_lineno_ ); + pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; + + for (;;) + { + node = *pnode; + if ( !node ) + break; + + if ( node->file_name == ft_debug_file_ && + node->line_no == ft_debug_lineno_ ) + goto Exit; + + pnode = &node->link; + } + + node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) ); + if ( !node ) + ft_mem_debug_panic( + "not enough memory to perform memory debugging\n" ); + + node->file_name = ft_debug_file_; + node->line_no = ft_debug_lineno_; + + node->cur_blocks = 0; + node->max_blocks = 0; + node->all_blocks = 0; + + node->cur_size = 0; + node->max_size = 0; + node->all_size = 0; + + node->cur_max = 0; + + node->link = NULL; + node->hash = hash; + *pnode = node; + + Exit: + return node; + } + + + static void + ft_mem_table_set( FT_MemTable table, + FT_Byte* address, + FT_Long size, + FT_Long delta ) + { + FT_MemNode *pnode, node; + + + if ( table ) + { + FT_MemSource source; + + + pnode = ft_mem_table_get_nodep( table, address ); + node = *pnode; + if ( node ) + { + if ( node->size < 0 ) + { + /* This block was already freed. Our memory is now completely */ + /* corrupted! */ + /* This can only happen in keep-alive mode. */ + ft_mem_debug_panic( + "memory heap corrupted (allocating freed block)" ); + } + else + { + /* This block was already allocated. This means that our memory */ + /* is also corrupted! */ + ft_mem_debug_panic( + "memory heap corrupted (re-allocating allocated block at" + " %p, of size %ld)\n" + "org=%s:%d new=%s:%d\n", + node->address, node->size, + FT_FILENAME( node->source->file_name ), node->source->line_no, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); + } + } + + /* we need to create a new node in this table */ + node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) ); + if ( !node ) + ft_mem_debug_panic( "not enough memory to run memory tests" ); + + node->address = address; + node->size = size; + node->source = source = ft_mem_table_get_source( table ); + + if ( delta == 0 ) + { + /* this is an allocation */ + source->all_blocks++; + source->cur_blocks++; + if ( source->cur_blocks > source->max_blocks ) + source->max_blocks = source->cur_blocks; + } + + if ( size > source->cur_max ) + source->cur_max = size; + + if ( delta != 0 ) + { + /* we are growing or shrinking a reallocated block */ + source->cur_size += delta; + table->alloc_current += delta; + } + else + { + /* we are allocating a new block */ + source->cur_size += size; + table->alloc_current += size; + } + + source->all_size += size; + + if ( source->cur_size > source->max_size ) + source->max_size = source->cur_size; + + node->free_file_name = NULL; + node->free_line_no = 0; + + node->link = pnode[0]; + + pnode[0] = node; + table->nodes++; + + table->alloc_total += size; + + if ( table->alloc_current > table->alloc_max ) + table->alloc_max = table->alloc_current; + + if ( table->nodes * 3 < table->size || + table->size * 3 < table->nodes ) + ft_mem_table_resize( table ); + } + } + + + static void + ft_mem_table_remove( FT_MemTable table, + FT_Byte* address, + FT_Long delta ) + { + if ( table ) + { + FT_MemNode *pnode, node; + + + pnode = ft_mem_table_get_nodep( table, address ); + node = *pnode; + if ( node ) + { + FT_MemSource source; + + + if ( node->size < 0 ) + ft_mem_debug_panic( + "freeing memory block at %p more than once\n" + " at (%s:%ld)!\n" + " Block was allocated at (%s:%ld)\n" + " and released at (%s:%ld).", + address, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_, + FT_FILENAME( node->source->file_name ), node->source->line_no, + FT_FILENAME( node->free_file_name ), node->free_line_no ); + + /* scramble the node's content for additional safety */ + FT_MEM_SET( address, 0xF3, node->size ); + + if ( delta == 0 ) + { + source = node->source; + + source->cur_blocks--; + source->cur_size -= node->size; + + table->alloc_current -= node->size; + } + + if ( table->keep_alive ) + { + /* we simply invert the node's size to indicate that the node */ + /* was freed. */ + node->size = -node->size; + node->free_file_name = ft_debug_file_; + node->free_line_no = ft_debug_lineno_; + } + else + { + table->nodes--; + + *pnode = node->link; + + node->size = 0; + node->source = NULL; + + ft_mem_table_free( table, node ); + + if ( table->nodes * 3 < table->size || + table->size * 3 < table->nodes ) + ft_mem_table_resize( table ); + } + } + else + ft_mem_debug_panic( + "trying to free unknown block at %p in (%s:%ld)\n", + address, + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); + } + } + + + static FT_Pointer + ft_mem_debug_alloc( FT_Memory memory, + FT_Long size ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_Byte* block; + + + if ( size <= 0 ) + ft_mem_debug_panic( "negative block size allocation (%ld)", size ); + + /* return NULL if the maximum number of allocations was reached */ + if ( table->bound_count && + table->alloc_count >= table->alloc_count_max ) + return NULL; + + /* return NULL if this allocation would overflow the maximum heap size */ + if ( table->bound_total && + table->alloc_total_max - table->alloc_current > size ) + return NULL; + + block = (FT_Byte *)ft_mem_table_alloc( table, size ); + if ( block ) + { + ft_mem_table_set( table, block, size, 0 ); + + table->alloc_count++; + } + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + + return (FT_Pointer)block; + } + + + static void + ft_mem_debug_free( FT_Memory memory, + FT_Pointer block ) + { + FT_MemTable table = (FT_MemTable)memory->user; + + + if ( !block ) + ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", + FT_FILENAME( ft_debug_file_ ), + ft_debug_lineno_ ); + + ft_mem_table_remove( table, (FT_Byte*)block, 0 ); + + if ( !table->keep_alive ) + ft_mem_table_free( table, block ); + + table->alloc_count--; + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + } + + + static FT_Pointer + ft_mem_debug_realloc( FT_Memory memory, + FT_Long cur_size, + FT_Long new_size, + FT_Pointer block ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_MemNode node, *pnode; + FT_Pointer new_block; + FT_Long delta; + + const char* file_name = FT_FILENAME( ft_debug_file_ ); + FT_Long line_no = ft_debug_lineno_; + + + /* unlikely, but possible */ + if ( new_size == cur_size ) + return block; + + /* the following is valid according to ANSI C */ +#if 0 + if ( !block || !cur_size ) + ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)", + file_name, line_no ); +#endif + + /* while the following is allowed in ANSI C also, we abort since */ + /* such case should be handled by FreeType. */ + if ( new_size <= 0 ) + ft_mem_debug_panic( + "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)", + block, cur_size, file_name, line_no ); + + /* check `cur_size' value */ + pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block ); + node = *pnode; + if ( !node ) + ft_mem_debug_panic( + "trying to reallocate unknown block at %p in (%s:%ld)", + block, file_name, line_no ); + + if ( node->size <= 0 ) + ft_mem_debug_panic( + "trying to reallocate freed block at %p in (%s:%ld)", + block, file_name, line_no ); + + if ( node->size != cur_size ) + ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is " + "%ld instead of %ld in (%s:%ld)", + block, cur_size, node->size, file_name, line_no ); + + /* return NULL if the maximum number of allocations was reached */ + if ( table->bound_count && + table->alloc_count >= table->alloc_count_max ) + return NULL; + + delta = new_size - cur_size; + + /* return NULL if this allocation would overflow the maximum heap size */ + if ( delta > 0 && + table->bound_total && + table->alloc_current + delta > table->alloc_total_max ) + return NULL; + + new_block = (FT_Pointer)ft_mem_table_alloc( table, new_size ); + if ( !new_block ) + return NULL; + + ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta ); + + ft_memcpy( new_block, block, cur_size < new_size ? (size_t)cur_size + : (size_t)new_size ); + + ft_mem_table_remove( table, (FT_Byte*)block, delta ); + + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; + + if ( !table->keep_alive ) + ft_mem_table_free( table, block ); + + return new_block; + } + + + extern void + ft_mem_debug_init( FT_Memory memory ) + { + FT_MemTable table; + + + if ( !ft_getenv( "FT2_DEBUG_MEMORY" ) ) + return; + + table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); + + if ( table ) + { + FT_ZERO( table ); + + table->memory = memory; + table->memory_user = memory->user; + table->alloc = memory->alloc; + table->realloc = memory->realloc; + table->free = memory->free; + + ft_mem_table_resize( table ); + + if ( table->size ) + { + const char* p; + + + memory->user = table; + memory->alloc = ft_mem_debug_alloc; + memory->realloc = ft_mem_debug_realloc; + memory->free = ft_mem_debug_free; + + p = ft_getenv( "FT2_ALLOC_TOTAL_MAX" ); + if ( p ) + { + FT_Long total_max = ft_strtol( p, NULL, 10 ); + + + if ( total_max > 0 ) + { + table->bound_total = 1; + table->alloc_total_max = total_max; + } + } + + p = ft_getenv( "FT2_ALLOC_COUNT_MAX" ); + if ( p ) + { + FT_Long total_count = ft_strtol( p, NULL, 10 ); + + + if ( total_count > 0 ) + { + table->bound_count = 1; + table->alloc_count_max = total_count; + } + } + + p = ft_getenv( "FT2_KEEP_ALIVE" ); + if ( p ) + { + FT_Long keep_alive = ft_strtol( p, NULL, 10 ); + + + if ( keep_alive > 0 ) + table->keep_alive = 1; + } + } + else + memory->free( memory, table ); + } + } + + + extern void + ft_mem_debug_done( FT_Memory memory ) + { + if ( memory->free == ft_mem_debug_free ) + { + FT_MemTable table = (FT_MemTable)memory->user; + + + FT_DumpMemory( memory ); + + ft_mem_table_destroy( table ); + + memory->free = table->free; + memory->realloc = table->realloc; + memory->alloc = table->alloc; + memory->user = table->memory_user; + + memory->free( memory, table ); + } + } + + + FT_COMPARE_DEF( int ) + ft_mem_source_compare( const void* p1, + const void* p2 ) + { + FT_MemSource s1 = *(FT_MemSource*)p1; + FT_MemSource s2 = *(FT_MemSource*)p2; + + + if ( s2->max_size > s1->max_size ) + return 1; + else if ( s2->max_size < s1->max_size ) + return -1; + else + return 0; + } + + + extern void + FT_DumpMemory( FT_Memory memory ) + { + if ( memory->free == ft_mem_debug_free ) + { + FT_MemTable table = (FT_MemTable)memory->user; + FT_MemSource* bucket = table->sources; + FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS; + FT_MemSource* sources; + FT_Int nn, count; + const char* fmt; + + + count = 0; + for ( ; bucket < limit; bucket++ ) + { + FT_MemSource source = *bucket; + + + for ( ; source; source = source->link ) + count++; + } + + sources = (FT_MemSource*) + ft_mem_table_alloc( + table, count * (FT_Long)sizeof ( *sources ) ); + + count = 0; + for ( bucket = table->sources; bucket < limit; bucket++ ) + { + FT_MemSource source = *bucket; + + + for ( ; source; source = source->link ) + sources[count++] = source; + } + + ft_qsort( sources, + (size_t)count, + sizeof ( *sources ), + ft_mem_source_compare ); + + printf( "FreeType Memory Dump: " + "current=%ld max=%ld total=%ld count=%ld\n", + table->alloc_current, table->alloc_max, + table->alloc_total, table->alloc_count ); + printf( " block block sizes sizes sizes source\n" ); + printf( " count high sum highsum max location\n" ); + printf( "-------------------------------------------------\n" ); + + fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n"; + + for ( nn = 0; nn < count; nn++ ) + { + FT_MemSource source = sources[nn]; + + + printf( fmt, + source->cur_blocks, source->max_blocks, + source->cur_size, source->max_size, source->cur_max, + FT_FILENAME( source->file_name ), + source->line_no ); + } + printf( "------------------------------------------------\n" ); + + ft_mem_table_free( table, sources ); + } + } + +#else /* !FT_DEBUG_MEMORY */ + + /* ANSI C doesn't like empty source files */ + typedef int debug_mem_dummy_; + +#endif /* !FT_DEBUG_MEMORY */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftdebug.c b/Dependencies/freetype/freetype/src/base/ftdebug.c new file mode 100644 index 00000000..11307eaa --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftdebug.c @@ -0,0 +1,644 @@ +/**************************************************************************** + * + * ftdebug.c + * + * Debugging and logging component (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This component contains various macros and functions used to ease the + * debugging of the FreeType engine. Its main purpose is in assertion + * checking, tracing, and error detection. + * + * There are now three debugging modes: + * + * - trace mode + * + * Error and trace messages are sent to the log file (which can be the + * standard error output). + * + * - error mode + * + * Only error messages are generated. + * + * - release mode: + * + * No error message is sent or generated. The code is free from any + * debugging parts. + * + */ + + +#include +#include +#include +#include + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Variables used to control logging. + * + * 1. `ft_default_trace_level` stores the value of trace levels, which are + * provided to FreeType using the `FT2_DEBUG` environment variable. + * + * 2. `ft_fileptr` stores the `FILE*` handle. + * + * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`. + * + * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along + * with the actual log message if set to true. + * + * 5. The flag `ft_timestamp_flag` prints time along with the actual log + * message if set to ture. + * + * 6. `ft_have_newline_char` is used to differentiate between a log + * message with and without a trailing newline character. + * + * 7. `ft_custom_trace_level` stores the custom trace level value, which + * is provided by the user at run-time. + * + * We use `static` to avoid 'unused variable' warnings. + * + */ + static const char* ft_default_trace_level = NULL; + static FILE* ft_fileptr = NULL; + static const char* ft_component = NULL; + static FT_Bool ft_component_flag = FALSE; + static FT_Bool ft_timestamp_flag = FALSE; + static FT_Bool ft_have_newline_char = TRUE; + static const char* ft_custom_trace_level = NULL; + + /* declared in ftdebug.h */ + + dlg_handler ft_default_log_handler = NULL; + FT_Custom_Log_Handler custom_output_handler = NULL; + +#endif /* FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_ERROR + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Panic( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + + exit( EXIT_FAILURE ); + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( int ) + FT_Throw( FT_Error error, + int line, + const char* file ) + { +#if 0 + /* activating the code in this block makes FreeType very chatty */ + fprintf( stderr, + "%s:%d: error 0x%02x: %s\n", + file, + line, + error, + FT_Error_String( error ) ); +#else + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); +#endif + + return 0; + } + +#endif /* FT_DEBUG_LEVEL_ERROR */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* array of trace levels, initialized to 0; */ + /* this gets adjusted at run-time */ + static int ft_trace_levels_enabled[trace_count]; + + /* array of trace levels, always initialized to 0 */ + static int ft_trace_levels_disabled[trace_count]; + + /* a pointer to either `ft_trace_levels_enabled' */ + /* or `ft_trace_levels_disabled' */ + int* ft_trace_levels; + + /* define array of trace toggle names */ +#define FT_TRACE_DEF( x ) #x , + + static const char* ft_trace_toggles[trace_count + 1] = + { +#include + NULL + }; + +#undef FT_TRACE_DEF + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return trace_count; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + int max = FT_Trace_Get_Count(); + + + if ( idx < max ) + return ft_trace_toggles[idx]; + else + return NULL; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + ft_trace_levels = ft_trace_levels_disabled; + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + ft_trace_levels = ft_trace_levels_enabled; + } + + + /************************************************************************** + * + * Initialize the tracing sub-system. This is done by retrieving the + * value of the `FT2_DEBUG' environment variable. It must be a list of + * toggles, separated by spaces, `;', or `,'. Example: + * + * export FT2_DEBUG="any:3 memory:7 stream:5" + * + * This requests that all levels be set to 3, except the trace level for + * the memory and stream components which are set to 7 and 5, + * respectively. + * + * See the file `include/freetype/internal/fttrace.h' for details of + * the available toggle names. + * + * The level must be between 0 and 7; 0 means quiet (except for serious + * runtime errors), and 7 means _very_ verbose. + */ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + const char* ft2_debug = NULL; + + +#ifdef FT_DEBUG_LOGGING + if ( ft_custom_trace_level != NULL ) + ft2_debug = ft_custom_trace_level; + else + ft2_debug = ft_default_trace_level; +#else + ft2_debug = ft_getenv( "FT2_DEBUG" ); +#endif + + if ( ft2_debug ) + { + const char* p = ft2_debug; + const char* q; + + + for ( ; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) + continue; + +#ifdef FT_DEBUG_LOGGING + + /* check extra arguments for logging */ + if ( *p == '-' ) + { + const char* r = ++p; + + + if ( *r == 'v' ) + { + const char* s = ++r; + + + ft_component_flag = TRUE; + + if ( *s == 't' ) + { + ft_timestamp_flag = TRUE; + p++; + } + + p++; + } + + else if ( *r == 't' ) + { + const char* s = ++r; + + + ft_timestamp_flag = TRUE; + + if ( *s == 'v' ) + { + ft_component_flag = TRUE; + p++; + } + + p++; + } + } + +#endif /* FT_DEBUG_LOGGING */ + + /* read toggle name, followed by ':' */ + q = p; + while ( *p && *p != ':' ) + p++; + + if ( !*p ) + break; + + if ( *p == ':' && p > q ) + { + FT_Int n, i, len = (FT_Int)( p - q ); + FT_Int level = -1, found = -1; + + + for ( n = 0; n < trace_count; n++ ) + { + const char* toggle = ft_trace_toggles[n]; + + + for ( i = 0; i < len; i++ ) + { + if ( toggle[i] != q[i] ) + break; + } + + if ( i == len && toggle[i] == 0 ) + { + found = n; + break; + } + } + + /* read level */ + p++; + if ( *p ) + { + level = *p - '0'; + if ( level < 0 || level > 7 ) + level = -1; + } + + if ( found >= 0 && level >= 0 ) + { + if ( found == trace_any ) + { + /* special case for `any' */ + for ( n = 0; n < trace_count; n++ ) + ft_trace_levels_enabled[n] = level; + } + else + ft_trace_levels_enabled[found] = level; + } + } + } + } + + ft_trace_levels = ft_trace_levels_enabled; + } + + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + + FT_BASE_DEF( void ) + ft_debug_init( void ) + { + /* nothing */ + } + + + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + + + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + + return NULL; + } + + + FT_BASE_DEF( void ) + FT_Trace_Disable( void ) + { + /* nothing */ + } + + + /* documentation is in ftdebug.h */ + + FT_BASE_DEF( void ) + FT_Trace_Enable( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Initialize and de-initialize 'dlg' library. + * + */ + + FT_BASE_DEF( void ) + ft_logging_init( void ) + { + ft_default_log_handler = ft_log_handler; + ft_default_trace_level = ft_getenv( "FT2_DEBUG" ); + + if ( ft_getenv( "FT_LOGGING_FILE" ) ) + ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" ); + else + ft_fileptr = stderr; + + ft_debug_init(); + + /* Set the default output handler for 'dlg'. */ + dlg_set_handler( ft_default_log_handler, NULL ); + } + + + FT_BASE_DEF( void ) + ft_logging_deinit( void ) + { + if ( ft_fileptr != stderr ) + ft_fclose( ft_fileptr ); + } + + + /************************************************************************** + * + * An output log handler for FreeType. + * + */ + FT_BASE_DEF( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ) + { + char features_buf[128]; + char* bufp = features_buf; + + FT_UNUSED( data ); + + + if ( ft_have_newline_char ) + { + const char* features = NULL; + size_t features_length = 0; + + +#define FEATURES_TIMESTAMP "[%h:%m] " +#define FEATURES_COMPONENT "[%t] " +#define FEATURES_TIMESTAMP_COMPONENT "[%h:%m %t] " + + if ( ft_timestamp_flag && ft_component_flag ) + { + features = FEATURES_TIMESTAMP_COMPONENT; + features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT ); + } + else if ( ft_timestamp_flag ) + { + features = FEATURES_TIMESTAMP; + features_length = sizeof ( FEATURES_TIMESTAMP ); + } + else if ( ft_component_flag ) + { + features = FEATURES_COMPONENT; + features_length = sizeof ( FEATURES_COMPONENT ); + } + + if ( ft_component_flag || ft_timestamp_flag ) + { + ft_strncpy( features_buf, features, features_length ); + bufp += features_length - 1; + } + + if ( ft_component_flag ) + { + size_t tag_length = ft_strlen( *origin->tags ); + size_t i; + + + /* To vertically align tracing messages we compensate the */ + /* different FT_COMPONENT string lengths by inserting an */ + /* appropriate amount of space characters. */ + for ( i = 0; + i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length; + i++ ) + *bufp++ = ' '; + } + } + + /* Finally add the format string for the tracing message. */ + *bufp++ = '%'; + *bufp++ = 'c'; + *bufp = '\0'; + + dlg_generic_outputf_stream( ft_fileptr, + (const char*)features_buf, + origin, + string, + dlg_default_output_styles, + true ); + + if ( ft_strrchr( string, '\n' ) ) + ft_have_newline_char = TRUE; + else + ft_have_newline_char = FALSE; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_add_tag( const char* tag ) + { + ft_component = tag; + + dlg_add_tag( tag, NULL ); + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_remove_tag( const char* tag ) + { + dlg_remove_tag( tag, NULL ); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = level; + + ft_debug_init(); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = NULL; + + ft_debug_init(); + } + + + /************************************************************************** + * + * Functions to handle a custom log handler. + * + */ + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + custom_output_handler = handler; + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + custom_output_handler = NULL; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + FT_Logging_Callback( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + custom_output_handler( ft_component, fmt, ap ); + va_end( ap ); + } + +#else /* !FT_DEBUG_LOGGING */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + FT_UNUSED( level ); + } + + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + /* nothing */ + } + + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + FT_UNUSED( handler ); + } + + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LOGGING */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/fterrors.c b/Dependencies/freetype/freetype/src/base/fterrors.c new file mode 100644 index 00000000..61041a37 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/fterrors.c @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * fterrors.c + * + * FreeType API for error code handling. + * + * Copyright (C) 2018-2024 by + * Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + /* documentation is in fterrors.h */ + + FT_EXPORT_DEF( const char* ) + FT_Error_String( FT_Error error_code ) + { + if ( error_code < 0 || + error_code >= FT_ERR_CAT( FT_ERR_PREFIX, Max ) ) + return NULL; + +#if defined( FT_CONFIG_OPTION_ERROR_STRINGS ) || \ + defined( FT_DEBUG_LEVEL_ERROR ) + +#undef FTERRORS_H_ +#define FT_ERROR_START_LIST switch ( FT_ERROR_BASE( error_code ) ) { +#define FT_ERRORDEF( e, v, s ) case v: return s; +#define FT_ERROR_END_LIST } + +#include + +#endif /* defined( FT_CONFIG_OPTION_ERROR_STRINGS ) || ... */ + + return NULL; + } diff --git a/Dependencies/freetype/freetype/src/base/ftfntfmt.c b/Dependencies/freetype/freetype/src/base/ftfntfmt.c new file mode 100644 index 00000000..77b4089e --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftfntfmt.c @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * ftfntfmt.c + * + * FreeType utility file for font formats (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + + + /* documentation is in ftfntfmt.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_Font_Format( FT_Face face ) + { + const char* result = NULL; + + + if ( face ) + FT_FACE_FIND_SERVICE( face, result, FONT_FORMAT ); + + return result; + } + + + /* deprecated function name; retained for ABI compatibility */ + + FT_EXPORT_DEF( const char* ) + FT_Get_X11_Font_Format( FT_Face face ) + { + const char* result = NULL; + + + if ( face ) + FT_FACE_FIND_SERVICE( face, result, FONT_FORMAT ); + + return result; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftfstype.c b/Dependencies/freetype/freetype/src/base/ftfstype.c new file mode 100644 index 00000000..1565c3b7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftfstype.c @@ -0,0 +1,61 @@ +/**************************************************************************** + * + * ftfstype.c + * + * FreeType utility file to access FSType data (body). + * + * Copyright (C) 2008-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ) + { + TT_OS2* os2; + + + /* first, try to get the fs_type directly from the font */ + if ( face ) + { + FT_Service_PsInfo service = NULL; + + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_extra ) + { + PS_FontExtraRec extra; + + + if ( !service->ps_get_font_extra( face, &extra ) && + extra.fs_type != 0 ) + return extra.fs_type; + } + } + + /* look at FSType before fsType for Type42 */ + + if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, FT_SFNT_OS2 ) ) != NULL && + os2->version != 0xFFFFU ) + return os2->fsType; + + return 0; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftgasp.c b/Dependencies/freetype/freetype/src/base/ftgasp.c new file mode 100644 index 00000000..c63d30e9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftgasp.c @@ -0,0 +1,60 @@ +/**************************************************************************** + * + * ftgasp.c + * + * Access of TrueType's `gasp' table (body). + * + * Copyright (C) 2007-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ) + { + FT_Int result = FT_GASP_NO_TABLE; + + + if ( face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->gasp.numRanges > 0 ) + { + TT_GaspRange range = ttface->gasp.gaspRanges; + TT_GaspRange range_end = range + ttface->gasp.numRanges; + + + while ( ppem > range->maxPPEM ) + { + range++; + if ( range >= range_end ) + goto Exit; + } + + result = range->gaspFlag; + + /* ensure that we don't have spurious bits */ + if ( ttface->gasp.version == 0 ) + result &= 3; + } + } + Exit: + return result; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftgloadr.c b/Dependencies/freetype/freetype/src/base/ftgloadr.c new file mode 100644 index 00000000..484d98f1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftgloadr.c @@ -0,0 +1,383 @@ +/**************************************************************************** + * + * ftgloadr.c + * + * The FreeType glyph loader (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT gloader + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** G L Y P H L O A D E R *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * The glyph loader is a simple object which is used to load a set of + * glyphs easily. It is critical for the correct loading of composites. + * + * Ideally, one can see it as a stack of abstract `glyph' objects. + * + * loader.base Is really the bottom of the stack. It describes a + * single glyph image made of the juxtaposition of + * several glyphs (those `in the stack'). + * + * loader.current Describes the top of the stack, on which a new + * glyph can be loaded. + * + * Rewind Clears the stack. + * Prepare Set up `loader.current' for addition of a new glyph + * image. + * Add Add the `current' glyph image to the `base' one, + * and prepare for another one. + * + * The glyph loader is now a base object. Each driver used to + * re-implement it in one way or the other, which wasted code and + * energy. + * + */ + + + /* create a new glyph loader */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ) + { + FT_GlyphLoader loader = NULL; + FT_Error error; + + + if ( !FT_NEW( loader ) ) + { + loader->memory = memory; + *aloader = loader; + } + return error; + } + + + /* rewind the glyph loader - reset counters to 0 */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + base->outline.n_points = 0; + base->outline.n_contours = 0; + base->outline.flags = 0; + base->num_subglyphs = 0; + + *current = *base; + } + + + /* reset glyph loader, free all allocated tables, */ + /* and start from zero */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ) + { + FT_Memory memory = loader->memory; + + + FT_FREE( loader->base.outline.points ); + FT_FREE( loader->base.outline.tags ); + FT_FREE( loader->base.outline.contours ); + FT_FREE( loader->base.extra_points ); + FT_FREE( loader->base.subglyphs ); + + loader->base.extra_points2 = NULL; + + loader->max_points = 0; + loader->max_contours = 0; + loader->max_subglyphs = 0; + + FT_GlyphLoader_Rewind( loader ); + } + + + /* delete a glyph loader */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ) + { + if ( loader ) + { + FT_Memory memory = loader->memory; + + + FT_GlyphLoader_Reset( loader ); + FT_FREE( loader ); + } + } + + + /* re-adjust the `current' outline fields */ + static void + FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) + { + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + + + current->points = FT_OFFSET( base->points, base->n_points ); + current->tags = FT_OFFSET( base->tags, base->n_points ); + current->contours = FT_OFFSET( base->contours, base->n_contours ); + + /* handle extra points table - if any */ + if ( loader->use_extra ) + { + loader->current.extra_points = loader->base.extra_points + + base->n_points; + + loader->current.extra_points2 = loader->base.extra_points2 + + base->n_points; + } + } + + + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) + { + FT_Error error; + FT_Memory memory = loader->memory; + + + if ( loader->max_points == 0 || + loader->base.extra_points != NULL ) + return FT_Err_Ok; + + if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) + { + loader->use_extra = 1; + loader->base.extra_points2 = loader->base.extra_points + + loader->max_points; + + FT_GlyphLoader_Adjust_Points( loader ); + } + return error; + } + + + /* re-adjust the `current' subglyphs field */ + static void + FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + current->subglyphs = FT_OFFSET( base->subglyphs, base->num_subglyphs ); + } + + + /* Ensure that we can add `n_points' and `n_contours' to our glyph. */ + /* This function reallocates its outline tables if necessary. Note that */ + /* it DOESN'T change the number of points within the loader! */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + FT_Bool adjust = 0; + + FT_UInt new_max, old_max, min_new_max; + + + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + + /* check points & tags */ + new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + + n_points; + old_max = loader->max_points; + + if ( new_max > old_max ) + { + if ( new_max > FT_OUTLINE_POINTS_MAX ) + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( new_max > FT_OUTLINE_POINTS_MAX ) + new_max = FT_OUTLINE_POINTS_MAX; + + if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || + FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) + goto Exit; + + if ( loader->use_extra ) + { + if ( FT_RENEW_ARRAY( loader->base.extra_points, + old_max * 2, new_max * 2 ) ) + goto Exit; + + FT_ARRAY_MOVE( loader->base.extra_points + new_max, + loader->base.extra_points + old_max, + old_max ); + + loader->base.extra_points2 = loader->base.extra_points + new_max; + } + + adjust = 1; + loader->max_points = new_max; + } + + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + + /* check contours */ + old_max = loader->max_contours; + new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + + n_contours; + if ( new_max > old_max ) + { + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 4 ); + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + new_max = FT_OUTLINE_CONTOURS_MAX; + + if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) + goto Exit; + + adjust = 1; + loader->max_contours = new_max; + } + + if ( adjust ) + FT_GlyphLoader_Adjust_Points( loader ); + + Exit: + if ( error ) + FT_GlyphLoader_Reset( loader ); + + return error; + } + + + /* Ensure that we can add `n_subglyphs' to our glyph. this function */ + /* reallocates its subglyphs table if necessary. Note that it DOES */ + /* NOT change the number of subglyphs within the loader! */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_UInt new_max, old_max; + + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + + + new_max = base->num_subglyphs + current->num_subglyphs + n_subs; + old_max = loader->max_subglyphs; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 2 ); + if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) + goto Exit; + + loader->max_subglyphs = new_max; + + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + Exit: + return error; + } + + + /* prepare loader for the addition of a new glyph on top of the base one */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) + { + FT_GlyphLoad current = &loader->current; + + + current->outline.n_points = 0; + current->outline.n_contours = 0; + current->num_subglyphs = 0; + + FT_GlyphLoader_Adjust_Points ( loader ); + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + + + /* add current glyph to the base image -- and prepare for another */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ) + { + FT_Outline* base; + FT_Outline* current; + FT_Int n; + + + if ( !loader ) + return; + + base = &loader->base.outline; + current = &loader->current.outline; + + /* adjust contours count in newest outline */ + for ( n = 0; n < current->n_contours; n++ ) + current->contours[n] += base->n_points; + + base->n_points += current->n_points; + base->n_contours += current->n_contours; + + loader->base.num_subglyphs += loader->current.num_subglyphs; + + /* prepare for another new glyph image */ + FT_GlyphLoader_Prepare( loader ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftglyph.c b/Dependencies/freetype/freetype/src/base/ftglyph.c new file mode 100644 index 00000000..1b5849f9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftglyph.c @@ -0,0 +1,911 @@ +/**************************************************************************** + * + * ftglyph.c + * + * FreeType convenience functions to handle glyphs (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file contains the definition of several convenience functions + * that can be used by client applications to easily retrieve glyph + * bitmaps and outlines from a given face. + * + * These functions should be optional if you are writing a font server + * or text layout engine on top of FreeType. However, they are pretty + * handy for many other simple uses of the library. + * + */ + + +#include + +#include +#include +#include +#include +#include + +#include "ftbase.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT glyph + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_BitmapGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_init( FT_Glyph bitmap_glyph, + FT_GlyphSlot slot ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + glyph->left = slot->bitmap_left; + glyph->top = slot->bitmap_top; + + /* do lazy copying whenever possible */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + glyph->bitmap = slot->bitmap; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + FT_Bitmap_Init( &glyph->bitmap ); + error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_copy( FT_Glyph bitmap_source, + FT_Glyph bitmap_target ) + { + FT_Library library = bitmap_source->library; + FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source; + FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target; + + + target->left = source->left; + target->top = source->top; + + return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); + } + + + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_done( FT_Glyph bitmap_glyph ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Library library = FT_GLYPH( glyph )->library; + + + FT_Bitmap_Done( library, &glyph->bitmap ); + } + + + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph, + FT_BBox* cbox ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + + + cbox->xMin = glyph->left * 64; + cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 ); + cbox->yMax = glyph->top * 64; + cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 ); + } + + + FT_DEFINE_GLYPH( + ft_bitmap_glyph_class, + + sizeof ( FT_BitmapGlyphRec ), + FT_GLYPH_FORMAT_BITMAP, + + ft_bitmap_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_bitmap_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_bitmap_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + NULL, /* FT_Glyph_TransformFunc glyph_transform */ + ft_bitmap_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + NULL /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_OutlineGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_init( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + FT_Outline* source = &slot->outline; + FT_Outline* target = &glyph->outline; + + + /* check format in glyph slot */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* allocate new outline */ + error = FT_Outline_New( library, + (FT_UInt)source->n_points, + source->n_contours, + &glyph->outline ); + if ( error ) + goto Exit; + + FT_Outline_Copy( source, target ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_done( FT_Glyph outline_glyph ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_copy( FT_Glyph outline_source, + FT_Glyph outline_target ) + { + FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source; + FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target; + FT_Error error; + FT_Library library = FT_GLYPH( source )->library; + + + error = FT_Outline_New( library, + (FT_UInt)source->outline.n_points, + source->outline.n_contours, + &target->outline ); + if ( !error ) + FT_Outline_Copy( &source->outline, &target->outline ); + + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_transform( FT_Glyph outline_glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + if ( matrix ) + FT_Outline_Transform( &glyph->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); + } + + + FT_CALLBACK_DEF( void ) + ft_outline_glyph_bbox( FT_Glyph outline_glyph, + FT_BBox* bbox ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + FT_Outline_Get_CBox( &glyph->outline, bbox ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_prepare( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + + + slot->format = FT_GLYPH_FORMAT_OUTLINE; + slot->outline = glyph->outline; + slot->outline.flags &= ~FT_OUTLINE_OWNER; + + return FT_Err_Ok; + } + + + FT_DEFINE_GLYPH( + ft_outline_glyph_class, + + sizeof ( FT_OutlineGlyphRec ), + FT_GLYPH_FORMAT_OUTLINE, + + ft_outline_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_outline_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_outline_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_outline_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + ft_outline_glyph_bbox, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_outline_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + + +#ifdef FT_CONFIG_OPTION_SVG + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_SvgGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_init( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_ULong doc_length; + FT_SVG_Document document; + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( glyph )->library->memory; + + + if ( slot->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( slot->other == NULL ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + document = (FT_SVG_Document)slot->other; + + if ( document->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + /* allocate a new document */ + doc_length = document->svg_document_length; + if ( FT_QALLOC( glyph->svg_document, doc_length ) ) + goto Exit; + glyph->svg_document_length = doc_length; + + glyph->glyph_index = slot->glyph_index; + + glyph->metrics = document->metrics; + glyph->units_per_EM = document->units_per_EM; + + glyph->start_glyph_id = document->start_glyph_id; + glyph->end_glyph_id = document->end_glyph_id; + + glyph->transform = document->transform; + glyph->delta = document->delta; + + /* copy the document into glyph */ + FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_done( FT_Glyph svg_glyph ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Memory memory = svg_glyph->library->memory; + + + /* just free the memory */ + FT_FREE( glyph->svg_document ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_copy( FT_Glyph svg_source, + FT_Glyph svg_target ) + { + FT_SvgGlyph source = (FT_SvgGlyph)svg_source; + FT_SvgGlyph target = (FT_SvgGlyph)svg_target; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( source )->library->memory; + + + if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( source->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + target->glyph_index = source->glyph_index; + + target->svg_document_length = source->svg_document_length; + + target->metrics = source->metrics; + target->units_per_EM = source->units_per_EM; + + target->start_glyph_id = source->start_glyph_id; + target->end_glyph_id = source->end_glyph_id; + + target->transform = source->transform; + target->delta = source->delta; + + /* allocate space for the SVG document */ + if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) + goto Exit; + + /* copy the document */ + FT_MEM_COPY( target->svg_document, + source->svg_document, + target->svg_document_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_transform( FT_Glyph svg_glyph, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = glyph->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), + FT_MulFix( matrix->xy, glyph->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), + FT_MulFix( matrix->yy, glyph->delta.y ) ), + delta->y ); + + glyph->delta.x = x; + glyph->delta.y = y; + + glyph->transform = a; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_prepare( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = svg_glyph->library->memory; + + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + return error; + + document->svg_document = glyph->svg_document; + document->svg_document_length = glyph->svg_document_length; + + document->metrics = glyph->metrics; + document->units_per_EM = glyph->units_per_EM; + + document->start_glyph_id = glyph->start_glyph_id; + document->end_glyph_id = glyph->end_glyph_id; + + document->transform = glyph->transform; + document->delta = glyph->delta; + + slot->format = FT_GLYPH_FORMAT_SVG; + slot->glyph_index = glyph->glyph_index; + slot->other = document; + + return error; + } + + + FT_DEFINE_GLYPH( + ft_svg_glyph_class, + + sizeof ( FT_SvgGlyphRec ), + FT_GLYPH_FORMAT_SVG, + + ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + +#endif /* FT_CONFIG_OPTION_SVG */ + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_Glyph class and API ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + ft_new_glyph( FT_Library library, + const FT_Glyph_Class* clazz, + FT_Glyph* aglyph ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Glyph glyph = NULL; + + + *aglyph = NULL; + + if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) + { + glyph->library = library; + glyph->clazz = clazz; + glyph->format = clazz->glyph_format; + + *aglyph = glyph; + } + + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ) + { + FT_Glyph copy; + FT_Error error; + const FT_Glyph_Class* clazz; + + + /* check arguments */ + if ( !target || !source || !source->clazz ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + *target = NULL; + + if ( !source || !source->clazz ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + clazz = source->clazz; + error = ft_new_glyph( source->library, clazz, © ); + if ( error ) + goto Exit; + + copy->advance = source->advance; + copy->format = source->format; + + if ( clazz->glyph_copy ) + error = clazz->glyph_copy( source, copy ); + + if ( error ) + FT_Done_Glyph( copy ); + else + *target = copy; + + Exit: + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT( FT_Error ) + FT_New_Glyph( FT_Library library, + FT_Glyph_Format format, + FT_Glyph *aglyph ) + { + const FT_Glyph_Class* clazz = NULL; + + if ( !library || !aglyph ) + return FT_THROW( Invalid_Argument ); + + /* if it is a bitmap, that's easy :-) */ + if ( format == FT_GLYPH_FORMAT_BITMAP ) + clazz = &ft_bitmap_glyph_class; + + /* if it is an outline */ + else if ( format == FT_GLYPH_FORMAT_OUTLINE ) + clazz = &ft_outline_glyph_class; + +#ifdef FT_CONFIG_OPTION_SVG + /* if it is an SVG glyph */ + else if ( format == FT_GLYPH_FORMAT_SVG ) + clazz = &ft_svg_glyph_class; +#endif + + else + { + /* try to find a renderer that supports the glyph image format */ + FT_Renderer render = FT_Lookup_Renderer( library, format, 0 ); + + + if ( render ) + clazz = &render->glyph_class; + } + + if ( !clazz ) + return FT_THROW( Invalid_Glyph_Format ); + + /* create FT_Glyph object */ + return ft_new_glyph( library, clazz, aglyph ); + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ) + { + FT_Error error; + FT_Glyph glyph; + + + if ( !slot ) + return FT_THROW( Invalid_Slot_Handle ); + + if ( !aglyph ) + return FT_THROW( Invalid_Argument ); + + /* create FT_Glyph object */ + error = FT_New_Glyph( slot->library, slot->format, &glyph ); + if ( error ) + goto Exit; + + /* copy advance while converting 26.6 to 16.16 format */ + if ( slot->advance.x >= 0x8000L * 64 || + slot->advance.x <= -0x8000L * 64 ) + { + FT_ERROR(( "FT_Get_Glyph: advance width too large\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit2; + } + if ( slot->advance.y >= 0x8000L * 64 || + slot->advance.y <= -0x8000L * 64 ) + { + FT_ERROR(( "FT_Get_Glyph: advance height too large\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit2; + } + + glyph->advance.x = slot->advance.x * 1024; + glyph->advance.y = slot->advance.y * 1024; + + /* now import the image from the glyph slot */ + error = glyph->clazz->glyph_init( glyph, slot ); + + Exit2: + /* if an error occurred, destroy the glyph */ + if ( error ) + { + FT_Done_Glyph( glyph ); + *aglyph = NULL; + } + else + *aglyph = glyph; + + Exit: + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( !glyph || !glyph->clazz ) + error = FT_THROW( Invalid_Argument ); + else + { + const FT_Glyph_Class* clazz = glyph->clazz; + + + if ( clazz->glyph_transform ) + { + /* transform glyph image */ + clazz->glyph_transform( glyph, matrix, delta ); + + /* transform advance vector */ + if ( matrix ) + FT_Vector_Transform( &glyph->advance, matrix ); + } + else + error = FT_THROW( Invalid_Glyph_Format ); + } + return error; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ) + { + const FT_Glyph_Class* clazz; + + + if ( !acbox ) + return; + + acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; + + if ( !glyph || !glyph->clazz ) + return; + + clazz = glyph->clazz; + if ( !clazz->glyph_bbox ) + return; + + /* retrieve bbox in 26.6 coordinates */ + clazz->glyph_bbox( glyph, acbox ); + + /* perform grid fitting if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); + acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); + acbox->xMax = FT_PIX_CEIL_LONG( acbox->xMax ); + acbox->yMax = FT_PIX_CEIL_LONG( acbox->yMax ); + } + + /* convert to integer pixels if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin >>= 6; + acbox->yMin >>= 6; + acbox->xMax >>= 6; + acbox->yMax >>= 6; + } + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ) + { + FT_GlyphSlotRec dummy; + FT_GlyphSlot_InternalRec dummy_internal; + FT_Error error = FT_Err_Ok; + FT_Glyph b, glyph; + FT_BitmapGlyph bitmap = NULL; + const FT_Glyph_Class* clazz; + + FT_Library library; + + + /* check argument */ + if ( !the_glyph ) + goto Bad; + glyph = *the_glyph; + if ( !glyph ) + goto Bad; + + clazz = glyph->clazz; + library = glyph->library; + if ( !library || !clazz ) + goto Bad; + + /* when called with a bitmap glyph, do nothing and return successfully */ + if ( clazz == &ft_bitmap_glyph_class ) + goto Exit; + + if ( !clazz->glyph_prepare ) + goto Bad; + + /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ + /* then calling FT_Render_Glyph_Internal() */ + + FT_ZERO( &dummy ); + FT_ZERO( &dummy_internal ); + dummy.internal = &dummy_internal; + dummy.library = library; + dummy.format = clazz->glyph_format; + + /* create result bitmap glyph */ + error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b ); + if ( error ) + goto Exit; + bitmap = (FT_BitmapGlyph)b; + +#if 1 + /* if `origin' is set, translate the glyph image */ + if ( origin ) + FT_Glyph_Transform( glyph, NULL, origin ); +#else + FT_UNUSED( origin ); +#endif + + /* prepare dummy slot for rendering */ + error = clazz->glyph_prepare( glyph, &dummy ); + if ( !error ) + error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); + +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz == &ft_svg_glyph_class ) + { + FT_Memory memory = library->memory; + + + FT_FREE( dummy.other ); + } +#endif + +#if 1 + if ( !destroy && origin ) + { + FT_Vector v; + + + v.x = -origin->x; + v.y = -origin->y; + FT_Glyph_Transform( glyph, NULL, &v ); + } +#endif + + if ( error ) + goto Exit; + + /* in case of success, copy the bitmap to the glyph bitmap */ + error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); + if ( error ) + goto Exit; + + /* copy advance */ + bitmap->root.advance = glyph->advance; + + if ( destroy ) + FT_Done_Glyph( glyph ); + + *the_glyph = FT_GLYPH( bitmap ); + + Exit: + if ( error && bitmap ) + FT_Done_Glyph( FT_GLYPH( bitmap ) ); + + return error; + + Bad: + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + + /* documentation is in ftglyph.h */ + + FT_EXPORT_DEF( void ) + FT_Done_Glyph( FT_Glyph glyph ) + { + if ( glyph ) + { + FT_Memory memory = glyph->library->memory; + const FT_Glyph_Class* clazz = glyph->clazz; + + + if ( clazz->glyph_done ) + clazz->glyph_done( glyph ); + + FT_FREE( glyph ); + } + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftgxval.c b/Dependencies/freetype/freetype/src/base/ftgxval.c new file mode 100644 index 00000000..6e38cb5b --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftgxval.c @@ -0,0 +1,141 @@ +/**************************************************************************** + * + * ftgxval.c + * + * FreeType API for validating TrueTypeGX/AAT tables (body). + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO, Redhat K.K, + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include + +#include +#include + + + /* documentation is in ftgxval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ) + { + FT_Service_GXvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !tables ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + tables, + table_length ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( table ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ) + { + FT_Service_CKERNvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !ckern_table ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + ckern_table ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + + FT_FREE( table ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/fthash.c b/Dependencies/freetype/freetype/src/base/fthash.c new file mode 100644 index 00000000..313bbbb4 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/fthash.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * fthash.c + * + * Hashing functions (body). + * + */ + +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2015 + * Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on code from bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + +#include +#include + + +#define INITIAL_HT_SIZE 241 + + + static FT_ULong + hash_str_lookup( FT_Hashkey* key ) + { + const char* kp = key->str; + FT_ULong res = 0; + + + /* Mocklisp hash function. */ + while ( *kp ) + res = ( res << 5 ) - res + (FT_ULong)*kp++; + + return res; + } + + + static FT_ULong + hash_num_lookup( FT_Hashkey* key ) + { + FT_ULong num = (FT_ULong)key->num; + FT_ULong res; + + + /* Mocklisp hash function. */ + res = num & 0xFF; + res = ( res << 5 ) - res + ( ( num >> 8 ) & 0xFF ); + res = ( res << 5 ) - res + ( ( num >> 16 ) & 0xFF ); + res = ( res << 5 ) - res + ( ( num >> 24 ) & 0xFF ); + + return res; + } + + + static FT_Bool + hash_str_compare( FT_Hashkey* a, + FT_Hashkey* b ) + { + if ( a->str[0] == b->str[0] && + ft_strcmp( a->str, b->str ) == 0 ) + return 1; + + return 0; + } + + + static FT_Bool + hash_num_compare( FT_Hashkey* a, + FT_Hashkey* b ) + { + if ( a->num == b->num ) + return 1; + + return 0; + } + + + static FT_Hashnode* + hash_bucket( FT_Hashkey key, + FT_Hash hash ) + { + FT_ULong res = 0; + FT_Hashnode* bp = hash->table; + FT_Hashnode* ndp; + + + res = (hash->lookup)( &key ); + + ndp = bp + ( res % hash->size ); + while ( *ndp ) + { + if ( (hash->compare)( &(*ndp)->key, &key ) ) + break; + + ndp--; + if ( ndp < bp ) + ndp = bp + ( hash->size - 1 ); + } + + return ndp; + } + + + static FT_Error + hash_rehash( FT_Hash hash, + FT_Memory memory ) + { + FT_Hashnode* obp = hash->table; + FT_Hashnode* bp; + FT_Hashnode* nbp; + + FT_UInt i, sz = hash->size; + FT_Error error = FT_Err_Ok; + + + hash->size <<= 1; + hash->limit = hash->size / 3; + + if ( FT_NEW_ARRAY( hash->table, hash->size ) ) + goto Exit; + + for ( i = 0, bp = obp; i < sz; i++, bp++ ) + { + if ( *bp ) + { + nbp = hash_bucket( (*bp)->key, hash ); + *nbp = *bp; + } + } + + FT_FREE( obp ); + + Exit: + return error; + } + + + static FT_Error + hash_init( FT_Hash hash, + FT_Bool is_num, + FT_Memory memory ) + { + FT_UInt sz = INITIAL_HT_SIZE; + FT_Error error; + + + hash->size = sz; + hash->limit = sz / 3; + hash->used = 0; + + if ( is_num ) + { + hash->lookup = hash_num_lookup; + hash->compare = hash_num_compare; + } + else + { + hash->lookup = hash_str_lookup; + hash->compare = hash_str_compare; + } + + FT_MEM_NEW_ARRAY( hash->table, sz ); + + return error; + } + + + FT_Error + ft_hash_str_init( FT_Hash hash, + FT_Memory memory ) + { + return hash_init( hash, 0, memory ); + } + + + FT_Error + ft_hash_num_init( FT_Hash hash, + FT_Memory memory ) + { + return hash_init( hash, 1, memory ); + } + + + void + ft_hash_str_free( FT_Hash hash, + FT_Memory memory ) + { + if ( hash ) + { + FT_UInt sz = hash->size; + FT_Hashnode* bp = hash->table; + FT_UInt i; + + + for ( i = 0; i < sz; i++, bp++ ) + FT_FREE( *bp ); + + FT_FREE( hash->table ); + } + } + + + /* `ft_hash_num_free' is the same as `ft_hash_str_free' */ + + + static FT_Error + hash_insert( FT_Hashkey key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashnode nn; + FT_Hashnode* bp = hash_bucket( key, hash ); + FT_Error error = FT_Err_Ok; + + + nn = *bp; + if ( !nn ) + { + if ( FT_QNEW( nn ) ) + goto Exit; + *bp = nn; + + nn->key = key; + nn->data = data; + + if ( hash->used >= hash->limit ) + { + error = hash_rehash( hash, memory ); + if ( error ) + goto Exit; + } + + hash->used++; + } + else + nn->data = data; + + Exit: + return error; + } + + + FT_Error + ft_hash_str_insert( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_insert( hk, data, hash, memory ); + } + + + FT_Error + ft_hash_num_insert( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_insert( hk, data, hash, memory ); + } + + + static size_t* + hash_lookup( FT_Hashkey key, + FT_Hash hash ) + { + FT_Hashnode* np = hash_bucket( key, hash ); + + + return (*np) ? &(*np)->data + : NULL; + } + + + size_t* + ft_hash_str_lookup( const char* key, + FT_Hash hash ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_lookup( hk, hash ); + } + + + size_t* + ft_hash_num_lookup( FT_Int num, + FT_Hash hash ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_lookup( hk, hash ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftinit.c b/Dependencies/freetype/freetype/src/base/ftinit.c new file mode 100644 index 00000000..9a6c00e1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftinit.c @@ -0,0 +1,263 @@ +/**************************************************************************** + * + * ftinit.c + * + * FreeType initialization layer (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * The purpose of this file is to implement the following two + * functions: + * + * FT_Add_Default_Modules(): + * This function is used to add the set of default modules to a + * fresh new library object. The set is taken from the header file + * `freetype/config/ftmodule.h'. See the document `FreeType 2.0 + * Build System' for more information. + * + * FT_Init_FreeType(): + * This function creates a system object for the current platform, + * builds a library out of it, then calls FT_Default_Drivers(). + * + * Note that even if FT_Init_FreeType() uses the implementation of the + * system object defined at build time, client applications are still + * able to provide their own `ftsystem.c'. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT init + + +#undef FT_USE_MODULE +#ifdef __cplusplus +#define FT_USE_MODULE( type, x ) extern "C" const type x; +#else +#define FT_USE_MODULE( type, x ) extern const type x; +#endif + +#include FT_CONFIG_MODULES_H + +#undef FT_USE_MODULE +#define FT_USE_MODULE( type, x ) (const FT_Module_Class*)&(x), + + static + const FT_Module_Class* const ft_default_modules[] = + { +#include FT_CONFIG_MODULES_H + 0 + }; + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Add_Default_Modules( FT_Library library ) + { + FT_Error error; + const FT_Module_Class* const* cur; + + + /* GCC 4.6 warns the type difference: + * FT_Module_Class** != const FT_Module_Class* const* + */ + cur = (const FT_Module_Class* const*)ft_default_modules; + + /* test for valid `library' delayed to FT_Add_Module() */ + while ( *cur ) + { + error = FT_Add_Module( library, *cur ); + /* notify errors, but don't stop */ + if ( error ) + FT_TRACE0(( "FT_Add_Default_Module:" + " Cannot install `%s', error = 0x%x\n", + (*cur)->module_name, error )); + cur++; + } + } + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + +#define MAX_LENGTH 128 + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Properties( FT_Library library ) + { + const char* env; + const char* p; + const char* q; + + char module_name[MAX_LENGTH + 1]; + char property_name[MAX_LENGTH + 1]; + char property_value[MAX_LENGTH + 1]; + + int i; + + + env = ft_getenv( "FREETYPE_PROPERTIES" ); + if ( !env ) + return; + + for ( p = env; *p; p++ ) + { + /* skip leading whitespace and separators */ + if ( *p == ' ' || *p == '\t' ) + continue; + + /* read module name, followed by `:' */ + q = p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == ':' ) + break; + module_name[i] = *p++; + } + module_name[i] = '\0'; + + if ( !*p || *p != ':' || p == q ) + break; + + /* read property name, followed by `=' */ + q = ++p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == '=' ) + break; + property_name[i] = *p++; + } + property_name[i] = '\0'; + + if ( !*p || *p != '=' || p == q ) + break; + + /* read property value, followed by whitespace (if any) */ + q = ++p; + for ( i = 0; i < MAX_LENGTH; i++ ) + { + if ( !*p || *p == ' ' || *p == '\t' ) + break; + property_value[i] = *p++; + } + property_value[i] = '\0'; + + if ( !( *p == '\0' || *p == ' ' || *p == '\t' ) || p == q ) + break; + + /* we completely ignore errors */ + ft_property_string_set( library, + module_name, + property_name, + property_value ); + + if ( !*p ) + break; + } + } + +#else + + FT_EXPORT_DEF( void ) + FT_Set_Default_Properties( FT_Library library ) + { + FT_UNUSED( library ); + } + +#endif + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ) + { + FT_Error error; + FT_Memory memory; + + +#ifdef FT_DEBUG_LOGGING + ft_logging_init(); +#endif + + /* check of `alibrary' delayed to `FT_New_Library' */ + + /* First of all, allocate a new system object -- this function is part */ + /* of the system-specific component, i.e. `ftsystem.c'. */ + + memory = FT_New_Memory(); + if ( !memory ) + { + FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); + return FT_THROW( Unimplemented_Feature ); + } + + /* build a library out of it, then fill it with the set of */ + /* default drivers. */ + + error = FT_New_Library( memory, alibrary ); + if ( error ) + FT_Done_Memory( memory ); + else + FT_Add_Default_Modules( *alibrary ); + + FT_Set_Default_Properties( *alibrary ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_FreeType( FT_Library library ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + + /* Discard the library object */ + FT_Done_Library( library ); + + /* discard memory manager */ + FT_Done_Memory( memory ); + +#ifdef FT_DEBUG_LOGGING + ft_logging_deinit(); +#endif + + return FT_Err_Ok; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftlcdfil.c b/Dependencies/freetype/freetype/src/base/ftlcdfil.c new file mode 100644 index 00000000..1e69d4da --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftlcdfil.c @@ -0,0 +1,437 @@ +/**************************************************************************** + * + * ftlcdfil.c + * + * FreeType API for color filtering of subpixel bitmap glyphs (body). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + +/* define USE_LEGACY to implement the legacy filter */ +#define USE_LEGACY + +#define FT_SHIFTCLAMP( x ) ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) ) + + + /* add padding according to filter weights */ + FT_BASE_DEF( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ) + { + FT_Byte* lcd_weights; + FT_Bitmap_LcdFilterFunc lcd_filter_func; + + + /* Per-face LCD filtering takes priority if set up. */ + if ( slot->face && slot->face->internal->lcd_filter_func ) + { + lcd_weights = slot->face->internal->lcd_weights; + lcd_filter_func = slot->face->internal->lcd_filter_func; + } + else + { + lcd_weights = slot->library->lcd_weights; + lcd_filter_func = slot->library->lcd_filter_func; + } + + if ( lcd_filter_func == ft_lcd_filter_fir ) + { + if ( mode == FT_RENDER_MODE_LCD ) + { + cbox->xMin -= lcd_weights[0] ? 43 : + lcd_weights[1] ? 22 : 0; + cbox->xMax += lcd_weights[4] ? 43 : + lcd_weights[3] ? 22 : 0; + } + else if ( mode == FT_RENDER_MODE_LCD_V ) + { + cbox->yMin -= lcd_weights[0] ? 43 : + lcd_weights[1] ? 22 : 0; + cbox->yMax += lcd_weights[4] ? 43 : + lcd_weights[3] ? 22 : 0; + } + } + } + + + /* FIR filter used by the default and light filters */ + FT_BASE_DEF( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_LcdFiveTapFilter weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; + FT_Byte mode = bitmap->pixel_mode; + + + /* take care of bitmap flow */ + if ( pitch > 0 && height > 0 ) + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place FIR filter */ + if ( mode == FT_PIXEL_MODE_LCD && width >= 2 ) + { + FT_Byte* line = origin; + + + /* `fir' must be at least 32 bit wide, since the sum of */ + /* the values in `weights' can exceed 0xFF */ + + for ( ; height > 0; height--, line -= pitch ) + { + FT_UInt fir[5]; + FT_UInt val, xx; + + + val = line[0]; + fir[2] = weights[2] * val; + fir[3] = weights[3] * val; + fir[4] = weights[4] * val; + + val = line[1]; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + for ( xx = 2; xx < width; xx++ ) + { + val = line[xx]; + fir[0] = fir[1] + weights[0] * val; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + line[xx - 2] = FT_SHIFTCLAMP( fir[0] ); + } + + line[xx - 2] = FT_SHIFTCLAMP( fir[1] ); + line[xx - 1] = FT_SHIFTCLAMP( fir[2] ); + } + } + + /* vertical in-place FIR filter */ + else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 ) + { + FT_Byte* column = origin; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_UInt fir[5]; + FT_UInt val, yy; + + + val = col[0]; + fir[2] = weights[2] * val; + fir[3] = weights[3] * val; + fir[4] = weights[4] * val; + col -= pitch; + + val = col[0]; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + col -= pitch; + + for ( yy = 2; yy < height; yy++, col -= pitch ) + { + val = col[0]; + fir[0] = fir[1] + weights[0] * val; + fir[1] = fir[2] + weights[1] * val; + fir[2] = fir[3] + weights[2] * val; + fir[3] = fir[4] + weights[3] * val; + fir[4] = weights[4] * val; + + col[pitch * 2] = FT_SHIFTCLAMP( fir[0] ); + } + + col[pitch * 2] = FT_SHIFTCLAMP( fir[1] ); + col[pitch] = FT_SHIFTCLAMP( fir[2] ); + } + } + } + + +#ifdef USE_LEGACY + + /* intra-pixel filter used by the legacy filter */ + static void + _ft_lcd_filter_legacy( FT_Bitmap* bitmap, + FT_Byte* weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; + FT_Byte mode = bitmap->pixel_mode; + + static const unsigned int filters[3][3] = + { + { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 }, + { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 }, + { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 } + }; + + FT_UNUSED( weights ); + + + /* take care of bitmap flow */ + if ( pitch > 0 && height > 0 ) + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place intra-pixel filter */ + if ( mode == FT_PIXEL_MODE_LCD && width >= 3 ) + { + FT_Byte* line = origin; + + + for ( ; height > 0; height--, line -= pitch ) + { + FT_UInt xx; + + + for ( xx = 0; xx < width; xx += 3 ) + { + FT_UInt r, g, b; + FT_UInt p; + + + p = line[xx]; + r = filters[0][0] * p; + g = filters[0][1] * p; + b = filters[0][2] * p; + + p = line[xx + 1]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = line[xx + 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + line[xx] = (FT_Byte)( r / 65536 ); + line[xx + 1] = (FT_Byte)( g / 65536 ); + line[xx + 2] = (FT_Byte)( b / 65536 ); + } + } + } + else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 ) + { + FT_Byte* column = origin; + + + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column - 2 * pitch; + + + for ( ; height > 0; height -= 3, col -= 3 * pitch ) + { + FT_UInt r, g, b; + FT_UInt p; + + + p = col[0]; + r = filters[0][0] * p; + g = filters[0][1] * p; + b = filters[0][2] * p; + + p = col[pitch]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + + p = col[pitch * 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + + col[0] = (FT_Byte)( r / 65536 ); + col[pitch] = (FT_Byte)( g / 65536 ); + col[pitch * 2] = (FT_Byte)( b / 65536 ); + } + } + } + } + +#endif /* USE_LEGACY */ + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !weights ) + return FT_THROW( Invalid_Argument ); + + ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + + return FT_Err_Ok; + } + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + static const FT_LcdFiveTapFilter default_weights = + { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; + static const FT_LcdFiveTapFilter light_weights = + { 0x00, 0x55, 0x56, 0x55, 0x00 }; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + switch ( filter ) + { + case FT_LCD_FILTER_NONE: + library->lcd_filter_func = NULL; + break; + + case FT_LCD_FILTER_DEFAULT: + ft_memcpy( library->lcd_weights, + default_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + break; + + case FT_LCD_FILTER_LIGHT: + ft_memcpy( library->lcd_weights, + light_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; + break; + +#ifdef USE_LEGACY + + case FT_LCD_FILTER_LEGACY: + case FT_LCD_FILTER_LEGACY1: + library->lcd_filter_func = _ft_lcd_filter_legacy; + break; + +#endif + + default: + return FT_THROW( Invalid_Argument ); + } + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ) + { + FT_UNUSED( library ); + FT_UNUSED( sub ); + + return FT_THROW( Unimplemented_Feature ); + } + +#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* add padding to accommodate outline shifts */ + FT_BASE_DEF( void ) + ft_lcd_padding( FT_BBox* cbox, + FT_GlyphSlot slot, + FT_Render_Mode mode ) + { + FT_Vector* sub = slot->library->lcd_geometry; + + if ( mode == FT_RENDER_MODE_LCD ) + { + cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x ); + cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x ); + cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y ); + cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y ); + } + else if ( mode == FT_RENDER_MODE_LCD_V ) + { + cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y ); + cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y ); + cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x ); + cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x ); + } + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ) + { + FT_UNUSED( library ); + FT_UNUSED( weights ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + FT_UNUSED( library ); + FT_UNUSED( filter ); + + return FT_THROW( Unimplemented_Feature ); + } + + + /* documentation in ftlcdfil.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdGeometry( FT_Library library, + FT_Vector sub[3] ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !sub ) + return FT_THROW( Invalid_Argument ); + + ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) ); + + return FT_Err_Ok; + } + +#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftmac.c b/Dependencies/freetype/freetype/src/base/ftmac.c new file mode 100644 index 00000000..e8e35627 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftmac.c @@ -0,0 +1,1099 @@ +/**************************************************************************** + * + * ftmac.c + * + * Mac FOND support. Written by just@letterror.com. + * Heavily modified by mpsuzuki, George Williams, and Sean McBride. + * + * This file is for Mac OS X only; see builds/mac/ftoldmac.c for + * classic platforms built by MPW. + * + * Copyright (C) 1996-2024 by + * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + + Warning: fbit and NFNT bitmap resources are not supported yet. In old + sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' + resources instead of the `bdat' table in the sfnt resource. Therefore, + face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' + resource is unavailable at present. + + The Mac FOND support works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. This + is done by checking the file type: it has to be 'FFIL' or 'tfil'. The + stream that gets passed to our init_face() routine is a stdio stream, + which isn't usable for us, since the FOND resources live in the + resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is a + TrueType font and/or(!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate `LWFN' file), read + its data into memory, massage it slightly so it becomes PFB data, wrap + it into a memory stream, load the Type 1 driver and delegate the rest + of the work to it by calling FT_Open_Face(). (XXX TODO: after this + has been done, the kerning data from the FOND resource should be + appended to the face: On the Mac there are usually no AFM files + available. However, this is tricky since we need to map Mac char + codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an `sfnt' resource), read it into memory, + wrap it into a memory stream, load the TrueType driver and delegate + the rest of the work to it, by calling FT_Open_Face(). + + - Some suitcase fonts (notably Onyx) might point the `LWFN' file to + itself, even though it doesn't contains `POST' resources. To handle + this special case without opening the file an extra time, we just + ignore errors from the `LWFN' and fallback to the `sfnt' if both are + available. + */ + + +#include +#include +#include +#include +#include "ftbase.h" + + +#ifdef FT_MACINTOSH + + /* This is for Mac OS X. Without redefinition, OS_INLINE */ + /* expands to `static inline' which doesn't survive the */ + /* -ansi compilation flag of GCC. */ +#if !HAVE_ANSI_OS_INLINE +#undef OS_INLINE +#define OS_INLINE static __inline__ +#endif + + /* `configure' checks the availability of `ResourceIndex' strictly */ + /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always. If it is */ + /* not set (e.g., a build without `configure'), the availability */ + /* is guessed from the SDK version. */ +#ifndef HAVE_TYPE_RESOURCE_INDEX +#if !defined( MAC_OS_X_VERSION_10_5 ) || \ + ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) +#define HAVE_TYPE_RESOURCE_INDEX 0 +#else +#define HAVE_TYPE_RESOURCE_INDEX 1 +#endif +#endif /* !HAVE_TYPE_RESOURCE_INDEX */ + +#if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) + typedef short ResourceIndex; +#endif + +#include +#include +#include /* PATH_MAX */ + + /* Don't want warnings about our own use of deprecated functions. */ +#define FT_DEPRECATED_ATTRIBUTE + +#include + +#ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ +#define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault +#endif + + + /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available (this is not common, + but it *is* possible). */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif + + + /* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); + } + + + /* Private function. */ + /* The FSSpec type has been discouraged for a long time, */ + /* unfortunately an FSRef replacement API for */ + /* ATSFontGetFileSpecification() is only available in */ + /* Mac OS X 10.5 and later. */ + static OSStatus + FT_ATSFontGetFileReference( ATSFontRef ats_font_id, + FSRef* ats_font_ref ) + { +#if defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + + OSStatus err; + + err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); + + return err; +#elif __LP64__ /* No 64bit Carbon API on legacy platforms */ + FT_UNUSED( ats_font_id ); + FT_UNUSED( ats_font_ref ); + + + return fnfErr; +#else /* 32bit Carbon API on legacy platforms */ + OSStatus err; + FSSpec spec; + + + err = ATSFontGetFileSpecification( ats_font_id, &spec ); + if ( noErr == err ) + err = FSpMakeFSRef( &spec, ats_font_ref ); + + return err; +#endif + } + + + static FT_Error + FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, + FSRef* ats_font_ref, + FT_Long* face_index ) + { + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + + + *face_index = 0; + + cf_fontName = CFStringCreateWithCString( NULL, fontName, + kCFStringEncodingMacRoman ); + ats_font_id = ATSFontFindFromName( cf_fontName, + kATSOptionFlagsUnRestrictedScope ); + CFRelease( cf_fontName ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + return FT_THROW( Unknown_File_Format ); + + if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) + return FT_THROW( Unknown_File_Format ); + + /* face_index calculation by searching preceding fontIDs */ + /* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + + + while ( id2 > 0 ) + { + if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) + break; + + id2 --; + } + *face_index = ats_font_id - ( id2 + 1 ); + } + + return FT_Err_Ok; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + + + if ( !fontName || !face_index ) + return FT_THROW( Invalid_Argument); + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; + } + + + /* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + + return FT_THROW( Unimplemented_Feature ); +#else + FSRef ref; + FT_Error err; + + + if ( !fontName || !face_index ) + return FT_THROW( Invalid_Argument ); + + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( err ) + return err; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, + pathSpec, NULL ) ) + return FT_THROW( Unknown_File_Format ); + + return FT_Err_Ok; +#endif + } + + + static OSErr + FT_FSPathMakeRes( const UInt8* pathname, + ResFileRefNum* res ) + { + OSErr err; + FSRef ref; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + /* at present, no support for dfont format */ + err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); + if ( noErr == err ) + return err; + + /* fallback to original resource-fork font */ + *res = FSOpenResFile( &ref, fsRdPerm ); + err = ResError(); + + return err; + } + + + /* Return the file type for given pathname */ + static OSType + get_file_type_from_path( const UInt8* pathname ) + { + FSRef ref; + FSCatalogInfo info; + + + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return ( OSType ) 0; + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, + NULL, NULL, NULL ) ) + return ( OSType ) 0; + + return ( (FInfo *)( info.finderInfo ) )->fdType; + } + + + /* Given a PostScript font name, create the Macintosh LWFN file name. */ + static void + create_lwfn_name( char* ps_name, + Str255 lwfn_file_name ) + { + int max = 5, count = 0; + FT_Byte* p = lwfn_file_name; + FT_Byte* q = (FT_Byte*)ps_name; + + + lwfn_file_name[0] = 0; + + while ( *q ) + { + if ( ft_isupper( *q ) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + + + static short + count_faces_sfnt( char* fond_data ) + { + /* The count is 1 greater than the value in the FOND. */ + /* Isn't that cute? :-) */ + + return EndianS16_BtoN( *( (short*)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + } + + + static short + count_faces_scalable( char* fond_data ) + { + AsscEntry* assoc; + short i, face, face_all; + + + face_all = EndianS16_BtoN( *( (short *)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + face = 0; + + for ( i = 0; i < face_all; i++ ) + { + if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) + face++; + } + return face; + } + + + /* Look inside the FOND data, answer whether there should be an SFNT + resource, and answer the name of a possible LWFN Type 1 file. + + Thanks to Paul Miller (paulm@profoundeffects.com) for the fix + to load a face OTHER than the first one in the FOND! + */ + + + static void + parse_fond( char* fond_data, + short* have_sfnt, + ResID* sfnt_id, + Str255 lwfn_file_name, + short face_index ) + { + AsscEntry* assoc; + AsscEntry* base_assoc; + FamRec* fond; + + + *sfnt_id = 0; + *have_sfnt = 0; + lwfn_file_name[0] = 0; + + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + base_assoc = assoc; + + /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ + if ( 47 < face_index ) + return; + + /* Let's do a little range checking before we get too excited here */ + if ( face_index < count_faces_sfnt( fond_data ) ) + { + assoc += face_index; /* add on the face_index! */ + + /* if the face at this index is not scalable, + fall back to the first one (old behavior) */ + if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( assoc->fontID ); + } + else if ( base_assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); + } + } + + if ( EndianS32_BtoN( fond->ffStylOff ) ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + char ps_name[256]; + unsigned char* names[64]; + int i; + + + p += EndianS32_BtoN( fond->ffStylOff ); + style = (StyleTable*)p; + p += sizeof ( StyleTable ); + string_count = EndianS16_BtoN( *(short*)(p) ); + string_count = FT_MIN( 64, string_count ); + p += sizeof ( short ); + + for ( i = 0; i < string_count; i++ ) + { + names[i] = p; + p += names[i][0]; + p++; + } + + { + size_t ps_name_len = (size_t)names[0][0]; + + + if ( ps_name_len != 0 ) + { + ft_memcpy( ps_name, names[0] + 1, ps_name_len ); + ps_name[ps_name_len] = 0; + } + if ( style->indexes[face_index] > 1 && + style->indexes[face_index] <= string_count ) + { + unsigned char* suffixes = names[style->indexes[face_index] - 1]; + + + for ( i = 1; i <= suffixes[0]; i++ ) + { + unsigned char* s; + size_t j = suffixes[i] - 1; + + + if ( j < string_count && ( s = names[j] ) != NULL ) + { + size_t s_len = (size_t)s[0]; + + + if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) + { + ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); + ps_name_len += s_len; + ps_name[ps_name_len] = 0; + } + } + } + } + } + + create_lwfn_name( ps_name, lwfn_file_name ); + } + } + + + static FT_Error + lookup_lwfn_by_fond( const UInt8* path_fond, + ConstStr255Param base_lwfn, + UInt8* path_lwfn, + size_t path_size ) + { + FSRef ref, par_ref; + size_t dirname_len; + + + /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ + /* We should not extract parent directory by string manipulation. */ + + if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, &par_ref ) ) + return FT_THROW( Invalid_Argument ); + + if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) + return FT_THROW( Invalid_Argument ); + + if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) + return FT_THROW( Invalid_Argument ); + + /* now we have absolute dirname in path_lwfn */ + ft_strcat( (char *)path_lwfn, "/" ); + dirname_len = ft_strlen( (char *)path_lwfn ); + ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[dirname_len + base_lwfn[0]] = '\0'; + + if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) + return FT_THROW( Cannot_Open_Resource ); + + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, NULL ) ) + return FT_THROW( Cannot_Open_Resource ); + + return FT_Err_Ok; + } + + + static short + count_faces( Handle fond, + const UInt8* pathname ) + { + ResID sfnt_id; + short have_sfnt, have_lwfn; + Str255 lwfn_file_name; + UInt8 buff[PATH_MAX]; + FT_Error err; + short num_faces; + + + have_sfnt = have_lwfn = 0; + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); + + if ( lwfn_file_name[0] ) + { + err = lookup_lwfn_by_fond( pathname, lwfn_file_name, + buff, sizeof ( buff ) ); + if ( !err ) + have_lwfn = 1; + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + num_faces = 1; + else + num_faces = count_faces_scalable( *fond ); + + return num_faces; + } + + + /* Read Type 1 data from the POST resources inside the LWFN file, + return a PFB buffer. This is somewhat convoluted because the FT2 + PFB parser wants the ASCII header as one chunk, and the LWFN + chunks are often not organized that way, so we glue chunks + of the same type together. */ + static FT_Error + read_lwfn( FT_Memory memory, + ResFileRefNum res, + FT_Byte** pfb_data, + FT_ULong* size ) + { + FT_Error error = FT_Err_Ok; + ResID res_id; + unsigned char *buffer, *p, *size_p = NULL; + FT_ULong total_size = 0; + FT_ULong old_total_size = 0; + FT_ULong post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + + + UseResFile( res ); + + /* First pass: load all POST resources, and determine the size of */ + /* the output buffer. */ + res_id = 501; + last_code = -1; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( !post_data ) + break; /* we are done */ + + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( code == 5 ) + total_size += 2; /* just the end code */ + else + total_size += 6; /* code + 4 bytes chunk length */ + } + + total_size += (FT_ULong)GetHandleSize( post_data ) - 2; + last_code = code; + + /* detect resource fork overflow */ + if ( FT_MAC_RFORK_MAX_LEN < total_size ) + { + error = FT_THROW( Array_Too_Large ); + goto Error; + } + + old_total_size = total_size; + } + + if ( FT_QALLOC( buffer, (FT_Long)total_size ) ) + goto Error; + + /* Second pass: append all POST data to the buffer, add PFB fields. */ + /* Glue all consecutive chunks of the same type together. */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( !post_data ) + break; /* we are done */ + + post_size = (FT_ULong)GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + + if ( code != last_code ) + { + if ( last_code != -1 ) + { + /* we are done adding a chunk, fill in the size field */ + if ( size_p ) + { + *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); + } + pfb_chunk_size = 0; + } + + *p++ = 0x80; + if ( code == 5 ) + *p++ = 0x03; /* the end */ + else if ( code == 2 ) + *p++ = 0x02; /* binary segment */ + else + *p++ = 0x01; /* ASCII segment */ + + if ( code != 5 ) + { + size_p = p; /* save for later */ + p += 4; /* make space for size field */ + } + } + + ft_memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + + *pfb_data = buffer; + *size = total_size; + + Error: + CloseResFile( res ); + return error; + } + + + /* Create a new FT_Face from a file path to an LWFN file. */ + static FT_Error + FT_New_Face_From_LWFN( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Byte* pfb_data; + FT_ULong pfb_size; + FT_Error error; + ResFileRefNum res; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) + return FT_THROW( Cannot_Open_Resource ); + + pfb_data = NULL; + pfb_size = 0; + error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); + CloseResFile( res ); /* PFB is already loaded, useless anymore */ + if ( error ) + return error; + + return open_face_from_buffer( library, + pfb_data, + pfb_size, + face_index, + "type1", + aface ); + } + + + /* Create a new FT_Face from an SFNT resource, specified by res ID. */ + static FT_Error + FT_New_Face_From_SFNT( FT_Library library, + ResID sfnt_id, + FT_Long face_index, + FT_Face* aface ) + { + Handle sfnt = NULL; + FT_Byte* sfnt_data; + size_t sfnt_size; + FT_Error error = FT_Err_Ok; + FT_Memory memory = library->memory; + int is_cff, is_sfnt_ps; + + + sfnt = GetResource( TTAG_sfnt, sfnt_id ); + if ( !sfnt ) + return FT_THROW( Invalid_Handle ); + + sfnt_size = (FT_ULong)GetHandleSize( sfnt ); + + /* detect resource fork overflow */ + if ( FT_MAC_RFORK_MAX_LEN < sfnt_size ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + { + ReleaseResource( sfnt ); + return error; + } + + ft_memcpy( sfnt_data, *sfnt, sfnt_size ); + ReleaseResource( sfnt ); + + is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); + + if ( is_sfnt_ps ) + { + FT_Stream stream; + + + if ( FT_NEW( stream ) ) + goto Try_OpenType; + + FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); + if ( !open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ) ) + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + FT_FREE( sfnt_data ); + goto Exit; + } + + FT_FREE( stream ); + } + Try_OpenType: + error = open_face_from_buffer( library, + sfnt_data, + sfnt_size, + face_index, + is_cff ? "cff" : "truetype", + aface ); + Exit: + return error; + } + + + /* Create a new FT_Face from a file path to a suitcase file. */ + static FT_Error + FT_New_Face_From_Suitcase( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error = FT_ERR( Cannot_Open_Resource ); + ResFileRefNum res_ref; + ResourceIndex res_index; + Handle fond; + short num_faces_in_res; + FT_Long count; + + + if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) + return FT_THROW( Cannot_Open_Resource ); + + UseResFile( res_ref ); + if ( ResError() ) + return FT_THROW( Cannot_Open_Resource ); + + res_index = 1; + num_faces_in_res = 0; + count = face_index; + while ( count >= 0 ) + { + short num_faces_in_fond; + + + fond = Get1IndResource( TTAG_FOND, res_index ); + if ( ResError() ) + break; + + num_faces_in_fond = count_faces( fond, pathname ); + num_faces_in_res += num_faces_in_fond; + + if ( count < num_faces_in_fond ) + error = FT_New_Face_From_FOND( library, fond, count, aface ); + + res_index++; + count -= num_faces_in_fond; + } + + CloseResFile( res_ref ); + + if ( !error && aface && *aface ) + { + (*aface)->num_faces = num_faces_in_res; + (*aface)->face_index = face_index; + } + + return error; + } + + + /* documentation is in ftmac.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face* aface ) + { + short have_sfnt, have_lwfn = 0; + ResID sfnt_id, fond_id; + OSType fond_type; + Str255 fond_name; + Str255 lwfn_file_name; + UInt8 path_lwfn[PATH_MAX]; + OSErr err; + FT_Error error = FT_Err_Ok; + + + /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */ + + GetResInfo( fond, &fond_id, &fond_type, fond_name ); + if ( ResError() != noErr || fond_type != TTAG_FOND ) + return FT_THROW( Invalid_File_Format ); + + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); + + if ( lwfn_file_name[0] ) + { + ResFileRefNum res; + + + res = HomeResFile( fond ); + if ( noErr != ResError() ) + goto found_no_lwfn_file; + + { + UInt8 path_fond[PATH_MAX]; + FSRef ref; + + + err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, + NULL, NULL, NULL, &ref, NULL ); + if ( noErr != err ) + goto found_no_lwfn_file; + + err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( !error ) + have_lwfn = 1; + } + } + + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + error = FT_New_Face_From_LWFN( library, + path_lwfn, + face_index, + aface ); + else + error = FT_THROW( Unknown_File_Format ); + + found_no_lwfn_file: + if ( have_sfnt && error ) + error = FT_New_Face_From_SFNT( library, + sfnt_id, + face_index, + aface ); + + return error; + } + + + /* Common function to load a new FT_Face from a resource file. */ + static FT_Error + FT_New_Face_From_Resource( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + OSType file_type; + FT_Error error; + + + /* LWFN is a (very) specific file format, check for it explicitly */ + file_type = get_file_type_from_path( pathname ); + if ( file_type == TTAG_LWFN ) + return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); + + /* Otherwise the file type doesn't matter (there are more than */ + /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ + /* if it works, fine. */ + + error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); + if ( error ) + { + /* let it fall through to normal loader (.ttf, .otf, etc.); */ + /* we signal this by returning no error and no FT_Face */ + *aface = NULL; + } + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face + * + * @Description: + * This is the Mac-specific implementation of FT_New_Face. In + * addition to the standard FT_New_Face() functionality, it also + * accepts pathnames to Mac suitcase files. For further + * documentation see the original FT_New_Face() in freetype.h. + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; + + + /* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_THROW( Invalid_Argument ); + + *aface = NULL; + + /* try resourcefork based font: LWFN, FFIL */ + error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, + face_index, aface ); + if ( error || *aface ) + return error; + + /* let it fall through to normal loader (.ttf, .otf, etc.) */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face_From_FSRef + * + * @Description: + * FT_New_Face_From_FSRef is identical to FT_New_Face except it + * accepts an FSRef instead of a path. + * + * This function is deprecated because Carbon data types (FSRef) + * are not cross-platform, and thus not suitable for the FreeType API. + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef* ref, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error; + FT_Open_Args args; + + OSErr err; + UInt8 pathname[PATH_MAX]; + + + /* check of `library' and `aface' delayed to */ + /* `FT_New_Face_From_Resource' */ + + if ( !ref ) + return FT_THROW( Invalid_Argument ); + + err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_THROW( Cannot_Open_Resource ); + + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error || *aface ) + return error; + + /* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } + + + /************************************************************************** + * + * @Function: + * FT_New_Face_From_FSSpec + * + * @Description: + * FT_New_Face_From_FSSpec is identical to FT_New_Face except it + * accepts an FSSpec instead of a path. + * + * This function is deprecated because FSSpec is deprecated in Mac OS X + */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec* spec, + FT_Long face_index, + FT_Face* aface ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( library ); + FT_UNUSED( spec ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + + return FT_THROW( Unimplemented_Feature ); +#else + FSRef ref; + + + /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */ + + if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) + return FT_THROW( Invalid_Argument ); + else + return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); +#endif + } + +#else /* !FT_MACINTOSH */ + + /* ANSI C doesn't like empty source files */ + typedef int ft_mac_dummy_; + +#endif /* !FT_MACINTOSH */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftmm.c b/Dependencies/freetype/freetype/src/base/ftmm.c new file mode 100644 index 00000000..cc4ca22f --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftmm.c @@ -0,0 +1,704 @@ +/**************************************************************************** + * + * ftmm.c + * + * Multiple Master font support (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT mm + + + static FT_Error + ft_face_get_mm_service( FT_Face face, + FT_Service_MultiMasters *aservice ) + { + FT_Error error; + + + *aservice = NULL; + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + error = FT_ERR( Invalid_Argument ); + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + MULTI_MASTERS ); + + if ( *aservice ) + error = FT_Err_Ok; + } + + return error; + } + + + static FT_Error + ft_face_get_mvar_service( FT_Face face, + FT_Service_MetricsVariations *aservice ) + { + FT_Error error; + + + *aservice = NULL; + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + error = FT_ERR( Invalid_Argument ); + + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + METRICS_VARIATIONS ); + + if ( *aservice ) + error = FT_Err_Ok; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !amaster ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm ) + error = service->get_mm( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !amaster ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_var ) + error = service->get_mm_var( face, amaster ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_MM_Var( FT_Library library, + FT_MM_Var* amaster ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + FT_FREE( amaster ); + + return FT_Err_Ok; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->set_mm_design ) + error = service->set_mm_design( face, num_coords, coords ); + + if ( !error ) + { + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->set_mm_weightvector ) + error = service->set_mm_weightvector( face, len, weightvector ); + + if ( !error ) + { + if ( len ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_weightvector ) + error = service->get_mm_weightvector( face, len, weightvector ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_var_design ) + error = service_mm->set_var_design( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_var_design ) + error = service->get_var_design( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_mm_blend ) + error = service_mm->set_mm_blend( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + /* This is exactly the same as the previous function. It exists for */ + /* orthogonality. */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( num_coords && !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_mm_blend ) + error = service_mm->set_mm_blend( face, num_coords, coords ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_blend ) + error = service->get_mm_blend( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + /* This is exactly the same as the previous function. It exists for */ + /* orthogonality. */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( !coords ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_blend ) + error = service->get_mm_blend( face, num_coords, coords ); + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Var_Axis_Flags( FT_MM_Var* master, + FT_UInt axis_index, + FT_UInt* flags ) + { + FT_UShort* axis_flags; + + + if ( !master || !flags ) + return FT_THROW( Invalid_Argument ); + + if ( axis_index >= master->num_axis ) + return FT_THROW( Invalid_Argument ); + + /* the axis flags array immediately follows the data of `master' */ + axis_flags = (FT_UShort*)&( master[1] ); + *flags = axis_flags[axis_index]; + + return FT_Err_Ok; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ) + { + FT_Error error; + + FT_Service_MultiMasters service_mm = NULL; + FT_Service_MetricsVariations service_mvar = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service_mm->set_named_instance ) + error = service_mm->set_named_instance( face, instance_index ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + face->face_index = ( instance_index << 16 ) | + ( face->face_index & 0xFFFFL ); + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; + } + + if ( !error ) + { + (void)ft_face_get_mvar_service( face, &service_mvar ); + + if ( service_mvar && service_mvar->metrics_adjust ) + service_mvar->metrics_adjust( face ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + FT_Error error; + + FT_Service_MultiMasters service_mm = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + error = ft_face_get_mm_service( face, &service_mm ); + if ( !error ) + { + /* no error if `get_default_named_instance` is not available */ + if ( service_mm->get_default_named_instance ) + error = service_mm->get_default_named_instance( face, + instance_index ); + else + error = FT_Err_Ok; + } + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftobjs.c b/Dependencies/freetype/freetype/src/base/ftobjs.c new file mode 100644 index 00000000..9b97820c --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftobjs.c @@ -0,0 +1,5917 @@ +/**************************************************************************** + * + * ftobjs.c + * + * The FreeType private base classes (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* for SFNT_Load_Table_Func */ +#include /* for PS_Driver */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#include "ftbase.h" +#endif + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#include + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `conversion from XXX to YYY, */ + /* possible loss of data' in order to compile cleanly with */ + /* the maximum level of warnings: `md5.c' is non-FreeType */ + /* code, and it gets used during development builds only. */ +#pragma warning( push ) +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ + + /* It's easiest to include `md5.c' directly. However, since OpenSSL */ + /* also provides the same functions, there might be conflicts if */ + /* both FreeType and OpenSSL are built as static libraries. For */ + /* this reason, we put the MD5 stuff into the `FT_' namespace. */ +#define MD5_u32plus FT_MD5_u32plus +#define MD5_CTX FT_MD5_CTX +#define MD5_Init FT_MD5_Init +#define MD5_Update FT_MD5_Update +#define MD5_Final FT_MD5_Final + +#undef HAVE_OPENSSL + +#include "md5.c" + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + + /* This array must stay in sync with the @FT_Pixel_Mode enumeration */ + /* (in file `ftimage.h`). */ + + static const char* const pixel_modes[] = + { + "none", + "monochrome bitmap", + "gray 8-bit bitmap", + "gray 2-bit bitmap", + "gray 4-bit bitmap", + "LCD 8-bit bitmap", + "vertical LCD 8-bit bitmap", + "BGRA 32-bit color image bitmap", + "SDF 8-bit bitmap" + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + +#define GRID_FIT_METRICS + + + /* forward declaration */ + static FT_Error + ft_open_face_internal( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface, + FT_Bool test_mac_fonts ); + + + FT_BASE_DEF( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ) + { + FT_Pointer result = NULL; + FT_ServiceDesc desc = service_descriptors; + + + if ( desc && service_id ) + { + for ( ; desc->serv_id != NULL; desc++ ) + { + if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) + { + result = (FT_Pointer)desc->serv_data; + break; + } + } + } + + return result; + } + + + FT_BASE_DEF( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ) + { + valid->base = base; + valid->limit = limit; + valid->level = level; + valid->error = FT_Err_Ok; + } + + + FT_BASE_DEF( FT_Int ) + ft_validator_run( FT_Validator valid ) + { + /* This function doesn't work! None should call it. */ + FT_UNUSED( valid ); + + return -1; + } + + + FT_BASE_DEF( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ) + { + /* since the cast below also disables the compiler's */ + /* type check, we introduce a dummy variable, which */ + /* will be optimized away */ + volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; + + + valid->error = error; + + /* throw away volatileness; use `jump_buffer' or the */ + /* compiler may warn about an unused local variable */ + ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S T R E A M ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* create a new input stream from an FT_Open_Args structure */ + /* */ + FT_BASE_DEF( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + FT_UInt mode; + + + *astream = NULL; + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !args ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + mode = args->flags & + ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME ); + + if ( mode == FT_OPEN_MEMORY ) + { + /* create a memory-based stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, + (const FT_Byte*)args->memory_base, + (FT_ULong)args->memory_size ); + stream->memory = memory; + } + +#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT + + else if ( mode == FT_OPEN_PATHNAME ) + { + /* create a normal system stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + stream->memory = memory; + error = FT_Stream_Open( stream, args->pathname ); + if ( error ) + FT_FREE( stream ); + } + else if ( ( mode == FT_OPEN_STREAM ) && args->stream ) + { + /* use an existing, user-provided stream */ + + /* in this case, we do not need to allocate a new stream object */ + /* since the caller is responsible for closing it himself */ + stream = args->stream; + stream->memory = memory; + error = FT_Err_Ok; + } + +#endif + + else + { + error = FT_THROW( Invalid_Argument ); + if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + FT_Stream_Close( args->stream ); + } + + if ( !error ) + *astream = stream; + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ) + { + if ( stream ) + { + FT_Memory memory = stream->memory; + + + FT_Stream_Close( stream ); + + if ( !external ) + FT_FREE( stream ); + } + } + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT objs + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ft_glyphslot_init( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + FT_Error error = FT_Err_Ok; + FT_Slot_Internal internal = NULL; + + + slot->library = driver->root.library; + + if ( FT_NEW( internal ) ) + goto Exit; + + slot->internal = internal; + + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + error = FT_GlyphLoader_New( memory, &internal->loader ); + + if ( !error && clazz->init_slot ) + error = clazz->init_slot( slot ); + +#ifdef FT_CONFIG_OPTION_SVG + /* if SVG table exists, allocate the space in `slot->other` */ + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + goto Exit; + slot->other = document; + } +#endif + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) + { + if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + + + FT_FREE( slot->bitmap.buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* assume that the bitmap buffer was stolen or not */ + /* allocated from the heap */ + slot->bitmap.buffer = NULL; + } + } + + + /* overflow-resistant presetting of bitmap position and dimensions; */ + /* also check whether the size is too large for rendering */ + FT_BASE_DEF( FT_Bool ) + ft_glyphslot_preset_bitmap( FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + + FT_Pixel_Mode pixel_mode; + + FT_BBox cbox, pbox; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + FT_Pos x_left, y_top; + FT_Pos width, height, pitch; + + + if ( slot->format == FT_GLYPH_FORMAT_SVG ) + { + FT_Module module; + SVG_Service svg_service; + + + module = FT_Get_Module( slot->library, "ot-svg" ); + svg_service = (SVG_Service)module->clazz->module_interface; + + return (FT_Bool)svg_service->preset_slot( module, slot, FALSE ); + } + else if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return 1; + + if ( origin ) + { + x_shift = origin->x; + y_shift = origin->y; + } + + /* compute the control box, and grid-fit it, */ + /* taking into account the origin shift */ + FT_Outline_Get_CBox( outline, &cbox ); + + /* rough estimate of pixel box */ + pbox.xMin = ( cbox.xMin >> 6 ) + ( x_shift >> 6 ); + pbox.yMin = ( cbox.yMin >> 6 ) + ( y_shift >> 6 ); + pbox.xMax = ( cbox.xMax >> 6 ) + ( x_shift >> 6 ); + pbox.yMax = ( cbox.yMax >> 6 ) + ( y_shift >> 6 ); + + /* tiny remainder box */ + cbox.xMin = ( cbox.xMin & 63 ) + ( x_shift & 63 ); + cbox.yMin = ( cbox.yMin & 63 ) + ( y_shift & 63 ); + cbox.xMax = ( cbox.xMax & 63 ) + ( x_shift & 63 ); + cbox.yMax = ( cbox.yMax & 63 ) + ( y_shift & 63 ); + + switch ( mode ) + { + case FT_RENDER_MODE_MONO: + pixel_mode = FT_PIXEL_MODE_MONO; +#if 1 + /* x */ + + /* undocumented but confirmed: bbox values get rounded; */ + /* we do asymmetric rounding so that the center of a pixel */ + /* gets always included */ + + pbox.xMin += ( cbox.xMin + 31 ) >> 6; + pbox.xMax += ( cbox.xMax + 32 ) >> 6; + + /* if the bbox collapsed, we add a pixel based on the total */ + /* rounding remainder to cover most of the original cbox */ + + if ( pbox.xMin == pbox.xMax ) + { + if ( ( ( cbox.xMin + 31 ) & 63 ) - 31 + + ( ( cbox.xMax + 32 ) & 63 ) - 32 < 0 ) + pbox.xMin -= 1; + else + pbox.xMax += 1; + } + + /* y */ + + pbox.yMin += ( cbox.yMin + 31 ) >> 6; + pbox.yMax += ( cbox.yMax + 32 ) >> 6; + + if ( pbox.yMin == pbox.yMax ) + { + if ( ( ( cbox.yMin + 31 ) & 63 ) - 31 + + ( ( cbox.yMax + 32 ) & 63 ) - 32 < 0 ) + pbox.yMin -= 1; + else + pbox.yMax += 1; + } + + break; +#else + goto Adjust; +#endif + + case FT_RENDER_MODE_LCD: + pixel_mode = FT_PIXEL_MODE_LCD; + ft_lcd_padding( &cbox, slot, mode ); + goto Adjust; + + case FT_RENDER_MODE_LCD_V: + pixel_mode = FT_PIXEL_MODE_LCD_V; + ft_lcd_padding( &cbox, slot, mode ); + goto Adjust; + + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_LIGHT: + default: + pixel_mode = FT_PIXEL_MODE_GRAY; + Adjust: + pbox.xMin += cbox.xMin >> 6; + pbox.yMin += cbox.yMin >> 6; + pbox.xMax += ( cbox.xMax + 63 ) >> 6; + pbox.yMax += ( cbox.yMax + 63 ) >> 6; + } + + x_left = pbox.xMin; + y_top = pbox.yMax; + + width = pbox.xMax - pbox.xMin; + height = pbox.yMax - pbox.yMin; + + switch ( pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + pitch = ( ( width + 15 ) >> 4 ) << 1; + break; + + case FT_PIXEL_MODE_LCD: + width *= 3; + pitch = FT_PAD_CEIL( width, 4 ); + break; + + case FT_PIXEL_MODE_LCD_V: + height *= 3; + FALL_THROUGH; + + case FT_PIXEL_MODE_GRAY: + default: + pitch = width; + } + + slot->bitmap_left = (FT_Int)x_left; + slot->bitmap_top = (FT_Int)y_top; + + bitmap->pixel_mode = (unsigned char)pixel_mode; + bitmap->num_grays = 256; + bitmap->width = (unsigned int)width; + bitmap->rows = (unsigned int)height; + bitmap->pitch = pitch; + + if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF || + pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF ) + { + FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n", + pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax )); + return 1; + } + + return 0; + } + + + FT_BASE_DEF( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ) + { + ft_glyphslot_free_bitmap( slot ); + + slot->bitmap.buffer = buffer; + + FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); + } + + + FT_BASE_DEF( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Error error; + + + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + FT_MEM_ALLOC( slot->bitmap.buffer, size ); + return error; + } + + + static void + ft_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + slot->glyph_index = 0; + + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + + slot->bitmap.width = 0; + slot->bitmap.rows = 0; + slot->bitmap.pitch = 0; + slot->bitmap.pixel_mode = 0; + /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = NULL; + slot->control_data = NULL; + slot->control_len = 0; + +#ifndef FT_CONFIG_OPTION_SVG + slot->other = NULL; +#else + if ( !( slot->face->face_flags & FT_FACE_FLAG_SVG ) ) + slot->other = NULL; + else + { + if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_Memory memory = slot->face->memory; + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + } +#endif + + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + slot->advance.x = 0; + slot->advance.y = 0; + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + + + static void + ft_glyphslot_done( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + +#ifdef FT_CONFIG_OPTION_SVG + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + /* Free memory in case SVG was there. */ + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal && slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + + FT_FREE( slot->other ); + } +#endif + + if ( clazz->done_slot ) + clazz->done_slot( slot ); + + /* free bitmap buffer if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* slot->internal might be NULL in out-of-memory situations */ + if ( slot->internal ) + { + /* free glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + FT_GlyphLoader_Done( slot->internal->loader ); + slot->internal->loader = NULL; + } + + FT_FREE( slot->internal ); + } + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ) + { + FT_Error error; + FT_Driver driver; + FT_Driver_Class clazz; + FT_Memory memory; + FT_GlyphSlot slot = NULL; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !face->driver ) + return FT_THROW( Invalid_Argument ); + + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + + FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); + if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) + { + slot->face = face; + + error = ft_glyphslot_init( slot ); + if ( error ) + { + ft_glyphslot_done( slot ); + FT_FREE( slot ); + goto Exit; + } + + slot->next = face->glyph; + face->glyph = slot; + + if ( aslot ) + *aslot = slot; + } + else if ( aslot ) + *aslot = NULL; + + + Exit: + FT_TRACE4(( "FT_New_GlyphSlot: Return 0x%x\n", error )); + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ) + { + if ( slot ) + { + FT_Driver driver = slot->face->driver; + FT_Memory memory = driver->root.memory; + FT_GlyphSlot prev; + FT_GlyphSlot cur; + + + /* Remove slot from its parent face's list */ + prev = NULL; + cur = slot->face->glyph; + + while ( cur ) + { + if ( cur == slot ) + { + if ( !prev ) + slot->face->glyph = cur->next; + else + prev->next = cur->next; + + /* finalize client-specific data */ + if ( slot->generic.finalizer ) + slot->generic.finalizer( slot ); + + ft_glyphslot_done( slot ); + FT_FREE( slot ); + break; + } + prev = cur; + cur = cur->next; + } + } + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + internal->transform_flags = 0; + + if ( !matrix ) + { + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + + matrix = &internal->transform_matrix; + } + else + internal->transform_matrix = *matrix; + + /* set transform_flags bit flag 0 if `matrix' isn't the identity */ + if ( ( matrix->xy | matrix->yx ) || + matrix->xx != 0x10000L || + matrix->yy != 0x10000L ) + internal->transform_flags |= 1; + + if ( !delta ) + { + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + + delta = &internal->transform_delta; + } + else + internal->transform_delta = *delta; + + /* set transform_flags bit flag 1 if `delta' isn't the null vector */ + if ( delta->x | delta->y ) + internal->transform_flags |= 2; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + if ( matrix ) + *matrix = internal->transform_matrix; + + if ( delta ) + *delta = internal->transform_delta; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ); + + +#ifdef GRID_FIT_METRICS + static void + ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, + FT_Bool vertical ) + { + FT_Glyph_Metrics* metrics = &slot->metrics; + FT_Pos right, bottom; + + + if ( vertical ) + { + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY ); + + right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingX, + metrics->width ) ); + bottom = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingY, + metrics->height ) ); + + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + metrics->width = SUB_LONG( right, + metrics->vertBearingX ); + metrics->height = SUB_LONG( bottom, + metrics->vertBearingY ); + } + else + { + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + + right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->horiBearingX, + metrics->width ) ); + bottom = FT_PIX_FLOOR( SUB_LONG( metrics->horiBearingY, + metrics->height ) ); + + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY ); + + metrics->width = SUB_LONG( right, + metrics->horiBearingX ); + metrics->height = SUB_LONG( metrics->horiBearingY, + bottom ); + } + + metrics->horiAdvance = FT_PIX_ROUND_LONG( metrics->horiAdvance ); + metrics->vertAdvance = FT_PIX_ROUND_LONG( metrics->vertAdvance ); + } +#endif /* GRID_FIT_METRICS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + FT_Driver driver; + FT_GlyphSlot slot; + FT_Library library; + FT_Bool autohint = FALSE; + FT_Module hinter; + TT_Face ttface = (TT_Face)face; + + + if ( !face || !face->size || !face->glyph ) + return FT_THROW( Invalid_Face_Handle ); + + /* The validity test for `glyph_index' is performed by the */ + /* font drivers. */ + + slot = face->glyph; + ft_glyphslot_clear( slot ); + + driver = face->driver; + library = driver->root.library; + hinter = library->auto_hinter; + + /* undefined scale means no scale */ + if ( face->size->metrics.x_ppem == 0 || + face->size->metrics.y_ppem == 0 ) + load_flags |= FT_LOAD_NO_SCALE; + + /* resolve load flags dependencies */ + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM; + + if ( load_flags & FT_LOAD_NO_SCALE ) + { + load_flags |= FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + + load_flags &= ~FT_LOAD_RENDER; + } + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + load_flags &= ~FT_LOAD_RENDER; + + /* + * Determine whether we need to auto-hint or not. + * The general rules are: + * + * - Do only auto-hinting if we have + * + * - a hinter module, + * - a scalable font, + * - not a tricky font, and + * - no transforms except simple slants and/or rotations by + * integer multiples of 90 degrees. + * + * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't + * have a native font hinter. + * + * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't + * any hinting bytecode in the TrueType/OpenType font. + * + * - Exception: The font is `tricky' and requires the native hinter to + * load properly. + */ + + if ( hinter && + !( load_flags & FT_LOAD_NO_HINTING ) && + !( load_flags & FT_LOAD_NO_AUTOHINT ) && + FT_IS_SCALABLE( face ) && + !FT_IS_TRICKY( face ) && + ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || + ( face->internal->transform_matrix.yx == 0 && + face->internal->transform_matrix.xx != 0 ) || + ( face->internal->transform_matrix.xx == 0 && + face->internal->transform_matrix.yx != 0 ) ) ) + { + if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) || + !FT_DRIVER_HAS_HINTER( driver ) ) + autohint = TRUE; + else + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + FT_Bool is_light_type1; + + + /* only the new Adobe engine (for both CFF and Type 1) is `light'; */ + /* we use `strstr' to catch both `Type 1' and `CID Type 1' */ + is_light_type1 = + ft_strstr( FT_Get_Font_Format( face ), "Type 1" ) != NULL && + ((PS_Driver)driver)->hinting_engine == FT_HINTING_ADOBE; + + /* the check for `num_locations' assures that we actually */ + /* test for instructions in a TTF and not in a CFF-based OTF */ + /* */ + /* since `maxSizeOfInstructions' might be unreliable, we */ + /* check the size of the `fpgm' and `prep' tables, too -- */ + /* the assumption is that there don't exist real TTFs where */ + /* both `fpgm' and `prep' tables are missing */ + if ( ( mode == FT_RENDER_MODE_LIGHT && + ( !FT_DRIVER_HINTS_LIGHTLY( driver ) && + !is_light_type1 ) ) || + ( FT_IS_SFNT( face ) && + ttface->num_locations && + ttface->max_profile.maxSizeOfInstructions == 0 && + ttface->font_program_size == 0 && + ttface->cvt_program_size == 0 ) ) + autohint = TRUE; + } + } + + if ( autohint ) + { + FT_AutoHinter_Interface hinting; + + + /* XXX: The use of the `FT_LOAD_XXX_ONLY` flags is not very */ + /* elegant. */ + + /* try to load SVG documents if available */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + FT_HAS_SVG( face ) ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SVG_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_SVG ) + goto Load_Ok; + } + + /* try to load embedded bitmaps if available */ + if ( FT_HAS_FIXED_SIZES( face ) && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SBITS_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) + goto Load_Ok; + } + + { + FT_Face_Internal internal = face->internal; + FT_Int transform_flags = internal->transform_flags; + + + /* since the auto-hinter calls FT_Load_Glyph by itself, */ + /* make sure that glyphs aren't transformed */ + internal->transform_flags = 0; + + /* load auto-hinted outline */ + hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface; + + error = hinting->load_glyph( (FT_AutoHinter)hinter, + slot, face->size, + glyph_index, load_flags ); + + internal->transform_flags = transform_flags; + } + } + else + { + error = driver->clazz->load_glyph( slot, + face->size, + glyph_index, + load_flags ); + if ( error ) + goto Exit; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* check that the loaded outline is correct */ + error = FT_Outline_Check( &slot->outline ); + if ( error ) + goto Exit; + +#ifdef GRID_FIT_METRICS + if ( !( load_flags & FT_LOAD_NO_HINTING ) ) + ft_glyphslot_grid_fit_metrics( + slot, + FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); +#endif + } + } + + Load_Ok: + /* compute the advance */ + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + slot->advance.x = 0; + slot->advance.y = slot->metrics.vertAdvance; + } + else + { + slot->advance.x = slot->metrics.horiAdvance; + slot->advance.y = 0; + } + + /* compute the linear advance in 16.16 pixels */ + if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && + FT_IS_SCALABLE( face ) ) + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + /* it's tricky! */ + slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, + metrics->x_scale, 64 ); + + slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, + metrics->y_scale, 64 ); + } + + if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) + { + FT_Face_Internal internal = face->internal; + + + /* now, transform the glyph image if needed */ + if ( internal->transform_flags ) + { + /* get renderer */ + FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); + + + if ( renderer ) + error = renderer->clazz->transform_glyph( + renderer, slot, + &internal->transform_matrix, + &internal->transform_delta ); + else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* apply `standard' transformation if no renderer is available */ + if ( internal->transform_flags & 1 ) + FT_Outline_Transform( &slot->outline, + &internal->transform_matrix ); + + if ( internal->transform_flags & 2 ) + FT_Outline_Translate( &slot->outline, + internal->transform_delta.x, + internal->transform_delta.y ); + } + + /* transform advance */ + FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); + } + } + + slot->glyph_index = glyph_index; + slot->internal->load_flags = load_flags; + + /* do we need to render the image or preset the bitmap now? */ + if ( !error && + ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + slot->format != FT_GLYPH_FORMAT_BITMAP && + slot->format != FT_GLYPH_FORMAT_COMPOSITE ) + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + + + if ( mode == FT_RENDER_MODE_NORMAL && + load_flags & FT_LOAD_MONOCHROME ) + mode = FT_RENDER_MODE_MONO; + + if ( load_flags & FT_LOAD_RENDER ) + error = FT_Render_Glyph( slot, mode ); + else + ft_glyphslot_preset_bitmap( slot, mode, NULL ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n", + glyph_index, load_flags )); + FT_TRACE5(( " bitmap %dx%d %s, %s (mode %d)\n", + slot->bitmap.width, + slot->bitmap.rows, + slot->outline.points ? + slot->bitmap.buffer ? "rendered" + : "preset" + : + slot->internal->flags & FT_GLYPH_OWN_BITMAP ? "owned" + : "unowned", + pixel_modes[slot->bitmap.pixel_mode], + slot->bitmap.pixel_mode )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " x advance: %f\n", (double)slot->advance.x / 64 )); + FT_TRACE5(( " y advance: %f\n", (double)slot->advance.y / 64 )); + FT_TRACE5(( " linear x advance: %f\n", + (double)slot->linearHoriAdvance / 65536 )); + FT_TRACE5(( " linear y advance: %f\n", + (double)slot->linearVertAdvance / 65536 )); + + { + FT_Glyph_Metrics* metrics = &slot->metrics; + + + FT_TRACE5(( " metrics:\n" )); + FT_TRACE5(( " width: %f\n", (double)metrics->width / 64 )); + FT_TRACE5(( " height: %f\n", (double)metrics->height / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " horiBearingX: %f\n", + (double)metrics->horiBearingX / 64 )); + FT_TRACE5(( " horiBearingY: %f\n", + (double)metrics->horiBearingY / 64 )); + FT_TRACE5(( " horiAdvance: %f\n", + (double)metrics->horiAdvance / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " vertBearingX: %f\n", + (double)metrics->vertBearingX / 64 )); + FT_TRACE5(( " vertBearingY: %f\n", + (double)metrics->vertBearingY / 64 )); + FT_TRACE5(( " vertAdvance: %f\n", + (double)metrics->vertAdvance / 64 )); + } +#endif + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ) + { + FT_UInt glyph_index; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + glyph_index = (FT_UInt)char_code; + if ( face->charmap ) + glyph_index = FT_Get_Char_Index( face, char_code ); + + return FT_Load_Glyph( face, glyph_index, load_flags ); + } + + + /* destructor for sizes list */ + static void + destroy_size( FT_Memory memory, + void* size_, + void* driver_ ) + { + FT_Size size = (FT_Size)size_; + FT_Driver driver = (FT_Driver)driver_; + + + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + + /* finalize format-specific stuff */ + if ( driver->clazz->done_size ) + driver->clazz->done_size( size ); + + FT_FREE( size->internal ); + FT_FREE( size ); + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ); + + + static void + destroy_charmaps( FT_Face face, + FT_Memory memory ) + { + FT_Int n; + + + if ( !face ) + return; + + for ( n = 0; n < face->num_charmaps; n++ ) + { + FT_CMap cmap = FT_CMAP( face->charmaps[n] ); + + + ft_cmap_done_internal( cmap ); + + face->charmaps[n] = NULL; + } + + FT_FREE( face->charmaps ); + face->num_charmaps = 0; + } + + + /* destructor for faces list */ + static void + destroy_face( FT_Memory memory, + void* face_, + void* driver_ ) + { + FT_Face face = (FT_Face)face_; + FT_Driver driver = (FT_Driver)driver_; + FT_Driver_Class clazz = driver->clazz; + + + /* discard auto-hinting data */ + if ( face->autohint.finalizer ) + face->autohint.finalizer( face->autohint.data ); + + /* Discard glyph slots for this face. */ + /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ + while ( face->glyph ) + FT_Done_GlyphSlot( face->glyph ); + + /* discard all sizes for this face */ + FT_List_Finalize( &face->sizes_list, + destroy_size, + memory, + driver ); + face->size = NULL; + + /* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + + /* discard charmaps */ + destroy_charmaps( face, memory ); + + /* finalize format-specific stuff */ + if ( clazz->done_face ) + clazz->done_face( face ); + + /* close the stream for this face if needed */ + FT_Stream_Free( + face->stream, + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->stream = NULL; + + /* get rid of it */ + if ( face->internal ) + { + FT_FREE( face->internal ); + } + FT_FREE( face ); + } + + + static void + Destroy_Driver( FT_Driver driver ) + { + FT_List_Finalize( &driver->faces_list, + destroy_face, + driver->root.memory, + driver ); + } + + + /************************************************************************** + * + * @Function: + * find_unicode_charmap + * + * @Description: + * This function finds a Unicode charmap, if there is one. + * And if there is more than one, it tries to favour the more + * extensive one, i.e., one that supports UCS-4 against those which + * are limited to the BMP (said UCS-2 encoding.) + * + * This function is called from open_face() (just below), and also + * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). + */ + static FT_Error + find_unicode_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* cur; + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return FT_THROW( Invalid_CharMap_Handle ); + + /* + * The original TrueType specification(s) only specified charmap + * formats that are capable of mapping 8 or 16 bit character codes to + * glyph indices. + * + * However, recent updates to the Apple and OpenType specifications + * introduced new formats that are capable of mapping 32-bit character + * codes as well. And these are already used on some fonts, mainly to + * map non-BMP Asian ideographs as defined in Unicode. + * + * For compatibility purposes, these fonts generally come with + * *several* Unicode charmaps: + * + * - One of them in the "old" 16-bit format, that cannot access + * all glyphs in the font. + * + * - Another one in the "new" 32-bit format, that can access all + * the glyphs. + * + * This function has been written to always favor a 32-bit charmap + * when found. Otherwise, a 16-bit one is returned when found. + */ + + /* Since the `interesting' table, with IDs (3,10), is normally the */ + /* last one, we loop backwards. This loses with type1 fonts with */ + /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ + /* chars (.01% ?), and this is the same about 99.99% of the time! */ + + cur = first + face->num_charmaps; /* points after the last one */ + + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { + /* XXX If some new encodings to represent UCS-4 are added, */ + /* they should be added here. */ + if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && + cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || + ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + } + + /* We do not have any UCS-4 charmap. */ + /* Do the loop again and search for UCS-2 charmaps. */ + cur = first + face->num_charmaps; + + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_CharMap_Handle ); + } + + + /************************************************************************** + * + * @Function: + * find_variant_selector_charmap + * + * @Description: + * This function finds the variant selector charmap, if there is one. + * There can only be one (platform=0, specific=5, format=14). + */ + static FT_CharMap + find_variant_selector_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* end; + FT_CharMap* cur; + + + /* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + + first = face->charmaps; + + if ( !first ) + return NULL; + + end = first + face->num_charmaps; /* points after the last one */ + + for ( cur = first; cur < end; cur++ ) + { + if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && + FT_Get_CMap_Format( cur[0] ) == 14 ) + return cur[0]; + } + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * open_face + * + * @Description: + * This function does some work for FT_Open_Face(). + */ + static FT_Error + open_face( FT_Driver driver, + FT_Stream *astream, + FT_Bool *anexternal_stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter* params, + FT_Face *aface ) + { + FT_Memory memory; + FT_Driver_Class clazz; + FT_Face face = NULL; + FT_Face_Internal internal = NULL; + + FT_Error error, error2; + + + clazz = driver->clazz; + memory = driver->root.memory; + + /* allocate the face object and perform basic initialization */ + if ( FT_ALLOC( face, clazz->face_object_size ) ) + goto Fail; + + face->driver = driver; + face->memory = memory; + face->stream = *astream; + + /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ + if ( *anexternal_stream ) + face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; + + if ( FT_NEW( internal ) ) + goto Fail; + + face->internal = internal; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + int i; + + + face->internal->incremental_interface = NULL; + for ( i = 0; i < num_params && !face->internal->incremental_interface; + i++ ) + if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) + face->internal->incremental_interface = + (FT_Incremental_Interface)params[i].data; + } +#endif + + face->internal->random_seed = -1; + + if ( clazz->init_face ) + error = clazz->init_face( *astream, + face, + (FT_Int)face_index, + num_params, + params ); + /* Stream may have been changed. */ + *astream = face->stream; + *anexternal_stream = + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0; + if ( error ) + goto Fail; + + /* select Unicode charmap by default */ + error2 = find_unicode_charmap( face ); + + /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ + /* is returned. */ + + /* no error should happen, but we want to play safe */ + if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) ) + { + error = error2; + goto Fail; + } + + *aface = face; + + Fail: + if ( error ) + { + destroy_charmaps( face, memory ); + if ( clazz->done_face ) + clazz->done_face( face ); + FT_FREE( internal ); + FT_FREE( face ); + *aface = NULL; + } + + return error; + } + + + /* there's a Mac-specific extended implementation of FT_New_Face() */ + /* in src/base/ftmac.c */ + +#ifndef FT_MACINTOSH + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `aface' delayed to `FT_Open_Face' */ + if ( !pathname ) + return FT_THROW( Invalid_Argument ); + + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + args.stream = NULL; + + return ft_open_face_internal( library, &args, face_index, aface, 1 ); + } + +#endif + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; + + + /* test for valid `library' and `face' delayed to `FT_Open_Face' */ + if ( !file_base ) + return FT_THROW( Invalid_Argument ); + + args.flags = FT_OPEN_MEMORY; + args.memory_base = file_base; + args.memory_size = file_size; + args.stream = NULL; + + return ft_open_face_internal( library, &args, face_index, aface, 1 ); + } + + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + + /* The behavior here is very similar to that in base/ftmac.c, but it */ + /* is designed to work on non-mac systems, so no mac specific calls. */ + /* */ + /* We look at the file and determine if it is a mac dfont file or a mac */ + /* resource file, or a macbinary file containing a mac resource file. */ + /* */ + /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ + /* the point, especially since there may be multiple `FOND' resources. */ + /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ + /* they occur in the file. */ + /* */ + /* Note that multiple `POST' resources do not mean multiple postscript */ + /* fonts; they all get jammed together to make what is essentially a */ + /* pfb file. */ + /* */ + /* We aren't interested in `NFNT' or `FONT' bitmap resources. */ + /* */ + /* As soon as we get an `sfnt' load it into memory and pass it off to */ + /* FT_Open_Face. */ + /* */ + /* If we have a (set of) `POST' resources, massage them into a (memory) */ + /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ + /* going to try to save the kerning info. After all that lives in the */ + /* `FOND' which isn't in the file containing the `POST' resources so */ + /* we don't really have access to it. */ + + + /* Finalizer for a memory stream; gets called by FT_Done_Face(). */ + /* It frees the memory it uses. */ + /* From `ftmac.c'. */ + static void + memory_stream_close( FT_Stream stream ) + { + FT_Memory memory = (FT_Memory)stream->descriptor.pointer; + + + FT_FREE( stream->base ); + stream->size = 0; + stream->close = NULL; + FT_FREE( stream ); + } + + + /* Create a new memory stream from a buffer and a size. */ + /* From `ftmac.c'. */ + static FT_Error + new_memory_stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream_CloseFunc close, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !base ) + return FT_THROW( Invalid_Argument ); + + *astream = NULL; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + + FT_Stream_OpenMemory( stream, base, size ); + + stream->descriptor.pointer = memory; + stream->close = close; + + *astream = stream; + + Exit: + return error; + } + + + /* Create a new FT_Face given a buffer and a driver name. */ + /* From `ftmac.c'. */ + FT_LOCAL_DEF( FT_Error ) + open_face_from_buffer( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Long face_index, + const char* driver_name, + FT_Face *aface ) + { + FT_Open_Args args; + FT_Error error; + FT_Memory memory = library->memory; + + + args.driver = NULL; + args.flags = 0; + + if ( driver_name ) + { + args.driver = FT_Get_Module( library, driver_name ); + if ( !args.driver ) + { + FT_FREE( base ); + return FT_THROW( Missing_Module ); + } + + args.flags = args.flags | FT_OPEN_DRIVER; + } + + /* `memory_stream_close` also frees the stream object. */ + error = new_memory_stream( library, + base, + size, + memory_stream_close, + &args.stream ); + if ( error ) + { + FT_FREE( base ); + return error; + } + + args.flags |= FT_OPEN_STREAM; + +#ifdef FT_MACINTOSH + /* At this point, the face index has served its purpose; */ + /* whoever calls this function has already used it to */ + /* locate the correct font data. We should not propagate */ + /* this index to FT_Open_Face() (unless it is negative). */ + + if ( face_index > 0 ) + face_index &= 0x7FFF0000L; /* retain GX data */ +#endif + + return ft_open_face_internal( library, &args, face_index, aface, 0 ); + } + + + /* Look up `TYP1' or `CID ' table from sfnt table directory. */ + /* `offset' and `length' must exclude the binary header in tables. */ + + /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */ + /* format too. Here, since we can't expect that the TrueType font */ + /* driver is loaded unconditionally, we must parse the font by */ + /* ourselves. We are only interested in the name of the table and */ + /* the offset. */ + + static FT_Error + ft_lookup_PS_in_sfnt_stream( FT_Stream stream, + FT_Long face_index, + FT_ULong* offset, + FT_ULong* length, + FT_Bool* is_sfnt_cid ) + { + FT_Error error; + FT_UShort numTables; + FT_Long pstable_index; + FT_ULong tag; + int i; + + + *offset = 0; + *length = 0; + *is_sfnt_cid = FALSE; + + /* TODO: support for sfnt-wrapped PS/CID in TTC format */ + + /* version check for 'typ1' (should be ignored?) */ + if ( FT_READ_ULONG( tag ) ) + return error; + if ( tag != TTAG_typ1 ) + return FT_THROW( Unknown_File_Format ); + + if ( FT_READ_USHORT( numTables ) ) + return error; + if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */ + return error; + + pstable_index = -1; + *is_sfnt_cid = FALSE; + + for ( i = 0; i < numTables; i++ ) + { + if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) || + FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) ) + return error; + + if ( tag == TTAG_CID ) + { + pstable_index++; + *offset += 22; + *length -= 22; + *is_sfnt_cid = TRUE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + else if ( tag == TTAG_TYP1 ) + { + pstable_index++; + *offset += 24; + *length -= 24; + *is_sfnt_cid = FALSE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + if ( face_index >= 0 && pstable_index == face_index ) + return FT_Err_Ok; + } + + return FT_THROW( Table_Missing ); + } + + + FT_LOCAL_DEF( FT_Error ) + open_face_PS_from_sfnt_stream( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter *params, + FT_Face *aface ) + { + FT_Error error; + FT_Memory memory = library->memory; + FT_ULong offset, length; + FT_ULong pos; + FT_Bool is_sfnt_cid; + FT_Byte* sfnt_ps = NULL; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + /* ignore GX stuff */ + if ( face_index > 0 ) + face_index &= 0xFFFFL; + + pos = FT_STREAM_POS(); + + error = ft_lookup_PS_in_sfnt_stream( stream, + face_index, + &offset, + &length, + &is_sfnt_cid ); + if ( error ) + goto Exit; + + if ( offset > stream->size ) + { + FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + else if ( length > stream->size - offset ) + { + FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + error = FT_Stream_Seek( stream, pos + offset ); + if ( error ) + goto Exit; + + if ( FT_QALLOC( sfnt_ps, (FT_Long)length ) ) + goto Exit; + + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); + if ( error ) + { + FT_FREE( sfnt_ps ); + goto Exit; + } + + error = open_face_from_buffer( library, + sfnt_ps, + length, + FT_MIN( face_index, 0 ), + is_sfnt_cid ? "t1cid" : "type1", + aface ); + Exit: + { + FT_Error error1; + + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + error1 = FT_Stream_Seek( stream, pos ); + if ( error1 ) + return error1; + } + + return error; + } + } + + +#ifndef FT_MACINTOSH + + /* The resource header says we've got resource_cnt `POST' (type1) */ + /* resources in this file. They all need to be coalesced into */ + /* one lump which gets passed on to the type1 driver. */ + /* Here can be only one PostScript font in a file so face_index */ + /* must be 0 (or -1). */ + /* */ + static FT_Error + Mac_Read_POST_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error = FT_ERR( Cannot_Open_Resource ); + FT_Memory memory = library->memory; + + FT_Byte* pfb_data = NULL; + int i, type, flags; + FT_ULong len; + FT_ULong pfb_len, pfb_pos, pfb_lenpos; + FT_ULong rlen, temp; + + + if ( face_index == -1 ) + face_index = 0; + if ( face_index != 0 ) + return error; + + /* Find the length of all the POST resources, concatenated. Assume */ + /* worst case (each resource in its own section). */ + pfb_len = 0; + for ( i = 0; i < resource_cnt; i++ ) + { + error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] ); + if ( error ) + goto Exit; + if ( FT_READ_ULONG( temp ) ) /* actually LONG */ + goto Exit; + + /* FT2 allocator takes signed long buffer length, + * too large value causing overflow should be checked + */ + FT_TRACE4(( " POST fragment #%d: length=0x%08lx" + " total pfb_len=0x%08lx\n", + i, temp, pfb_len + temp + 6 )); + + if ( FT_MAC_RFORK_MAX_LEN < temp || + FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 ) + { + FT_TRACE2(( " MacOS resource length cannot exceed" + " 0x%08lx\n", + FT_MAC_RFORK_MAX_LEN )); + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + + pfb_len += temp + 6; + } + + FT_TRACE2(( " total buffer size to concatenate" + " %ld POST fragments: 0x%08lx\n", + resource_cnt, pfb_len + 2 )); + + if ( pfb_len + 2 < 6 ) + { + FT_TRACE2(( " too long fragment length makes" + " pfb_len confused: pfb_len=0x%08lx\n", + pfb_len )); + + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + if ( FT_QALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + goto Exit; + + pfb_data[0] = 0x80; + pfb_data[1] = 1; /* Ascii section */ + pfb_data[2] = 0; /* 4-byte length, fill in later */ + pfb_data[3] = 0; + pfb_data[4] = 0; + pfb_data[5] = 0; + pfb_pos = 6; + pfb_lenpos = 2; + + len = 0; + type = 1; + + for ( i = 0; i < resource_cnt; i++ ) + { + error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] ); + if ( error ) + goto Exit2; + if ( FT_READ_ULONG( rlen ) ) + goto Exit2; + + /* FT2 allocator takes signed long buffer length, + * too large fragment length causing overflow should be checked + */ + if ( 0x7FFFFFFFUL < rlen ) + { + error = FT_THROW( Invalid_Offset ); + goto Exit2; + } + + if ( FT_READ_USHORT( flags ) ) + goto Exit2; + + FT_TRACE3(( "POST fragment[%d]:" + " offsets=0x%08lx, rlen=0x%08lx, flags=0x%04x\n", + i, offsets[i], rlen, flags )); + + error = FT_ERR( Array_Too_Large ); + + /* postpone the check of `rlen longer than buffer' */ + /* until `FT_Stream_Read' */ + + if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */ + { + FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n", + i )); + continue; + } + + /* the flags are part of the resource, so rlen >= 2, */ + /* but some fonts declare rlen = 0 for empty fragment */ + if ( rlen > 2 ) + rlen -= 2; + else + rlen = 0; + + if ( ( flags >> 8 ) == type ) + len += rlen; + else + { + FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer" + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_lenpos )); + + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + if ( ( flags >> 8 ) == 5 ) /* End of font mark */ + break; + + FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer" + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_pos )); + + if ( pfb_pos + 6 > pfb_len + 2 ) + goto Exit2; + + pfb_data[pfb_pos++] = 0x80; + + type = flags >> 8; + len = rlen; + + pfb_data[pfb_pos++] = (FT_Byte)type; + pfb_lenpos = pfb_pos; + pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + } + + if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) + goto Exit2; + + FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer" + " %p + 0x%08lx\n", + i, rlen, (void*)pfb_data, pfb_pos )); + + error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); + if ( error ) + goto Exit2; + + pfb_pos += rlen; + } + + error = FT_ERR( Array_Too_Large ); + + if ( pfb_pos + 2 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_pos++] = 0x80; + pfb_data[pfb_pos++] = 3; + + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + + return open_face_from_buffer( library, + pfb_data, + pfb_pos, + face_index, + "type1", + aface ); + + Exit2: + if ( FT_ERR_EQ( error, Array_Too_Large ) ) + FT_TRACE2(( " Abort due to too-short buffer to store" + " all POST fragments\n" )); + else if ( FT_ERR_EQ( error, Invalid_Offset ) ) + FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" )); + + if ( error ) + error = FT_ERR( Cannot_Open_Resource ); + FT_FREE( pfb_data ); + + Exit: + return error; + } + + + /* The resource header says we've got resource_cnt `sfnt' */ + /* (TrueType/OpenType) resources in this file. Look through */ + /* them for the one indicated by face_index, load it into mem, */ + /* pass it on to the truetype driver, and return it. */ + /* */ + static FT_Error + Mac_Read_sfnt_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Byte* sfnt_data = NULL; + FT_Error error; + FT_ULong flag_offset; + FT_ULong rlen; + int is_cff; + FT_Long face_index_in_resource = 0; + + + if ( face_index < 0 ) + face_index = -face_index - 1; + if ( face_index >= resource_cnt ) + return FT_THROW( Cannot_Open_Resource ); + + flag_offset = (FT_ULong)offsets[face_index]; + error = FT_Stream_Seek( stream, flag_offset ); + if ( error ) + goto Exit; + + if ( FT_READ_ULONG( rlen ) ) + goto Exit; + if ( !rlen ) + return FT_THROW( Cannot_Open_Resource ); + if ( rlen > FT_MAC_RFORK_MAX_LEN ) + return FT_THROW( Invalid_Offset ); + + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ); + if ( !error ) + goto Exit; + + /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */ + error = FT_Stream_Seek( stream, flag_offset + 4 ); + if ( error ) + goto Exit; + + if ( FT_QALLOC( sfnt_data, rlen ) ) + return error; + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); + if ( error ) + { + FT_FREE( sfnt_data ); + goto Exit; + } + + is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + error = open_face_from_buffer( library, + sfnt_data, + rlen, + face_index_in_resource, + is_cff ? "cff" : "truetype", + aface ); + + Exit: + return error; + } + + + /* Check for a valid resource fork header, or a valid dfont */ + /* header. In a resource fork the first 16 bytes are repeated */ + /* at the location specified by bytes 4-7. In a dfont bytes */ + /* 4-7 point to 16 bytes of zeroes instead. */ + /* */ + static FT_Error + IsMacResource( FT_Library library, + FT_Stream stream, + FT_Long resource_offset, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Long map_offset, rdata_pos; + FT_Long *data_offsets; + FT_Long count; + + + error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, + &map_offset, &rdata_pos ); + if ( error ) + return error; + + /* POST resources must be sorted to concatenate properly */ + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdata_pos, + TTAG_POST, TRUE, + &data_offsets, &count ); + if ( !error ) + { + error = Mac_Read_POST_Resource( library, stream, data_offsets, count, + face_index, aface ); + FT_FREE( data_offsets ); + /* POST exists in an LWFN providing a single face */ + if ( !error ) + (*aface)->num_faces = 1; + return error; + } + + /* sfnt resources should not be sorted to preserve the face order by + QuickDraw API */ + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdata_pos, + TTAG_sfnt, FALSE, + &data_offsets, &count ); + if ( !error ) + { + FT_Long face_index_internal = face_index % count; + + + error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, + face_index_internal, aface ); + FT_FREE( data_offsets ); + if ( !error ) + { + (*aface)->num_faces = count; + (*aface)->face_index = face_index_internal; + } + } + + return error; + } + + + /* Check for a valid macbinary header, and if we find one */ + /* check that the (flattened) resource fork in it is valid. */ + /* */ + static FT_Error + IsMacBinary( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface ) + { + unsigned char header[128]; + FT_Error error; + FT_Long dlen, offset; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Operation ); + + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + goto Exit; + + error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); + if ( error ) + goto Exit; + + if ( header[ 0] != 0 || + header[74] != 0 || + header[82] != 0 || + header[ 1] == 0 || + header[ 1] > 33 || + header[63] != 0 || + header[2 + header[1]] != 0 || + header[0x53] > 0x7F ) + return FT_THROW( Unknown_File_Format ); + + dlen = ( header[0x53] << 24 ) | + ( header[0x54] << 16 ) | + ( header[0x55] << 8 ) | + header[0x56]; +#if 0 + rlen = ( header[0x57] << 24 ) | + ( header[0x58] << 16 ) | + ( header[0x59] << 8 ) | + header[0x5A]; +#endif /* 0 */ + offset = 128 + ( ( dlen + 127 ) & ~127 ); + + return IsMacResource( library, stream, offset, face_index, aface ); + + Exit: + return error; + } + + + static FT_Error + load_face_in_embedded_rfork( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + + FT_Memory memory = library->memory; + FT_Error error = FT_ERR( Unknown_File_Format ); + FT_UInt i; + + char* file_names[FT_RACCESS_N_RULES]; + FT_Long offsets[FT_RACCESS_N_RULES]; + FT_Error errors[FT_RACCESS_N_RULES]; + FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */ + + FT_Open_Args args2; + FT_Stream stream2 = NULL; + + + FT_Raccess_Guess( library, stream, + args->pathname, file_names, offsets, errors ); + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); + if ( is_darwin_vfs && vfs_rfork_has_no_font ) + { + FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" + " is already checked and" + " no font is found\n", + i )); + continue; + } + + if ( errors[i] ) + { + FT_TRACE3(( "Error 0x%x has occurred in rule %d\n", + errors[i], i )); + continue; + } + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_names[i] ? file_names[i] : args->pathname; + + FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...", + i, args2.pathname, offsets[i] )); + + error = FT_Stream_New( library, &args2, &stream2 ); + if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) ) + vfs_rfork_has_no_font = TRUE; + + if ( error ) + { + FT_TRACE3(( "failed\n" )); + continue; + } + + error = IsMacResource( library, stream2, offsets[i], + face_index, aface ); + FT_Stream_Free( stream2, 0 ); + + FT_TRACE3(( "%s\n", error ? "failed": "successful" )); + + if ( !error ) + break; + else if ( is_darwin_vfs ) + vfs_rfork_has_no_font = TRUE; + } + + for (i = 0; i < FT_RACCESS_N_RULES; i++) + { + if ( file_names[i] ) + FT_FREE( file_names[i] ); + } + + /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ + if ( error ) + error = FT_ERR( Unknown_File_Format ); + + return error; + +#undef FT_COMPONENT +#define FT_COMPONENT objs + + } + + + /* Check for some macintosh formats without Carbon framework. */ + /* Is this a macbinary file? If so look at the resource fork. */ + /* Is this a mac dfont file? */ + /* Is this an old style resource fork? (in data) */ + /* Else call load_face_in_embedded_rfork to try extra rules */ + /* (defined in `ftrfork.c'). */ + /* */ + static FT_Error + load_mac_face( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + FT_Error error; + FT_UNUSED( args ); + + + error = IsMacBinary( library, stream, face_index, aface ); + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE3(( "Try as dfont: " )); + if ( !( args->flags & FT_OPEN_MEMORY ) ) + FT_TRACE3(( "%s ...", args->pathname )); +#endif + + error = IsMacResource( library, stream, 0, face_index, aface ); + + FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); + +#undef FT_COMPONENT +#define FT_COMPONENT objs + + } + + if ( ( FT_ERR_EQ( error, Unknown_File_Format ) || + FT_ERR_EQ( error, Invalid_Stream_Operation ) ) && + ( args->flags & FT_OPEN_PATHNAME ) ) + error = load_face_in_embedded_rfork( library, stream, + face_index, aface, args ); + return error; + } +#endif + +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ) + { + return ft_open_face_internal( library, args, face_index, aface, 1 ); + } + + + static FT_Error + ft_open_face_internal( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface, + FT_Bool test_mac_fonts ) + { + FT_Error error; + FT_Driver driver = NULL; + FT_Memory memory = NULL; + FT_Stream stream = NULL; + FT_Face face = NULL; + FT_ListNode node = NULL; + FT_Bool external_stream; + FT_Module* cur; + FT_Module* limit; + +#ifndef FT_CONFIG_OPTION_MAC_FONTS + FT_UNUSED( test_mac_fonts ); +#endif + + + /* only use lower 31 bits together with sign bit */ + if ( face_index > 0 ) + face_index &= 0x7FFFFFFFL; + else + { + face_index = -face_index; + face_index &= 0x7FFFFFFFL; + face_index = -face_index; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE3(( "FT_Open_Face: " )); + if ( face_index < 0 ) + FT_TRACE3(( "Requesting number of faces and named instances\n")); + else + { + FT_TRACE3(( "Requesting face %ld", face_index & 0xFFFFL )); + if ( face_index & 0x7FFF0000L ) + FT_TRACE3(( ", named instance %ld", face_index >> 16 )); + FT_TRACE3(( "\n" )); + } +#endif + + /* test for valid `library' delayed to `FT_Stream_New' */ + + if ( !args ) + return FT_THROW( Invalid_Argument ); + + external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && + args->stream ); + + /* create input stream */ + error = FT_Stream_New( library, args, &stream ); + if ( error ) + goto Fail3; + + /* Do this error check after `FT_Stream_New` to ensure that the */ + /* 'close' callback is called. */ + if ( !aface && face_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail3; + } + + memory = library->memory; + + /* If the font driver is specified in the `args' structure, use */ + /* it. Otherwise, we scan the list of registered drivers. */ + if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) + { + driver = FT_DRIVER( args->driver ); + + /* not all modules are drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( driver ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = NULL; + + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, &stream, &external_stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + } + else + error = FT_THROW( Invalid_Handle ); + + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + else + { + error = FT_ERR( Missing_Module ); + + /* check each font driver for an appropriate format */ + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + { + /* not all modules are font drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( cur[0] ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = NULL; + + + driver = FT_DRIVER( cur[0] ); + + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + + error = open_face( driver, &stream, &external_stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + +#ifdef FT_CONFIG_OPTION_MAC_FONTS + if ( test_mac_fonts && + ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && + FT_ERR_EQ( error, Table_Missing ) ) + { + /* TrueType but essential tables are missing */ + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + break; + + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + num_params, + params, + aface ); + if ( !error ) + { + FT_Stream_Free( stream, external_stream ); + return error; + } + } +#endif + + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Fail3; + } + } + + Fail3: + /* If we are on the mac, and we get an */ + /* FT_Err_Invalid_Stream_Operation it may be because we have an */ + /* empty data fork, so we need to check the resource fork. */ + if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) && + FT_ERR_NEQ( error, Unknown_File_Format ) && + FT_ERR_NEQ( error, Invalid_Stream_Operation ) ) + goto Fail2; + +#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) + if ( test_mac_fonts ) + { + error = load_mac_face( library, stream, face_index, aface, args ); + if ( !error ) + { + /* We don't want to go to Success here. We've already done */ + /* that. On the other hand, if we succeeded we still need to */ + /* close this stream (we opened a different stream which */ + /* extracted the interesting information out of this stream */ + /* here. That stream will still be open and the face will */ + /* point to it). */ + FT_Stream_Free( stream, external_stream ); + return error; + } + } + + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Fail2; +#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ + + /* no driver is able to handle this format */ + error = FT_THROW( Unknown_File_Format ); + + Fail2: + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + + Success: + FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); + + /* add the face object to its driver's list */ + if ( FT_QNEW( node ) ) + goto Fail; + + node->data = face; + /* don't assume driver is the same as face->driver, so use */ + /* face->driver instead. */ + FT_List_Add( &face->driver->faces_list, node ); + + /* now allocate a glyph slot object for the face */ + FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); + + if ( face_index >= 0 ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( error ) + goto Fail; + + /* finally, allocate a size object for the face */ + { + FT_Size size; + + + FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); + + error = FT_New_Size( face, &size ); + if ( error ) + goto Fail; + + face->size = size; + } + } + + /* some checks */ + + if ( FT_IS_SCALABLE( face ) ) + { + if ( face->height < 0 ) + face->height = (FT_Short)-face->height; + + if ( !FT_HAS_VERTICAL( face ) ) + face->max_advance_height = (FT_Short)face->height; + } + + if ( FT_HAS_FIXED_SIZES( face ) ) + { + FT_Int i; + + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( bsize->height < 0 ) + bsize->height = -bsize->height; + if ( bsize->x_ppem < 0 ) + bsize->x_ppem = -bsize->x_ppem; + if ( bsize->y_ppem < 0 ) + bsize->y_ppem = -bsize->y_ppem; + + /* check whether negation actually has worked */ + if ( bsize->height < 0 || bsize->x_ppem < 0 || bsize->y_ppem < 0 ) + { + FT_TRACE0(( "FT_Open_Face:" + " Invalid bitmap dimensions for strike %d," + " now disabled\n", i )); + bsize->width = 0; + bsize->height = 0; + bsize->size = 0; + bsize->x_ppem = 0; + bsize->y_ppem = 0; + } + } + } + + /* initialize internal face data */ + { + FT_Face_Internal internal = face->internal; + + + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + + internal->refcount = 1; + + internal->no_stem_darkening = -1; + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + /* Per-face filtering can only be set up by FT_Face_Properties */ + internal->lcd_filter_func = NULL; +#endif + } + + if ( aface ) + *aface = face; + else + FT_Done_Face( face ); + + goto Exit; + + Fail: + if ( node ) + FT_Done_Face( face ); /* face must be in the driver's list */ + else if ( face ) + destroy_face( memory, face, driver ); + + Exit: +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !error && face_index < 0 ) + { + FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n", + face->num_faces, + face->num_faces == 1 ? "" : "s" )); + FT_TRACE3(( " and %ld named instance%s for face %ld\n", + face->style_flags >> 16, + ( face->style_flags >> 16 ) == 1 ? "" : "s", + -face_index - 1 )); + } +#endif + + FT_TRACE4(( "FT_Open_Face: Return 0x%x\n", error )); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ) + { + FT_Open_Args open; + + + /* test for valid `face' delayed to `FT_Attach_Stream' */ + + if ( !filepathname ) + return FT_THROW( Invalid_Argument ); + + open.stream = NULL; + open.flags = FT_OPEN_PATHNAME; + open.pathname = (char*)filepathname; + + return FT_Attach_Stream( face, &open ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ) + { + FT_Stream stream; + FT_Error error; + FT_Driver driver; + + FT_Driver_Class clazz; + + + /* test for valid `parameters' delayed to `FT_Stream_New' */ + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + driver = face->driver; + if ( !driver ) + return FT_THROW( Invalid_Driver_Handle ); + + error = FT_Stream_New( driver->root.library, parameters, &stream ); + if ( error ) + goto Exit; + + /* we implement FT_Attach_Stream in each driver through the */ + /* `attach_file' interface */ + + error = FT_ERR( Unimplemented_Feature ); + clazz = driver->clazz; + if ( clazz->attach_file ) + error = clazz->attach_file( face, stream ); + + /* close the attached stream */ + FT_Stream_Free( stream, + FT_BOOL( parameters->stream && + ( parameters->flags & FT_OPEN_STREAM ) ) ); + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Face( FT_Face face ) + { + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + face->internal->refcount++; + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Face( FT_Face face ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_ListNode node; + + + error = FT_ERR( Invalid_Face_Handle ); + if ( face && face->driver ) + { + face->internal->refcount--; + if ( face->internal->refcount > 0 ) + error = FT_Err_Ok; + else + { + driver = face->driver; + memory = driver->root.memory; + + /* find face in driver's list */ + node = FT_List_Find( &driver->faces_list, face ); + if ( node ) + { + /* remove face object from the driver's list */ + FT_List_Remove( &driver->faces_list, node ); + FT_FREE( node ); + + /* now destroy the object proper */ + destroy_face( memory, face, driver ); + error = FT_Err_Ok; + } + } + } + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size *asize ) + { + FT_Error error; + FT_Memory memory; + FT_Driver driver; + FT_Driver_Class clazz; + + FT_Size size = NULL; + FT_ListNode node = NULL; + + FT_Size_Internal internal = NULL; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !asize ) + return FT_THROW( Invalid_Argument ); + + if ( !face->driver ) + return FT_THROW( Invalid_Driver_Handle ); + + *asize = NULL; + + driver = face->driver; + clazz = driver->clazz; + memory = face->memory; + + /* Allocate new size object and perform basic initialisation */ + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_QNEW( node ) ) + goto Exit; + + size->face = face; + + if ( FT_NEW( internal ) ) + goto Exit; + + size->internal = internal; + + if ( clazz->init_size ) + error = clazz->init_size( size ); + + /* in case of success, add to the face's list */ + if ( !error ) + { + *asize = size; + node->data = size; + FT_List_Add( &face->sizes_list, node ); + } + + Exit: + if ( error ) + { + FT_FREE( node ); + if ( size ) + FT_FREE( size->internal ); + FT_FREE( size ); + } + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Size( FT_Size size ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Face face; + FT_ListNode node; + + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + face = size->face; + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + driver = face->driver; + if ( !driver ) + return FT_THROW( Invalid_Driver_Handle ); + + memory = driver->root.memory; + + error = FT_Err_Ok; + node = FT_List_Find( &face->sizes_list, size ); + if ( node ) + { + FT_List_Remove( &face->sizes_list, node ); + FT_FREE( node ); + + if ( face->size == size ) + { + face->size = NULL; + if ( face->sizes_list.head ) + face->size = (FT_Size)(face->sizes_list.head->data); + } + + destroy_size( memory, size, driver ); + } + else + error = FT_THROW( Invalid_Size_Handle ); + + return error; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ) + { + FT_Int i; + FT_Long w, h; + + + if ( !FT_HAS_FIXED_SIZES( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + /* FT_Bitmap_Size doesn't provide enough info... */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + return FT_THROW( Unimplemented_Feature ); + + w = FT_REQUEST_WIDTH ( req ); + h = FT_REQUEST_HEIGHT( req ); + + if ( req->width && !req->height ) + h = w; + else if ( !req->width && req->height ) + w = h; + + w = FT_PIX_ROUND( w ); + h = FT_PIX_ROUND( h ); + + if ( !w || !h ) + return FT_THROW( Invalid_Pixel_Size ); + + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + + + if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) + continue; + + if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) + { + FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i )); + + if ( size_index ) + *size_index = (FT_ULong)i; + + return FT_Err_Ok; + } + } + + FT_TRACE3(( "FT_Match_Size: no matching bitmap strike\n" )); + + return FT_THROW( Invalid_Pixel_Size ); + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ) + { + FT_Pos height = metrics->height; + + + /* compensate for glyph with bbox above/below the baseline */ + if ( metrics->horiBearingY < 0 ) + { + if ( height < metrics->horiBearingY ) + height = metrics->horiBearingY; + } + else if ( metrics->horiBearingY > 0 ) + height -= metrics->horiBearingY; + + /* the factor 1.2 is a heuristical value */ + if ( !advance ) + advance = height * 12 / 10; + + metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; + metrics->vertBearingY = ( advance - height ) / 2; + metrics->vertAdvance = advance; + } + + + static void + ft_recompute_scaled_metrics( FT_Face face, + FT_Size_Metrics* metrics ) + { + /* Compute root ascender, descender, test height, and max_advance */ + +#ifdef GRID_FIT_METRICS + metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, + metrics->y_scale ) ); + + metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, + metrics->y_scale ) ); + + metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, + metrics->y_scale ) ); + + metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, + metrics->x_scale ) ); +#else /* !GRID_FIT_METRICS */ + metrics->ascender = FT_MulFix( face->ascender, + metrics->y_scale ); + + metrics->descender = FT_MulFix( face->descender, + metrics->y_scale ); + + metrics->height = FT_MulFix( face->height, + metrics->y_scale ); + + metrics->max_advance = FT_MulFix( face->max_advance_width, + metrics->x_scale ); +#endif /* !GRID_FIT_METRICS */ + } + + + FT_BASE_DEF( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ) + { + FT_Size_Metrics* metrics; + FT_Bitmap_Size* bsize; + + + metrics = &face->size->metrics; + bsize = face->available_sizes + strike_index; + + metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); + + if ( FT_IS_SCALABLE( face ) ) + { + metrics->x_scale = FT_DivFix( bsize->x_ppem, + face->units_per_EM ); + metrics->y_scale = FT_DivFix( bsize->y_ppem, + face->units_per_EM ); + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + metrics->ascender = bsize->y_ppem; + metrics->descender = 0; + metrics->height = bsize->height << 6; + metrics->max_advance = bsize->x_ppem; + } + } + + + FT_BASE_DEF( FT_Error ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ) + { + FT_Error error = FT_Err_Ok; + + FT_Size_Metrics* metrics; + + + metrics = &face->size->metrics; + + if ( FT_IS_SCALABLE( face ) ) + { + FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; + + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + w = h = face->units_per_EM; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + w = h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_BBOX: + w = face->bbox.xMax - face->bbox.xMin; + h = face->bbox.yMax - face->bbox.yMin; + break; + + case FT_SIZE_REQUEST_TYPE_CELL: + w = face->max_advance_width; + h = face->ascender - face->descender; + break; + + case FT_SIZE_REQUEST_TYPE_SCALES: + metrics->x_scale = (FT_Fixed)req->width; + metrics->y_scale = (FT_Fixed)req->height; + if ( !metrics->x_scale ) + metrics->x_scale = metrics->y_scale; + else if ( !metrics->y_scale ) + metrics->y_scale = metrics->x_scale; + goto Calculate_Ppem; + + case FT_SIZE_REQUEST_TYPE_MAX: + break; + } + + /* to be on the safe side */ + if ( w < 0 ) + w = -w; + + if ( h < 0 ) + h = -h; + + scaled_w = FT_REQUEST_WIDTH ( req ); + scaled_h = FT_REQUEST_HEIGHT( req ); + + /* determine scales */ + if ( req->height || !req->width ) + { + if ( h == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + + metrics->y_scale = FT_DivFix( scaled_h, h ); + } + + if ( req->width ) + { + if ( w == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + + metrics->x_scale = FT_DivFix( scaled_w, w ); + } + else + { + metrics->x_scale = metrics->y_scale; + scaled_w = FT_MulDiv( scaled_h, w, h ); + } + + if ( !req->height ) + { + metrics->y_scale = metrics->x_scale; + scaled_h = FT_MulDiv( scaled_w, h, w ); + } + + if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) + { + if ( metrics->y_scale > metrics->x_scale ) + metrics->y_scale = metrics->x_scale; + else + metrics->x_scale = metrics->y_scale; + } + + Calculate_Ppem: + /* calculate the ppems */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + { + scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); + scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); + } + + scaled_w = ( scaled_w + 32 ) >> 6; + scaled_h = ( scaled_h + 32 ) >> 6; + if ( scaled_w > (FT_Long)FT_USHORT_MAX || + scaled_h > (FT_Long)FT_USHORT_MAX ) + { + FT_ERROR(( "FT_Request_Metrics: Resulting ppem size too large\n" )); + error = FT_ERR( Invalid_Pixel_Size ); + goto Exit; + } + + metrics->x_ppem = (FT_UShort)scaled_w; + metrics->y_ppem = (FT_UShort)scaled_h; + + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + FT_ZERO( metrics ); + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + } + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ) + { + FT_Error error = FT_Err_Ok; + FT_Driver_Class clazz; + + + if ( !face || !FT_HAS_FIXED_SIZES( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) + return FT_THROW( Invalid_Argument ); + + clazz = face->driver->clazz; + + if ( clazz->select_size ) + { + error = clazz->select_size( face->size, (FT_ULong)strike_index ); + + FT_TRACE5(( "FT_Select_Size (%s driver):\n", + face->driver->root.clazz->module_name )); + } + else + { + FT_Select_Metrics( face, (FT_ULong)strike_index ); + + FT_TRACE5(( "FT_Select_Size:\n" )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } +#endif + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ) + { + FT_Error error; + FT_Driver_Class clazz; + FT_ULong strike_index; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( !req || req->width < 0 || req->height < 0 || + req->type >= FT_SIZE_REQUEST_TYPE_MAX ) + return FT_THROW( Invalid_Argument ); + + /* signal the auto-hinter to recompute its size metrics */ + /* (if requested) */ + face->size->internal->autohint_metrics.x_scale = 0; + + clazz = face->driver->clazz; + + if ( clazz->request_size ) + { + error = clazz->request_size( face->size, req ); + + FT_TRACE5(( "FT_Request_Size (%s driver):\n", + face->driver->root.clazz->module_name )); + } + else if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) + { + /* + * The reason that a driver doesn't have `request_size' defined is + * either that the scaling here suffices or that the supported formats + * are bitmap-only and size matching is not implemented. + * + * In the latter case, a simple size matching is done. + */ + error = FT_Match_Size( face, req, 0, &strike_index ); + if ( error ) + goto Exit; + + return FT_Select_Size( face, (FT_Int)strike_index ); + } + else + { + error = FT_Request_Metrics( face, req ); + if ( error ) + goto Exit; + + FT_TRACE5(( "FT_Request_Size:\n" )); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Size_Metrics* metrics = &face->size->metrics; + + + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } +#endif + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_RequestRec req; + + + /* check of `face' delayed to `FT_Request_Size' */ + + if ( !char_width ) + char_width = char_height; + else if ( !char_height ) + char_height = char_width; + + if ( !horz_resolution ) + horz_resolution = vert_resolution; + else if ( !vert_resolution ) + vert_resolution = horz_resolution; + + if ( char_width < 1 * 64 ) + char_width = 1 * 64; + if ( char_height < 1 * 64 ) + char_height = 1 * 64; + + if ( !horz_resolution ) + horz_resolution = vert_resolution = 72; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = char_width; + req.height = char_height; + req.horiResolution = horz_resolution; + req.vertResolution = vert_resolution; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Size_RequestRec req; + + + /* check of `face' delayed to `FT_Request_Size' */ + + if ( pixel_width == 0 ) + pixel_width = pixel_height; + else if ( pixel_height == 0 ) + pixel_height = pixel_width; + + if ( pixel_width < 1 ) + pixel_width = 1; + if ( pixel_height < 1 ) + pixel_height = 1; + + /* use `>=' to avoid potential compiler warning on 16bit platforms */ + if ( pixel_width >= 0xFFFFU ) + pixel_width = 0xFFFFU; + if ( pixel_height >= 0xFFFFU ) + pixel_height = 0xFFFFU; + + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = (FT_Long)( pixel_width << 6 ); + req.height = (FT_Long)( pixel_height << 6 ); + req.horiResolution = 0; + req.vertResolution = 0; + + return FT_Request_Size( face, &req ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !akerning ) + return FT_THROW( Invalid_Argument ); + + driver = face->driver; + + akerning->x = 0; + akerning->y = 0; + + if ( driver->clazz->get_kerning ) + { + error = driver->clazz->get_kerning( face, + left_glyph, + right_glyph, + akerning ); + if ( !error ) + { + if ( kern_mode != FT_KERNING_UNSCALED ) + { + akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); + akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); + + if ( kern_mode != FT_KERNING_UNFITTED ) + { + FT_Pos orig_x = akerning->x; + FT_Pos orig_y = akerning->y; + + + /* we scale down kerning values for small ppem values */ + /* to avoid that rounding makes them too big. */ + /* `25' has been determined heuristically. */ + if ( face->size->metrics.x_ppem < 25 ) + akerning->x = FT_MulDiv( orig_x, + face->size->metrics.x_ppem, 25 ); + if ( face->size->metrics.y_ppem < 25 ) + akerning->y = FT_MulDiv( orig_y, + face->size->metrics.y_ppem, 25 ); + + akerning->x = FT_PIX_ROUND( akerning->x ); + akerning->y = FT_PIX_ROUND( akerning->y ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Pos orig_x_rounded = FT_PIX_ROUND( orig_x ); + FT_Pos orig_y_rounded = FT_PIX_ROUND( orig_y ); + + + if ( akerning->x != orig_x_rounded || + akerning->y != orig_y_rounded ) + FT_TRACE5(( "FT_Get_Kerning: horizontal kerning" + " (%ld, %ld) scaled down to (%ld, %ld) pixels\n", + orig_x_rounded / 64, orig_y_rounded / 64, + akerning->x / 64, akerning->y / 64 )); + } +#endif + } + } + } + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ) + { + FT_Service_Kerning service; + FT_Error error = FT_Err_Ok; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !akerning ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, KERNING ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + error = service->get_track( face, + point_size, + degree, + akerning ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + /* FT_ENCODING_NONE is a valid encoding for BDF, PCF, and Windows FNT */ + if ( encoding == FT_ENCODING_NONE && !face->num_charmaps ) + return FT_THROW( Invalid_Argument ); + + /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ + /* charmap available, i.e., one with UCS-4 characters, if possible. */ + /* */ + /* This is done by find_unicode_charmap() above, to share code. */ + if ( encoding == FT_ENCODING_UNICODE ) + return find_unicode_charmap( face ); + + cur = face->charmaps; + if ( !cur ) + return FT_THROW( Invalid_CharMap_Handle ); + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0]->encoding == encoding ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_Argument ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ) + { + FT_CharMap* cur; + FT_CharMap* limit; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + cur = face->charmaps; + if ( !cur || !charmap ) + return FT_THROW( Invalid_CharMap_Handle ); + + limit = cur + face->num_charmaps; + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == charmap && + FT_Get_CMap_Format ( charmap ) != 14 ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + + return FT_THROW( Invalid_Argument ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ) + { + FT_Int i; + + + if ( !charmap || !charmap->face ) + return -1; + + for ( i = 0; i < charmap->face->num_charmaps; i++ ) + if ( charmap->face->charmaps[i] == charmap ) + break; + + FT_ASSERT( i < charmap->face->num_charmaps ); + + return i; + } + + + static void + ft_cmap_done_internal( FT_CMap cmap ) + { + FT_CMap_Class clazz = cmap->clazz; + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( clazz->done ) + clazz->done( cmap ); + + FT_FREE( cmap ); + } + + + FT_BASE_DEF( void ) + FT_CMap_Done( FT_CMap cmap ) + { + if ( cmap ) + { + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error; + FT_Int i, j; + + + for ( i = 0; i < face->num_charmaps; i++ ) + { + if ( (FT_CMap)face->charmaps[i] == cmap ) + { + FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; + + + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) + return; + + /* remove it from our list of charmaps */ + for ( j = i + 1; j < face->num_charmaps; j++ ) + { + if ( j == face->num_charmaps - 1 ) + face->charmaps[j - 1] = last_charmap; + else + face->charmaps[j - 1] = face->charmaps[j]; + } + + face->num_charmaps--; + + if ( (FT_CMap)face->charmap == cmap ) + face->charmap = NULL; + + ft_cmap_done_internal( cmap ); + + break; + } + } + } + } + + + FT_BASE_DEF( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ) + { + FT_Error error; + FT_Face face; + FT_Memory memory; + FT_CMap cmap = NULL; + + + if ( !clazz || !charmap || !charmap->face ) + return FT_THROW( Invalid_Argument ); + + face = charmap->face; + memory = FT_FACE_MEMORY( face ); + + if ( !FT_ALLOC( cmap, clazz->size ) ) + { + cmap->charmap = *charmap; + cmap->clazz = clazz; + + if ( clazz->init ) + { + error = clazz->init( cmap, init_data ); + if ( error ) + goto Fail; + } + + /* add it to our list of charmaps */ + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) + goto Fail; + + face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; + } + + Exit: + if ( acmap ) + *acmap = cmap; + + return error; + + Fail: + ft_cmap_done_internal( cmap ); + cmap = NULL; + goto Exit; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ) + { + FT_UInt result = 0; + + + if ( face && face->charmap ) + { + FT_CMap cmap = FT_CMAP( face->charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + + result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); + if ( result >= (FT_UInt)face->num_glyphs ) + result = 0; + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + /* only do something if we have a charmap, and we have glyphs at all */ + if ( face && face->charmap && face->num_glyphs ) + { + gindex = FT_Get_Char_Index( face, 0 ); + if ( gindex == 0 ) + result = FT_Get_Next_Char( face, 0, &gindex ); + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong charcode, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + + + if ( face && face->charmap && face->num_glyphs ) + { + FT_UInt32 code = (FT_UInt32)charcode; + FT_CMap cmap = FT_CMAP( face->charmap ); + + + do + { + gindex = cmap->clazz->char_next( cmap, &code ); + + } while ( gindex >= (FT_UInt)face->num_glyphs ); + + result = ( gindex == 0 ) ? 0 : code; + } + + if ( agindex ) + *agindex = gindex; + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Face_Properties( FT_Face face, + FT_UInt num_properties, + FT_Parameter* properties ) + { + FT_Error error = FT_Err_Ok; + + + if ( num_properties > 0 && !properties ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + for ( ; num_properties > 0; num_properties-- ) + { + if ( properties->tag == FT_PARAM_TAG_STEM_DARKENING ) + { + if ( properties->data ) + { + if ( *( (FT_Bool*)properties->data ) == TRUE ) + face->internal->no_stem_darkening = FALSE; + else + face->internal->no_stem_darkening = TRUE; + } + else + { + /* use module default */ + face->internal->no_stem_darkening = -1; + } + } + else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS ) + { +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + if ( properties->data ) + { + ft_memcpy( face->internal->lcd_weights, + properties->data, + FT_LCD_FILTER_FIVE_TAPS ); + face->internal->lcd_filter_func = ft_lcd_filter_fir; + } +#else + error = FT_THROW( Unimplemented_Feature ); + goto Exit; +#endif + } + else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED ) + { + if ( properties->data ) + { + face->internal->random_seed = *( (FT_Int32*)properties->data ); + if ( face->internal->random_seed < 0 ) + face->internal->random_seed = 0; + } + else + { + /* use module default */ + face->internal->random_seed = -1; + } + } + else + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( error ) + break; + + properties++; + } + + Exit: + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_UInt result = 0; + + + if ( face && + face->charmap && + face->charmap->encoding == FT_ENCODING_UNICODE ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + FT_CMap ucmap = FT_CMAP( face->charmap ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIndex:" + " too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIndex:" + " too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->char_var_index( vcmap, ucmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_Int result = -1; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" + " too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" + " too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->char_var_default( vcmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + result = vcmap->clazz->variant_list( vcmap, memory ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Face_GetVariantsOfChar: too large charcode" )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); + } + + result = vcmap->clazz->charvariant_list( vcmap, memory, + (FT_UInt32)charcode ); + } + } + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ) + { + FT_UInt32 *result = NULL; + + + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + + + if ( charmap ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); + } + + result = vcmap->clazz->variantchar_list( vcmap, memory, + (FT_UInt32)variantSelector ); + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + const FT_String* glyph_name ) + { + FT_UInt result = 0; + + + if ( face && + FT_HAS_GLYPH_NAMES( face ) && + glyph_name ) + { + FT_Service_GlyphDict service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + + if ( service && service->name_index ) + result = service->name_index( face, glyph_name ); + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_Error error; + FT_Service_GlyphDict service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !buffer || buffer_max == 0 ) + return FT_THROW( Invalid_Argument ); + + /* clean up buffer */ + ((FT_Byte*)buffer)[0] = '\0'; + + if ( (FT_Long)glyph_index >= face->num_glyphs ) + return FT_THROW( Invalid_Glyph_Index ); + + if ( !FT_HAS_GLYPH_NAMES( face ) ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT ); + if ( service && service->get_name ) + error = service->get_name( face, glyph_index, buffer, buffer_max ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( const char* ) + FT_Get_Postscript_Name( FT_Face face ) + { + const char* result = NULL; + + + if ( !face ) + goto Exit; + + if ( !result ) + { + FT_Service_PsFontName service; + + + FT_FACE_LOOKUP_SERVICE( face, + service, + POSTSCRIPT_FONT_NAME ); + + if ( service && service->get_ps_font_name ) + result = service->get_ps_font_name( face ); + } + + Exit: + return result; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ) + { + void* table = NULL; + FT_Service_SFNT_Table service; + + + if ( face && FT_IS_SFNT( face ) ) + { + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service ) + table = service->get_table( face, tag ); + } + + return table; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Service_SFNT_Table service; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + return service->load_table( face, tag, offset, buffer, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ) + { + FT_Service_SFNT_Table service; + FT_ULong offset; + + + /* test for valid `length' delayed to `service->table_info' */ + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( !service ) + return FT_THROW( Unimplemented_Feature ); + + return service->table_info( face, table_index, tag, &offset, length ); + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return 0; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( !service ) + return 0; + if ( service->get_cmap_info( charmap, &cmap_info )) + return 0; + + return cmap_info.language; + } + + + /* documentation is in tttables.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + + + if ( !charmap || !charmap->face ) + return -1; + + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( !service ) + return -1; + if ( service->get_cmap_info( charmap, &cmap_info )) + return -1; + + return cmap_info.format; + } + + + /* documentation is in ftsizes.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Activate_Size( FT_Size size ) + { + FT_Face face; + + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + face = size->face; + if ( !face || !face->driver ) + return FT_THROW( Invalid_Face_Handle ); + + /* we don't need anything more complex than that; all size objects */ + /* are already listed by the face */ + face->size = size; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** R E N D E R E R S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* lookup a renderer by glyph format in the library's list */ + FT_BASE_DEF( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ) + { + FT_ListNode cur; + FT_Renderer result = NULL; + + + if ( !library ) + goto Exit; + + cur = library->renderers.head; + + if ( node ) + { + if ( *node ) + cur = (*node)->next; + *node = NULL; + } + + while ( cur ) + { + FT_Renderer renderer = FT_RENDERER( cur->data ); + + + if ( renderer->glyph_format == format ) + { + if ( node ) + *node = cur; + + result = renderer; + break; + } + cur = cur->next; + } + + Exit: + return result; + } + + + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ) + { + FT_Face face = slot->face; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Renderer result = library->cur_renderer; + + + if ( !result || result->glyph_format != slot->format ) + result = FT_Lookup_Renderer( library, slot->format, 0 ); + + return result; + } + + + static void + ft_set_current_renderer( FT_Library library ) + { + FT_Renderer renderer; + + + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); + library->cur_renderer = renderer; + } + + + static FT_Error + ft_add_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_Error error; + FT_ListNode node = NULL; + + + if ( FT_QNEW( node ) ) + goto Exit; + + { + FT_Renderer render = FT_RENDERER( module ); + FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; + + + render->clazz = clazz; + render->glyph_format = clazz->glyph_format; + + /* allocate raster object if needed */ + if ( clazz->raster_class && clazz->raster_class->raster_new ) + { + error = clazz->raster_class->raster_new( memory, &render->raster ); + if ( error ) + goto Fail; + + render->raster_render = clazz->raster_class->raster_render; + render->render = clazz->render_glyph; + } + +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG ) + render->render = clazz->render_glyph; +#endif + + /* add to list */ + node->data = module; + FT_List_Add( &library->renderers, node ); + + ft_set_current_renderer( library ); + } + + Fail: + if ( error ) + FT_FREE( node ); + + Exit: + return error; + } + + + static void + ft_remove_renderer( FT_Module module ) + { + FT_Library library; + FT_Memory memory; + FT_ListNode node; + + + library = module->library; + if ( !library ) + return; + + memory = library->memory; + + node = FT_List_Find( &library->renderers, module ); + if ( node ) + { + FT_Renderer render = FT_RENDERER( module ); + + + /* release raster object, if any */ + if ( render->raster ) + render->clazz->raster_class->raster_done( render->raster ); + + /* remove from list */ + FT_List_Remove( &library->renderers, node ); + FT_FREE( node ); + + ft_set_current_renderer( library ); + } + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ) + { + /* test for valid `library' delayed to `FT_Lookup_Renderer' */ + + return FT_Lookup_Renderer( library, format, 0 ); + } + + + /* documentation is in ftrender.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ) + { + FT_ListNode node; + FT_Error error = FT_Err_Ok; + + FT_Renderer_SetModeFunc set_mode; + + + if ( !library ) + { + error = FT_THROW( Invalid_Library_Handle ); + goto Exit; + } + + if ( !renderer ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( num_params > 0 && !parameters ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + node = FT_List_Find( &library->renderers, renderer ); + if ( !node ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_List_Up( &library->renderers, node ); + + if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) + library->cur_renderer = renderer; + + set_mode = renderer->clazz->set_mode; + + for ( ; num_params > 0; num_params-- ) + { + error = set_mode( renderer, parameters->tag, parameters->data ); + if ( error ) + break; + parameters++; + } + + Exit: + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = slot->face; + FT_Renderer renderer; + + + switch ( slot->format ) + { + default: + if ( slot->internal->load_flags & FT_LOAD_COLOR ) + { + FT_LayerIterator iterator; + + FT_UInt base_glyph = slot->glyph_index; + + FT_Bool have_layers; + FT_UInt glyph_index; + FT_UInt color_index; + + + /* check whether we have colored glyph layers */ + iterator.p = NULL; + have_layers = FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ); + if ( have_layers ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( !error ) + { + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + + do + { + FT_Int32 load_flags = slot->internal->load_flags; + + + /* disable the `FT_LOAD_COLOR' flag to avoid recursion */ + /* right here in this function */ + load_flags &= ~FT_LOAD_COLOR; + + /* render into the new `face->glyph' glyph slot */ + load_flags |= FT_LOAD_RENDER; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + break; + + /* blend new `face->glyph' into old `slot'; */ + /* at the first call, `slot' is still empty */ + error = sfnt->colr_blend( ttface, + color_index, + slot, + face->glyph ); + if ( error ) + break; + + } while ( FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ) ); + + if ( !error ) + slot->format = FT_GLYPH_FORMAT_BITMAP; + + /* this call also restores `slot' as the glyph slot */ + FT_Done_GlyphSlot( face->glyph ); + } + + if ( !error ) + return error; + + /* Failed to do the colored layer. Draw outline instead. */ + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + } + + { + FT_ListNode node = NULL; + + + /* small shortcut for the very common case */ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + + error = FT_ERR( Cannot_Render_Glyph ); + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, NULL ); + if ( !error || + FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format. */ + + /* now, look for another renderer that supports the same */ + /* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + } + + /* it is not an error if we cannot render a bitmap glyph */ + if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && + slot->format == FT_GLYPH_FORMAT_BITMAP ) + error = FT_Err_Ok; + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + +#undef FT_COMPONENT +#define FT_COMPONENT checksum + + /* + * Computing the MD5 checksum is expensive, unnecessarily distorting a + * possible profiling of FreeType if compiled with tracing support. For + * this reason, we execute the following code only if explicitly + * requested. + */ + + /* we use FT_TRACE3 in this block */ + if ( !error && + ft_trace_levels[trace_checksum] >= 3 && + slot->bitmap.buffer ) + { + FT_Bitmap bitmap; + FT_Error err; + + + FT_Bitmap_Init( &bitmap ); + + /* we convert to a single bitmap format for computing the checksum */ + /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */ + err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 ); + if ( !err ) + { + MD5_CTX ctx; + unsigned char md5[16]; + unsigned long coverage = 0; + int i, j; + int rows = (int)bitmap.rows; + int pitch = bitmap.pitch; + + + FT_TRACE3(( "FT_Render_Glyph: bitmap %dx%d, %s (mode %d)\n", + pitch, + rows, + pixel_modes[slot->bitmap.pixel_mode], + slot->bitmap.pixel_mode )); + + for ( i = 0; i < rows; i++ ) + for ( j = 0; j < pitch; j++ ) + coverage += bitmap.buffer[i * pitch + j]; + + FT_TRACE3(( " Total coverage: %lu\n", coverage )); + + MD5_Init( &ctx ); + if ( bitmap.buffer ) + MD5_Update( &ctx, bitmap.buffer, + (unsigned long)rows * (unsigned long)pitch ); + MD5_Final( md5, &ctx ); + + FT_TRACE3(( " MD5 checksum: " )); + for ( i = 0; i < 16; i++ ) + FT_TRACE3(( "%02X", md5[i] )); + FT_TRACE3(( "\n" )); + } + + FT_Bitmap_Done( library, &bitmap ); + } + + /* + * Dump bitmap in Netpbm format (PBM or PGM). + */ + + /* we use FT_TRACE7 in this block */ + if ( !error && + ft_trace_levels[trace_checksum] >= 7 && + slot->bitmap.buffer ) + { + if ( slot->bitmap.rows < 128U && + slot->bitmap.width < 128U ) + { + int rows = (int)slot->bitmap.rows; + int width = (int)slot->bitmap.width; + int pitch = slot->bitmap.pitch; + int i, j, m; + + unsigned char* topleft = slot->bitmap.buffer; + + + if ( pitch < 0 ) + topleft -= pitch * ( rows - 1 ); + + FT_TRACE7(( "Netpbm image: start\n" )); + switch ( slot->bitmap.pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + FT_TRACE7(( "P1 %d %d\n", width, rows )); + for ( i = 0; i < rows; i++ ) + { + for ( j = 0; j < width; ) + for ( m = 128; m > 0 && j < width; m >>= 1, j++ ) + FT_TRACE7(( " %d", + ( topleft[i * pitch + j / 8] & m ) != 0 )); + FT_TRACE7(( "\n" )); + } + break; + + default: + FT_TRACE7(( "P2 %d %d 255\n", width, rows )); + for ( i = 0; i < rows; i++ ) + { + for ( j = 0; j < width; j += 1 ) + FT_TRACE7(( " %3u", topleft[i * pitch + j] )); + FT_TRACE7(( "\n" )); + } + } + FT_TRACE7(( "Netpbm image: end\n" )); + } + else + FT_TRACE7(( "Netpbm image: too large, omitted\n" )); + } + +#undef FT_COMPONENT +#define FT_COMPONENT objs + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Library library; + + + if ( !slot || !slot->face ) + return FT_THROW( Invalid_Argument ); + + library = FT_FACE_LIBRARY( slot->face ); + + return FT_Render_Glyph_Internal( library, slot, render_mode ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** M O D U L E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * Destroy_Module + * + * @Description: + * Destroys a given module object. For drivers, this also destroys + * all child faces. + * + * @InOut: + * module :: + * A handle to the target driver object. + * + * @Note: + * The driver _must_ be LOCKED! + */ + static void + Destroy_Module( FT_Module module ) + { + FT_Memory memory = module->memory; + FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + + + if ( library && library->auto_hinter == module ) + library->auto_hinter = NULL; + + /* if the module is a renderer */ + if ( FT_MODULE_IS_RENDERER( module ) ) + ft_remove_renderer( module ); + + /* if the module is a font driver, add some steps */ + if ( FT_MODULE_IS_DRIVER( module ) ) + Destroy_Driver( FT_DRIVER( module ) ); + + /* finalize the module object */ + if ( clazz->module_done ) + clazz->module_done( module ); + + /* discard it */ + FT_FREE( module ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ) + { + FT_Error error; + FT_Memory memory; + FT_Module module = NULL; + FT_UInt nn; + + +#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ + FREETYPE_MINOR ) + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !clazz ) + return FT_THROW( Invalid_Argument ); + + /* check FreeType version */ + if ( clazz->module_requires > FREETYPE_VER_FIXED ) + return FT_THROW( Invalid_Version ); + + /* look for a module with the same name in the library's table */ + for ( nn = 0; nn < library->num_modules; nn++ ) + { + module = library->modules[nn]; + if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) + { + /* this installed module has the same name, compare their versions */ + if ( clazz->module_version <= module->clazz->module_version ) + return FT_THROW( Lower_Module_Version ); + + /* remove the module from our list, then exit the loop to replace */ + /* it by our new version.. */ + FT_Remove_Module( library, module ); + break; + } + } + + memory = library->memory; + error = FT_Err_Ok; + + if ( library->num_modules >= FT_MAX_MODULES ) + { + error = FT_THROW( Too_Many_Drivers ); + goto Exit; + } + + /* allocate module object */ + if ( FT_ALLOC( module, clazz->module_size ) ) + goto Exit; + + /* base initialization */ + module->library = library; + module->memory = memory; + module->clazz = (FT_Module_Class*)clazz; + + /* check whether the module is a renderer - this must be performed */ + /* before the normal module initialization */ + if ( FT_MODULE_IS_RENDERER( module ) ) + { + /* add to the renderers list */ + error = ft_add_renderer( module ); + if ( error ) + goto Fail; + } + + /* is the module a auto-hinter? */ + if ( FT_MODULE_IS_HINTER( module ) ) + library->auto_hinter = module; + + /* if the module is a font driver */ + if ( FT_MODULE_IS_DRIVER( module ) ) + { + FT_Driver driver = FT_DRIVER( module ); + + + driver->clazz = (FT_Driver_Class)module->clazz; + } + + if ( clazz->module_init ) + { + error = clazz->module_init( module ); + if ( error ) + goto Fail; + } + + /* add module to the library's table */ + library->modules[library->num_modules++] = module; + + Exit: + return error; + + Fail: + if ( FT_MODULE_IS_RENDERER( module ) ) + { + FT_Renderer renderer = FT_RENDERER( module ); + + + if ( renderer->clazz && + renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + renderer->raster ) + renderer->clazz->raster_class->raster_done( renderer->raster ); + } + + FT_FREE( module ); + goto Exit; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ) + { + FT_Module result = NULL; + FT_Module* cur; + FT_Module* limit; + + + if ( !library || !module_name ) + return result; + + cur = library->modules; + limit = cur + library->num_modules; + + for ( ; cur < limit; cur++ ) + if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) + { + result = cur[0]; + break; + } + + return result; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ) + { + FT_Module module; + + + /* test for valid `library' delayed to FT_Get_Module() */ + + module = FT_Get_Module( library, mod_name ); + + return module ? module->clazz->module_interface : 0; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id, + FT_Bool global ) + { + FT_Pointer result = NULL; + + + if ( module ) + { + FT_ASSERT( module->clazz && module->clazz->get_interface ); + + /* first, look for the service in the module */ + if ( module->clazz->get_interface ) + result = module->clazz->get_interface( module, service_id ); + + if ( global && !result ) + { + /* we didn't find it, look in all other modules then */ + FT_Library library = module->library; + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] != module ) + { + FT_ASSERT( cur[0]->clazz ); + + if ( cur[0]->clazz->get_interface ) + { + result = cur[0]->clazz->get_interface( cur[0], service_id ); + if ( result ) + break; + } + } + } + } + } + + return result; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ) + { + /* try to find the module from the table, then remove it from there */ + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( module ) + { + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + + + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == module ) + { + /* remove it from the table */ + library->num_modules--; + limit--; + while ( cur < limit ) + { + cur[0] = cur[1]; + cur++; + } + limit[0] = NULL; + + /* destroy the module */ + Destroy_Module( module ); + + return FT_Err_Ok; + } + } + } + return FT_THROW( Invalid_Driver_Handle ); + } + + + static FT_Error + ft_property_do( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value, + FT_Bool set, + FT_Bool value_is_string ) + { + FT_Module* cur; + FT_Module* limit; + FT_Module_Interface interface; + + FT_Service_Properties service; + +#ifdef FT_DEBUG_LEVEL_ERROR + const FT_String* set_name = "FT_Property_Set"; + const FT_String* get_name = "FT_Property_Get"; + const FT_String* func_name = set ? set_name : get_name; +#endif + + FT_Bool missing_func; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !module_name || !property_name || !value ) + return FT_THROW( Invalid_Argument ); + + cur = library->modules; + limit = cur + library->num_modules; + + /* search module */ + for ( ; cur < limit; cur++ ) + if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) ) + break; + + if ( cur == limit ) + { + FT_TRACE2(( "%s: can't find module `%s'\n", + func_name, module_name )); + return FT_THROW( Missing_Module ); + } + + /* check whether we have a service interface */ + if ( !cur[0]->clazz->get_interface ) + { + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + /* search property service */ + interface = cur[0]->clazz->get_interface( cur[0], + FT_SERVICE_ID_PROPERTIES ); + if ( !interface ) + { + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + service = (FT_Service_Properties)interface; + + if ( set ) + missing_func = FT_BOOL( !service->set_property ); + else + missing_func = FT_BOOL( !service->get_property ); + + if ( missing_func ) + { + FT_TRACE2(( "%s: property service of module `%s' is broken\n", + func_name, module_name )); + return FT_THROW( Unimplemented_Feature ); + } + + return set ? service->set_property( cur[0], + property_name, + value, + value_is_string ) + : service->get_property( cur[0], + property_name, + value ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ) + { + return ft_property_do( library, + module_name, + property_name, + (void*)value, + TRUE, + FALSE ); + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ) + { + return ft_property_do( library, + module_name, + property_name, + value, + FALSE, + FALSE ); + } + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + /* this variant is used for handling the FREETYPE_PROPERTIES */ + /* environment variable */ + + FT_BASE_DEF( FT_Error ) + ft_property_string_set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + FT_String* value ) + { + return ft_property_do( library, + module_name, + property_name, + (void*)value, + TRUE, + TRUE ); + } + +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** L I B R A R Y ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Library( FT_Library library ) + { + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + library->refcount++; + + return FT_Err_Ok; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ) + { + FT_Library library = NULL; + FT_Error error; + + + if ( !memory || !alibrary ) + return FT_THROW( Invalid_Argument ); + +#ifndef FT_DEBUG_LOGGING +#ifdef FT_DEBUG_LEVEL_ERROR + /* init debugging support */ + ft_debug_init(); +#endif /* FT_DEBUG_LEVEL_ERROR */ +#endif /* !FT_DEBUG_LOGGING */ + + /* first of all, allocate the library object */ + if ( FT_NEW( library ) ) + return error; + + library->memory = memory; + + library->version_major = FREETYPE_MAJOR; + library->version_minor = FREETYPE_MINOR; + library->version_patch = FREETYPE_PATCH; + + library->refcount = 1; + + /* That's ok now */ + *alibrary = library; + + return FT_Err_Ok; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ) + { + FT_Int major = 0; + FT_Int minor = 0; + FT_Int patch = 0; + + + if ( library ) + { + major = library->version_major; + minor = library->version_minor; + patch = library->version_patch; + } + + if ( amajor ) + *amajor = major; + + if ( aminor ) + *aminor = minor; + + if ( apatch ) + *apatch = patch; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Done_Library( FT_Library library ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + library->refcount--; + if ( library->refcount > 0 ) + goto Exit; + + memory = library->memory; + + /* + * Close all faces in the library. If we don't do this, we can have + * some subtle memory leaks. + * + * Example: + * + * - the cff font driver uses the pshinter module in cff_size_done + * - if the pshinter module is destroyed before the cff font driver, + * opened FT_Face objects managed by the driver are not properly + * destroyed, resulting in a memory leak + * + * Some faces are dependent on other faces, like Type42 faces that + * depend on TrueType faces synthesized internally. + * + * The order of drivers should be specified in driver_name[]. + */ + { + FT_UInt m, n; + const char* driver_name[] = { "type42", NULL }; + + + for ( m = 0; + m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); + m++ ) + { + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + const char* module_name = module->clazz->module_name; + FT_List faces; + + + if ( driver_name[m] && + ft_strcmp( module_name, driver_name[m] ) != 0 ) + continue; + + if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) + continue; + + FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name )); + + faces = &FT_DRIVER( module )->faces_list; + while ( faces->head ) + { + FT_Done_Face( FT_FACE( faces->head->data ) ); + if ( faces->head ) + FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" )); + } + } + } + } + + /* Close all other modules in the library */ +#if 1 + /* XXX Modules are removed in the reversed order so that */ + /* type42 module is removed before truetype module. This */ + /* avoids double free in some occasions. It is a hack. */ + while ( library->num_modules > 0 ) + FT_Remove_Module( library, + library->modules[library->num_modules - 1] ); +#else + { + FT_UInt n; + + + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + + + if ( module ) + { + Destroy_Module( module ); + library->modules[n] = NULL; + } + } + } +#endif + + FT_FREE( library ); + + Exit: + return FT_Err_Ok; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ) + { + if ( library && debug_hook && + hook_index < + ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) + library->debug_hooks[hook_index] = debug_hook; + } + + + /* documentation is in ftmodapi.h */ + + FT_EXPORT_DEF( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ) + { + FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; + + + if ( library ) + { + FT_Module module = FT_Get_Module( library, "truetype" ); + + + if ( module ) + { + FT_Service_TrueTypeEngine service; + + + service = (FT_Service_TrueTypeEngine) + ft_module_get_service( module, + FT_SERVICE_ID_TRUETYPE_ENGINE, + 0 ); + if ( service ) + result = service->engine_type; + } + } + + return result; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( glyph && + glyph->subglyphs && + glyph->format == FT_GLYPH_FORMAT_COMPOSITE && + sub_index < glyph->num_subglyphs ) + { + FT_SubGlyph subg = glyph->subglyphs + sub_index; + + + *p_index = subg->index; + *p_flags = subg->flags; + *p_arg1 = subg->arg1; + *p_arg2 = subg->arg2; + *p_transform = subg->transform; + + error = FT_Err_Ok; + } + + return error; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || + !aglyph_index || + !acolor_index || + !iterator || + base_glyph >= (FT_UInt)face->num_glyphs ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_layer ) + return sfnt->get_colr_layer( ttface, + base_glyph, + aglyph_index, + acolor_index, + iterator ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_glyph_paint ) + return sfnt->get_colr_glyph_paint( ttface, + base_glyph, + root_transform, + paint ); + else + return 0; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !clip_box ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_color_glyph_clipbox ) + return sfnt->get_color_glyph_clipbox( ttface, + base_glyph, + clip_box ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* layer_iterator, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint || !layer_iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint_layers ) + return sfnt->get_paint_layers( ttface, layer_iterator, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint ) + return sfnt->get_paint( ttface, opaque_paint, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Colorline_Stops ( FT_Face face, + FT_ColorStop * color_stop, + FT_ColorStopIterator *iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !color_stop || !iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colorline_stops ) + return sfnt->get_colorline_stops ( ttface, color_stop, iterator ); + else + return 0; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftotval.c b/Dependencies/freetype/freetype/src/base/ftotval.c new file mode 100644 index 00000000..aed9eef3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftotval.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * + * ftotval.c + * + * FreeType API for validating OpenType tables (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include + +#include +#include +#include + + + /* documentation is in ftotval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ) + { + FT_Service_OTvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( !( BASE_table && + GDEF_table && + GPOS_table && + GSUB_table && + JSTF_table ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + BASE_table, + GDEF_table, + GPOS_table, + GSUB_table, + JSTF_table ); + else + error = FT_THROW( Unimplemented_Feature ); + + Exit: + return error; + } + + + FT_EXPORT_DEF( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( table ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftoutln.c b/Dependencies/freetype/freetype/src/base/ftoutln.c new file mode 100644 index 00000000..ef699b3c --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftoutln.c @@ -0,0 +1,1120 @@ +/**************************************************************************** + * + * ftoutln.c + * + * FreeType outline management (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT outline + + + static + const FT_Outline null_outline = { 0, 0, NULL, NULL, NULL, 0 }; + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + FT_Byte* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + + FT_Int tag; /* current point's state */ + + FT_Int shift; + FT_Pos delta; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return FT_THROW( Invalid_Argument ); + + shift = func_interface->shift; + delta = func_interface->delta; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); + + first = last + 1; + last = outline->contours[n]; + if ( last < first ) + goto Invalid_Outline; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + /* v_last = v_start; */ + } + point--; + tags--; + } + + FT_TRACE5(( " move to (%.2f, %.2f)\n", + (double)v_start.x / 64, (double)v_start.y / 64 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " line to (%.2f, %.2f)\n", + (double)vec.x / 64, (double)vec.y / 64 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)vec.x / 64, + (double)vec.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)v_middle.x / 64, + (double)v_middle.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + (double)vec.x / 64, + (double)vec.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + (double)v_start.x / 64, (double)v_start.y / 64 )); + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + } + + FT_TRACE5(( "FT_Outline_Decompose: Done\n" )); + return FT_Err_Ok; + + Invalid_Outline: + error = FT_THROW( Invalid_Outline ); + /* fall through */ + + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + FT_Error error; + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + memory = library->memory; + + if ( !anoutline || !memory ) + return FT_THROW( Invalid_Argument ); + + *anoutline = null_outline; + + if ( numContours < 0 || + (FT_UInt)numContours > numPoints ) + return FT_THROW( Invalid_Argument ); + + if ( numPoints > FT_OUTLINE_POINTS_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_NEW_ARRAY( anoutline->points, numPoints ) || + FT_NEW_ARRAY( anoutline->tags, numPoints ) || + FT_NEW_ARRAY( anoutline->contours, numContours ) ) + goto Fail; + + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_UShort)numContours; + anoutline->flags |= FT_OUTLINE_OWNER; + + return FT_Err_Ok; + + Fail: + anoutline->flags |= FT_OUTLINE_OWNER; + FT_Outline_Done( library, anoutline ); + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Check( FT_Outline* outline ) + { + if ( outline ) + { + FT_Int n_points = outline->n_points; + FT_Int n_contours = outline->n_contours; + FT_Int end0, end; + FT_Int n; + + + FT_TRACE5(( "FT_Outline_Check: contours = %d, points = %d\n", + n_contours, n_points )); + /* empty glyph? */ + if ( n_points == 0 && n_contours == 0 ) + return FT_Err_Ok; + + /* check point and contour counts */ + if ( n_points == 0 || n_contours == 0 ) + goto Bad; + + end0 = -1; + for ( n = 0; n < n_contours; n++ ) + { + end = outline->contours[n]; + + /* note that we don't accept empty contours */ + if ( end <= end0 || end >= n_points ) + goto Bad; + + end0 = end; + } + + if ( end0 != n_points - 1 ) + goto Bad; + + /* XXX: check the tags array */ + return FT_Err_Ok; + } + + Bad: + return FT_THROW( Invalid_Outline ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ) + { + FT_Int is_owner; + + + if ( !source || !target ) + return FT_THROW( Invalid_Outline ); + + if ( source->n_points != target->n_points || + source->n_contours != target->n_contours ) + return FT_THROW( Invalid_Argument ); + + if ( source == target ) + return FT_Err_Ok; + + if ( source->n_points ) + { + FT_ARRAY_COPY( target->points, source->points, source->n_points ); + FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); + } + + if ( source->n_contours ) + FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); + + /* copy all flags, except the `FT_OUTLINE_OWNER' one */ + is_owner = target->flags & FT_OUTLINE_OWNER; + target->flags = source->flags; + + target->flags &= ~FT_OUTLINE_OWNER; + target->flags |= is_owner; + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ) + { + FT_Memory memory; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + memory = library->memory; + + if ( !memory ) + return FT_THROW( Invalid_Argument ); + + if ( outline->flags & FT_OUTLINE_OWNER ) + { + FT_FREE( outline->points ); + FT_FREE( outline->tags ); + FT_FREE( outline->contours ); + } + *outline = null_outline; + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ) + { + FT_Pos xMin, yMin, xMax, yMax; + + + if ( outline && acbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for ( ; vec < limit; vec++ ) + { + FT_Pos x, y; + + + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ) + { + FT_UShort n; + FT_Vector* vec; + + + if ( !outline ) + return; + + vec = outline->points; + + for ( n = 0; n < outline->n_points; n++ ) + { + vec->x = ADD_LONG( vec->x, xOffset ); + vec->y = ADD_LONG( vec->y, yOffset ); + vec++; + } + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Reverse( FT_Outline* outline ) + { + FT_UShort n; + FT_Int first, last; + + + if ( !outline ) + return; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + /* keep the first contour point as is and swap points around it */ + /* to guarantee that the cubic arches stay valid after reverse */ + first = last + 2; + last = outline->contours[n]; + + /* reverse point table */ + { + FT_Vector* p = outline->points + first; + FT_Vector* q = outline->points + last; + FT_Vector swap; + + + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + + /* reverse tags table */ + { + FT_Byte* p = outline->tags + first; + FT_Byte* q = outline->tags + last; + + + while ( p < q ) + { + FT_Byte swap; + + + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + } + + outline->flags ^= FT_OUTLINE_REVERSE_FILL; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ) + { + FT_Error error; + FT_Renderer renderer; + FT_ListNode node; + FT_BBox cbox; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !params ) + return FT_THROW( Invalid_Argument ); + + FT_Outline_Get_CBox( outline, &cbox ); + if ( cbox.xMin < -0x1000000L || cbox.yMin < -0x1000000L || + cbox.xMax > 0x1000000L || cbox.yMax > 0x1000000L ) + return FT_THROW( Invalid_Outline ); + + renderer = library->cur_renderer; + node = library->renderers.head; + + params->source = (void*)outline; + + /* preset clip_box for direct mode */ + if ( params->flags & FT_RASTER_FLAG_DIRECT && + !( params->flags & FT_RASTER_FLAG_CLIP ) ) + { + params->clip_box.xMin = cbox.xMin >> 6; + params->clip_box.yMin = cbox.yMin >> 6; + params->clip_box.xMax = ( cbox.xMax + 63 ) >> 6; + params->clip_box.yMax = ( cbox.yMax + 63 ) >> 6; + } + + error = FT_ERR( Cannot_Render_Glyph ); + while ( renderer ) + { + error = renderer->raster_render( renderer->raster, params ); + if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) + break; + + /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format */ + + /* now, look for another renderer that supports the same */ + /* format */ + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, + &node ); + } + + return error; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ) + { + FT_Raster_Params params; + + + if ( !abitmap ) + return FT_THROW( Invalid_Argument ); + + /* other checks are delayed to `FT_Outline_Render' */ + + params.target = abitmap; + params.flags = 0; + + if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + params.flags |= FT_RASTER_FLAG_AA; + + return FT_Outline_Render( library, outline, ¶ms ); + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ) + { + FT_Pos xz, yz; + + + if ( !vector || !matrix ) + return; + + xz = FT_MulFix( vector->x, matrix->xx ) + + FT_MulFix( vector->y, matrix->xy ); + + yz = FT_MulFix( vector->x, matrix->yx ) + + FT_MulFix( vector->y, matrix->yy ); + + vector->x = xz; + vector->y = yz; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ) + { + FT_Vector* vec; + FT_Vector* limit; + + + if ( !outline || !matrix || !outline->points ) + return; + + vec = outline->points; + limit = vec + outline->n_points; + + for ( ; vec < limit; vec++ ) + FT_Vector_Transform( vec, matrix ); + } + + +#if 0 + +#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \ + do \ + { \ + (first) = ( c > 0 ) ? (outline)->points + \ + (outline)->contours[c - 1] + 1 \ + : (outline)->points; \ + (last) = (outline)->points + (outline)->contours[c]; \ + } while ( 0 ) + + + /* Is a point in some contour? */ + /* */ + /* We treat every point of the contour as if it */ + /* it were ON. That is, we allow false positives, */ + /* but disallow false negatives. (XXX really?) */ + static FT_Bool + ft_contour_has( FT_Outline* outline, + FT_Short c, + FT_Vector* point ) + { + FT_Vector* first; + FT_Vector* last; + FT_Vector* a; + FT_Vector* b; + FT_UInt n = 0; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( a = first; a <= last; a++ ) + { + FT_Pos x; + FT_Int intersect; + + + b = ( a == last ) ? first : a + 1; + + intersect = ( a->y - point->y ) ^ ( b->y - point->y ); + + /* a and b are on the same side */ + if ( intersect >= 0 ) + { + if ( intersect == 0 && a->y == point->y ) + { + if ( ( a->x <= point->x && b->x >= point->x ) || + ( a->x >= point->x && b->x <= point->x ) ) + return 1; + } + + continue; + } + + x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); + + if ( x < point->x ) + n++; + else if ( x == point->x ) + return 1; + } + + return n & 1; + } + + + static FT_Bool + ft_contour_enclosed( FT_Outline* outline, + FT_UShort c ) + { + FT_Vector* first; + FT_Vector* last; + FT_Short i; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( i = 0; i < outline->n_contours; i++ ) + { + if ( i != c && ft_contour_has( outline, i, first ) ) + { + FT_Vector* pt; + + + for ( pt = first + 1; pt <= last; pt++ ) + if ( !ft_contour_has( outline, i, pt ) ) + return 0; + + return 1; + } + } + + return 0; + } + + + /* This version differs from the public one in that each */ + /* part (contour not enclosed in another contour) of the */ + /* outline is checked for orientation. This is */ + /* necessary for some buggy CJK fonts. */ + static FT_Orientation + ft_outline_get_orientation( FT_Outline* outline ) + { + FT_Short i; + FT_Vector* first; + FT_Vector* last; + FT_Orientation orient = FT_ORIENTATION_NONE; + + + first = outline->points; + for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) + { + FT_Vector* point; + FT_Vector* xmin_point; + FT_Pos xmin; + + + last = outline->points + outline->contours[i]; + + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + if ( ft_contour_enclosed( outline, i ) ) + continue; + + xmin = first->x; + xmin_point = first; + + for ( point = first + 1; point <= last; point++ ) + { + if ( point->x < xmin ) + { + xmin = point->x; + xmin_point = point; + } + } + + /* check the orientation of the contour */ + { + FT_Vector* prev; + FT_Vector* next; + FT_Orientation o; + + + prev = ( xmin_point == first ) ? last : xmin_point - 1; + next = ( xmin_point == last ) ? first : xmin_point + 1; + + if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > + FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) + o = FT_ORIENTATION_POSTSCRIPT; + else + o = FT_ORIENTATION_TRUETYPE; + + if ( orient == FT_ORIENTATION_NONE ) + orient = o; + else if ( orient != o ) + return FT_ORIENTATION_NONE; + } + } + + return orient; + } + +#endif /* 0 */ + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ) + { + return FT_Outline_EmboldenXY( outline, strength, strength ); + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ) + { + FT_Vector* points; + FT_Int c, first, last; + FT_Orientation orientation; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + xstrength /= 2; + ystrength /= 2; + if ( xstrength == 0 && ystrength == 0 ) + return FT_Err_Ok; + + orientation = FT_Outline_Get_Orientation( outline ); + if ( orientation == FT_ORIENTATION_NONE ) + { + if ( outline->n_contours ) + return FT_THROW( Invalid_Argument ); + else + return FT_Err_Ok; + } + + points = outline->points; + + last = -1; + for ( c = 0; c < outline->n_contours; c++ ) + { + FT_Vector in, out, anchor, shift; + FT_Fixed l_in, l_out, l_anchor = 0, l, q, d; + FT_Int i, j, k; + + + first = last + 1; + last = outline->contours[c]; + l_in = 0; + + /* pacify compiler */ + in.x = in.y = anchor.x = anchor.y = 0; + + /* Counter j cycles though the points; counter i advances only */ + /* when points are moved; anchor k marks the first moved point. */ + for ( i = last, j = first, k = -1; + j != i && i != k; + j = j < last ? j + 1 : first ) + { + if ( j != k ) + { + out.x = points[j].x - points[i].x; + out.y = points[j].y - points[i].y; + l_out = (FT_Fixed)FT_Vector_NormLen( &out ); + + if ( l_out == 0 ) + continue; + } + else + { + out = anchor; + l_out = l_anchor; + } + + if ( l_in != 0 ) + { + if ( k < 0 ) + { + k = i; + anchor = in; + l_anchor = l_in; + } + + d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y ); + + /* shift only if turn is less than ~160 degrees */ + if ( d > -0xF000L ) + { + d = d + 0x10000L; + + /* shift components along lateral bisector in proper orientation */ + shift.x = in.y + out.y; + shift.y = in.x + out.x; + + if ( orientation == FT_ORIENTATION_TRUETYPE ) + shift.x = -shift.x; + else + shift.y = -shift.y; + + /* restrict shift magnitude to better handle collapsing segments */ + q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x ); + if ( orientation == FT_ORIENTATION_TRUETYPE ) + q = -q; + + l = FT_MIN( l_in, l_out ); + + /* non-strict inequalities avoid divide-by-zero when q == l == 0 */ + if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) ) + shift.x = FT_MulDiv( shift.x, xstrength, d ); + else + shift.x = FT_MulDiv( shift.x, l, q ); + + + if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) ) + shift.y = FT_MulDiv( shift.y, ystrength, d ); + else + shift.y = FT_MulDiv( shift.y, l, q ); + } + else + shift.x = shift.y = 0; + + for ( ; + i != j; + i = i < last ? i + 1 : first ) + { + points[i].x += xstrength + shift.x; + points[i].y += ystrength + shift.y; + } + } + else + i = j; + + in = out; + l_in = l_out; + } + } + + return FT_Err_Ok; + } + + + /* documentation is in ftoutln.h */ + + FT_EXPORT_DEF( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ) + { + FT_BBox cbox = { 0, 0, 0, 0 }; + FT_Int xshift, yshift; + FT_Vector* points; + FT_Vector v_prev, v_cur; + FT_Int c, n, first, last; + FT_Pos area = 0; + + + if ( !outline || outline->n_points <= 0 ) + return FT_ORIENTATION_TRUETYPE; + + /* We use the nonzero winding rule to find the orientation. */ + /* Since glyph outlines behave much more `regular' than arbitrary */ + /* cubic or quadratic curves, this test deals with the polygon */ + /* only that is spanned up by the control points. */ + + FT_Outline_Get_CBox( outline, &cbox ); + + /* Handle collapsed outlines to avoid undefined FT_MSB. */ + if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) + return FT_ORIENTATION_NONE; + + /* Reject values large outlines. */ + if ( cbox.xMin < -0x1000000L || cbox.yMin < -0x1000000L || + cbox.xMax > 0x1000000L || cbox.yMax > 0x1000000L ) + return FT_ORIENTATION_NONE; + + xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | + FT_ABS( cbox.xMin ) ) ) - 14; + xshift = FT_MAX( xshift, 0 ); + + yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; + yshift = FT_MAX( yshift, 0 ); + + points = outline->points; + + last = -1; + for ( c = 0; c < outline->n_contours; c++ ) + { + first = last + 1; + last = outline->contours[c]; + + v_prev.x = points[last].x >> xshift; + v_prev.y = points[last].y >> yshift; + + for ( n = first; n <= last; n++ ) + { + v_cur.x = points[n].x >> xshift; + v_cur.y = points[n].y >> yshift; + + area = ADD_LONG( area, + MUL_LONG( v_cur.y - v_prev.y, + v_cur.x + v_prev.x ) ); + + v_prev = v_cur; + } + } + + if ( area > 0 ) + return FT_ORIENTATION_POSTSCRIPT; + else if ( area < 0 ) + return FT_ORIENTATION_TRUETYPE; + else + return FT_ORIENTATION_NONE; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftpatent.c b/Dependencies/freetype/freetype/src/base/ftpatent.c new file mode 100644 index 00000000..2055757e --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftpatent.c @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * ftpatent.c + * + * FreeType API for checking patented TrueType bytecode instructions + * (body). Obsolete, retained for backward compatibility. + * + * Copyright (C) 2007-2024 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include +#include + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ) + { + FT_UNUSED( face ); + + return FALSE; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ) + { + FT_UNUSED( face ); + FT_UNUSED( value ); + + return FALSE; + } + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftpfr.c b/Dependencies/freetype/freetype/src/base/ftpfr.c new file mode 100644 index 00000000..0caa9d1d --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftpfr.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * ftpfr.c + * + * FreeType API for accessing PFR-specific data (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include + +#include +#include + + + /* check the format */ + static FT_Service_PfrMetrics + ft_pfr_check( FT_Face face ) + { + FT_Service_PfrMetrics service = NULL; + + + if ( face ) + FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS ); + + return service; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + FT_Error error = FT_Err_Ok; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_metrics( face, + aoutline_resolution, + ametrics_resolution, + ametrics_x_scale, + ametrics_y_scale ); + } + else + { + FT_Fixed x_scale, y_scale; + + + /* this is not a PFR font */ + if ( aoutline_resolution ) + *aoutline_resolution = face->units_per_EM; + + if ( ametrics_resolution ) + *ametrics_resolution = face->units_per_EM; + + x_scale = y_scale = 0x10000L; + if ( face->size ) + { + x_scale = face->size->metrics.x_scale; + y_scale = face->size->metrics.y_scale; + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + error = FT_THROW( Unknown_File_Format ); + } + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !avector ) + return FT_THROW( Invalid_Argument ); + + service = ft_pfr_check( face ); + if ( service ) + error = service->get_kerning( face, left, right, avector ); + else + error = FT_Get_Kerning( face, left, right, + FT_KERNING_UNSCALED, avector ); + + return error; + } + + + /* documentation is in ftpfr.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ) + { + FT_Error error; + FT_Service_PfrMetrics service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !aadvance ) + return FT_THROW( Invalid_Argument ); + + service = ft_pfr_check( face ); + if ( service ) + error = service->get_advance( face, gindex, aadvance ); + else + /* XXX: TODO: PROVIDE ADVANCE-LOADING METHOD TO ALL FONT DRIVERS */ + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftpsprop.c b/Dependencies/freetype/freetype/src/base/ftpsprop.c new file mode 100644 index 00000000..37a6cee6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftpsprop.c @@ -0,0 +1,284 @@ +/**************************************************************************** + * + * ftpsprop.c + * + * Get and set properties of PostScript drivers (body). + * See `ftdriver.h' for available properties. + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psprops + + + FT_BASE_CALLBACK_DEF( FT_Error ) + ps_property_set( FT_Module module, /* PS_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + PS_Driver driver = (PS_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_Int dp[8]; + + + if ( value_is_string ) + { + const char* s = (const char*)value; + char* ep; + int i; + + + /* eight comma-separated numbers */ + for ( i = 0; i < 7; i++ ) + { + dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( *ep != ',' || s == ep ) + return FT_THROW( Invalid_Argument ); + + s = ep + 1; + } + + dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) + return FT_THROW( Invalid_Argument ); + + darken_params = dp; + } + else +#endif + darken_params = (FT_Int*)value; + + x1 = darken_params[0]; + y1 = darken_params[1]; + x2 = darken_params[2]; + y2 = darken_params[3]; + x3 = darken_params[4]; + y3 = darken_params[5]; + x4 = darken_params[6]; + y4 = darken_params[7]; + + if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || + y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || + x1 > x2 || x2 > x3 || x3 > x4 || + y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) + return FT_THROW( Invalid_Argument ); + + driver->darken_params[0] = x1; + driver->darken_params[1] = y1; + driver->darken_params[2] = x2; + driver->darken_params[3] = y2; + driver->darken_params[4] = x3; + driver->darken_params[5] = y3; + driver->darken_params[6] = x4; + driver->darken_params[7] = y4; + + return error; + } + + else if ( !ft_strcmp( property_name, "hinting-engine" ) ) + { +#if defined( CFF_CONFIG_OPTION_OLD_ENGINE ) || \ + defined( T1_CONFIG_OPTION_OLD_ENGINE ) + const char* module_name = module->clazz->module_name; +#endif + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + if ( !ft_strcmp( s, "adobe" ) ) + driver->hinting_engine = FT_HINTING_ADOBE; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( !ft_strcmp( module_name, "cff" ) && + !ft_strcmp( s, "freetype" ) ) + driver->hinting_engine = FT_HINTING_FREETYPE; +#endif + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + else if ( ( !ft_strcmp( module_name, "type1" ) || + !ft_strcmp( module_name, "t1cid" ) ) && + !ft_strcmp( s, "freetype" ) ) + driver->hinting_engine = FT_HINTING_FREETYPE; +#endif + + else + return FT_THROW( Invalid_Argument ); + } + else +#endif /* FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES */ + { + FT_UInt* hinting_engine = (FT_UInt*)value; + + + if ( *hinting_engine == FT_HINTING_ADOBE +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + || ( *hinting_engine == FT_HINTING_FREETYPE && + !ft_strcmp( module_name, "cff" ) ) +#endif +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + || ( *hinting_engine == FT_HINTING_FREETYPE && + ( !ft_strcmp( module_name, "type1" ) || + !ft_strcmp( module_name, "t1cid" ) ) ) +#endif + ) + driver->hinting_engine = *hinting_engine; + else + error = FT_ERR( Unimplemented_Feature ); + } + + return error; + } + + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long nsd = ft_strtol( s, NULL, 10 ); + + + if ( !nsd ) + driver->no_stem_darkening = FALSE; + else + driver->no_stem_darkening = TRUE; + } + else +#endif + { + FT_Bool* no_stem_darkening = (FT_Bool*)value; + + + driver->no_stem_darkening = *no_stem_darkening; + } + + return error; + } + + else if ( !ft_strcmp( property_name, "random-seed" ) ) + { + FT_Int32 random_seed; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + random_seed = (FT_Int32)ft_strtol( s, NULL, 10 ); + } + else +#endif + random_seed = *(FT_Int32*)value; + + if ( random_seed < 0 ) + random_seed = 0; + + driver->random_seed = random_seed; + + return error; + } + + FT_TRACE2(( "ps_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_BASE_CALLBACK_DEF( FT_Error ) + ps_property_get( FT_Module module, /* PS_Driver */ + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + PS_Driver driver = (PS_Driver)module; + + + if ( !ft_strcmp( property_name, "darkening-parameters" ) ) + { + FT_Int* darken_params = driver->darken_params; + FT_Int* val = (FT_Int*)value; + + + val[0] = darken_params[0]; + val[1] = darken_params[1]; + val[2] = darken_params[2]; + val[3] = darken_params[3]; + val[4] = darken_params[4]; + val[5] = darken_params[5]; + val[6] = darken_params[6]; + val[7] = darken_params[7]; + + return error; + } + + else if ( !ft_strcmp( property_name, "hinting-engine" ) ) + { + FT_UInt hinting_engine = driver->hinting_engine; + FT_UInt* val = (FT_UInt*)value; + + + *val = hinting_engine; + + return error; + } + + else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) + { + FT_Bool no_stem_darkening = driver->no_stem_darkening; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_stem_darkening; + + return error; + } + + FT_TRACE2(( "ps_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftrfork.c b/Dependencies/freetype/freetype/src/base/ftrfork.c new file mode 100644 index 00000000..dc9b043d --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftrfork.c @@ -0,0 +1,934 @@ +/**************************************************************************** + * + * ftrfork.c + * + * Embedded resource forks accessor (body). + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO and Redhat K.K. + * + * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are + * derived from ftobjs.c. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * Development of the code in this file is support of + * Information-technology Promotion Agency, Japan. + */ + + +#include +#include +#include + +#include "ftbase.h" + +#undef FT_COMPONENT +#define FT_COMPONENT raccess + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Resource fork directory access ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ) + { + FT_Error error; + unsigned char head[16], head2[16]; + FT_Long map_pos, map_len, rdata_len; + int allzeros, allmatch, i; + FT_Long type_list; + + FT_UNUSED( library ); + + + error = FT_Stream_Seek( stream, (FT_ULong)rfork_offset ); + if ( error ) + return error; + + error = FT_Stream_Read( stream, (FT_Byte*)head, 16 ); + if ( error ) + return error; + + /* ensure positive values */ + if ( head[0] >= 0x80 || + head[4] >= 0x80 || + head[8] >= 0x80 || + head[12] >= 0x80 ) + return FT_THROW( Unknown_File_Format ); + + *rdata_pos = ( head[ 0] << 24 ) | + ( head[ 1] << 16 ) | + ( head[ 2] << 8 ) | + head[ 3]; + map_pos = ( head[ 4] << 24 ) | + ( head[ 5] << 16 ) | + ( head[ 6] << 8 ) | + head[ 7]; + rdata_len = ( head[ 8] << 24 ) | + ( head[ 9] << 16 ) | + ( head[10] << 8 ) | + head[11]; + map_len = ( head[12] << 24 ) | + ( head[13] << 16 ) | + ( head[14] << 8 ) | + head[15]; + + /* the map must not be empty */ + if ( !map_pos ) + return FT_THROW( Unknown_File_Format ); + + /* check whether rdata and map overlap */ + if ( *rdata_pos < map_pos ) + { + if ( *rdata_pos > map_pos - rdata_len ) + return FT_THROW( Unknown_File_Format ); + } + else + { + if ( map_pos > *rdata_pos - map_len ) + return FT_THROW( Unknown_File_Format ); + } + + /* check whether end of rdata or map exceeds stream size */ + if ( FT_LONG_MAX - rdata_len < *rdata_pos || + FT_LONG_MAX - map_len < map_pos || + + FT_LONG_MAX - ( *rdata_pos + rdata_len ) < rfork_offset || + FT_LONG_MAX - ( map_pos + map_len ) < rfork_offset || + + (FT_ULong)( rfork_offset + *rdata_pos + rdata_len ) > stream->size || + (FT_ULong)( rfork_offset + map_pos + map_len ) > stream->size ) + return FT_THROW( Unknown_File_Format ); + + *rdata_pos += rfork_offset; + map_pos += rfork_offset; + + error = FT_Stream_Seek( stream, (FT_ULong)map_pos ); + if ( error ) + return error; + + head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ + + error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); + if ( error ) + return error; + + allzeros = 1; + allmatch = 1; + for ( i = 0; i < 16; i++ ) + { + if ( head2[i] != 0 ) + allzeros = 0; + if ( head2[i] != head[i] ) + allmatch = 0; + } + if ( !allzeros && !allmatch ) + return FT_THROW( Unknown_File_Format ); + + /* If we have reached this point then it is probably a mac resource */ + /* file. Now, does it contain any interesting resources? */ + + (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ + + 2 /* skip file resource number */ + + 2 ); /* skip attributes */ + + if ( FT_READ_SHORT( type_list ) ) + return error; + if ( type_list < 0 ) + return FT_THROW( Unknown_File_Format ); + + error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) ); + if ( error ) + return error; + + *map_offset = map_pos + type_list; + return FT_Err_Ok; + } + + + FT_COMPARE_DEF( int ) + ft_raccess_sort_ref_by_id( const void* a, + const void* b ) + { + return ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id; + } + + + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Bool sort_by_res_id, + FT_Long **offsets, + FT_Long *count ) + { + FT_Error error; + int i, j, cnt, subcnt; + FT_Long tag_internal, rpos; + FT_Memory memory = library->memory; + FT_Long temp; + FT_Long *offsets_internal = NULL; + FT_RFork_Ref *ref = NULL; + + + FT_TRACE3(( "\n" )); + error = FT_Stream_Seek( stream, (FT_ULong)map_offset ); + if ( error ) + return error; + + if ( FT_READ_SHORT( cnt ) ) + return error; + cnt++; + + /* `rpos' is a signed 16bit integer offset to resource records; the */ + /* size of a resource record is 12 bytes. The map header is 28 bytes, */ + /* and a type list needs 10 bytes or more. If we assume that the name */ + /* list is empty and we have only a single entry in the type list, */ + /* there can be at most */ + /* */ + /* (32768 - 28 - 10) / 12 = 2727 */ + /* */ + /* resources. */ + /* */ + /* A type list starts with a two-byte counter, followed by 10-byte */ + /* type records. Assuming that there are no resources, the number of */ + /* type records can be at most */ + /* */ + /* (32768 - 28 - 2) / 8 = 4079 */ + /* */ + if ( cnt > 4079 ) + return FT_THROW( Invalid_Table ); + + for ( i = 0; i < cnt; i++ ) + { + if ( FT_READ_LONG( tag_internal ) || + FT_READ_SHORT( subcnt ) || + FT_READ_SHORT( rpos ) ) + return error; + + FT_TRACE2(( "Resource tags: %c%c%c%c\n", + (char)( 0xFF & ( tag_internal >> 24 ) ), + (char)( 0xFF & ( tag_internal >> 16 ) ), + (char)( 0xFF & ( tag_internal >> 8 ) ), + (char)( 0xFF & ( tag_internal >> 0 ) ) )); + FT_TRACE3(( " : subcount=%d, suboffset=0x%04lx\n", + subcnt, rpos )); + + if ( tag_internal == tag ) + { + *count = subcnt + 1; + rpos += map_offset; + + /* a zero count might be valid in the resource specification, */ + /* however, it is completely useless to us */ + if ( *count < 1 || *count > 2727 ) + return FT_THROW( Invalid_Table ); + + error = FT_Stream_Seek( stream, (FT_ULong)rpos ); + if ( error ) + return error; + + if ( FT_QNEW_ARRAY( ref, *count ) ) + return error; + + for ( j = 0; j < *count; j++ ) + { + if ( FT_READ_SHORT( ref[j].res_id ) ) + goto Exit; + if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */ + goto Exit; + if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */ + goto Exit; + if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ + goto Exit; + + /* + * According to Inside Macintosh: More Macintosh Toolbox, + * "Resource IDs" (1-46), there are some reserved IDs. + * However, FreeType2 is not a font synthesizer, no need + * to check the acceptable resource ID. + */ + if ( temp < 0 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + ref[j].offset = temp & 0xFFFFFFL; + + FT_TRACE3(( " [%d]:" + " resource_id=0x%04x, offset=0x%08lx\n", + j, (FT_UShort)ref[j].res_id, ref[j].offset )); + } + + if ( sort_by_res_id ) + { + ft_qsort( ref, + (size_t)*count, + sizeof ( FT_RFork_Ref ), + ft_raccess_sort_ref_by_id ); + + FT_TRACE3(( " -- sort resources by their ids --\n" )); + + for ( j = 0; j < *count; j++ ) + FT_TRACE3(( " [%d]:" + " resource_id=0x%04x, offset=0x%08lx\n", + j, ref[j].res_id, ref[j].offset )); + } + + if ( FT_QNEW_ARRAY( offsets_internal, *count ) ) + goto Exit; + + /* XXX: duplicated reference ID, + * gap between reference IDs are acceptable? + * further investigation on Apple implementation is needed. + */ + for ( j = 0; j < *count; j++ ) + offsets_internal[j] = rdata_pos + ref[j].offset; + + *offsets = offsets_internal; + error = FT_Err_Ok; + + Exit: + FT_FREE( ref ); + return error; + } + } + + return FT_THROW( Cannot_Open_Resource ); + } + + +#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** Guessing functions ****/ + /**** ****/ + /**** When you add a new guessing function, ****/ + /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + + + CONST_FT_RFORK_RULE_ARRAY_BEGIN( ft_raccess_guess_table, + ft_raccess_guess_rec ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_double, apple_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_single, apple_single ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_ufs_export, darwin_ufs_export ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_newvfs, darwin_newvfs ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_hfsplus, darwin_hfsplus ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( vfat, vfat ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_cap, linux_cap ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_double, linux_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_netatalk, linux_netatalk ) + CONST_FT_RFORK_RULE_ARRAY_END + + + /*************************************************************************/ + /**** ****/ + /**** Helper functions ****/ + /**** ****/ + /*************************************************************************/ + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ); + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char* file_name, + FT_Long *result_offset ); + + static char * + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ); + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Int i; + + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + if ( NULL != stream ) + errors[i] = FT_Stream_Seek( stream, 0 ); + else + errors[i] = FT_Err_Ok; + + if ( errors[i] ) + continue; + + errors[i] = ft_raccess_guess_table[i].func( library, + stream, base_name, + &(new_names[i]), + &(offsets[i]) ); + } + + return; + } + + +#if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH ) + static FT_RFork_Rule + raccess_get_rule_type_from_rule_index( FT_Library library, + FT_UInt rule_index ) + { + FT_UNUSED( library ); + + if ( rule_index >= FT_RACCESS_N_RULES ) + return FT_RFork_Rule_invalid; + + return ft_raccess_guess_table[rule_index].type; + } + + + /* + * For this function, refer ftbase.h. + */ + FT_LOCAL_DEF( FT_Bool ) + ft_raccess_rule_by_darwin_vfs( FT_Library library, + FT_UInt rule_index ) + { + switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) + { + case FT_RFork_Rule_darwin_newvfs: + case FT_RFork_Rule_darwin_hfsplus: + return TRUE; + + default: + return FALSE; + } + } +#endif + + + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x07; + + + *result_file_name = NULL; + if ( NULL == stream ) + return FT_THROW( Cannot_Open_Stream ); + + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x00; + + + *result_file_name = NULL; + if ( NULL == stream ) + return FT_THROW( Cannot_Open_Stream ); + + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + + + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, "._" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + /* + Only meaningful on systems with hfs+ drivers (or Macs). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); + + FT_UNUSED( stream ); + + + memory = library->memory; + + if ( base_file_len + 6 > FT_INT_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( newpath, base_file_len + 6 ) ) + return error; + + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + /* + Only meaningful on systems with Mac OS X (> 10.1). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); + + FT_UNUSED( stream ); + + + memory = library->memory; + + if ( base_file_len + 18 > FT_INT_MAX ) + return FT_THROW( Array_Too_Large ); + + if ( FT_QALLOC( newpath, base_file_len + 18 ) ) + return error; + + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + "resource.frk/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + *result_file_name = newpath; + *result_offset = 0; + + return FT_Err_Ok; + } + + + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, "%" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + + FT_UNUSED( stream ); + + + memory = library->memory; + + newpath = raccess_make_file_name( memory, base_file_name, + ".AppleDouble/" ); + if ( !newpath ) + return FT_THROW( Out_Of_Memory ); + + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + + return error; + } + + + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ) + { + FT_Int32 magic_from_stream; + FT_Error error; + FT_Int32 version_number = 0; + FT_UShort n_of_entries; + + int i; + FT_Int32 entry_id, entry_offset, entry_length = 0; + + const FT_Int32 resource_fork_entry_id = 0x2; + + FT_UNUSED( library ); + FT_UNUSED( base_file_name ); + FT_UNUSED( version_number ); + FT_UNUSED( entry_length ); + + + if ( FT_READ_LONG( magic_from_stream ) ) + return error; + if ( magic_from_stream != magic ) + return FT_THROW( Unknown_File_Format ); + + if ( FT_READ_LONG( version_number ) ) + return error; + + /* filler */ + error = FT_Stream_Skip( stream, 16 ); + if ( error ) + return error; + + if ( FT_READ_USHORT( n_of_entries ) ) + return error; + if ( n_of_entries == 0 ) + return FT_THROW( Unknown_File_Format ); + + for ( i = 0; i < n_of_entries; i++ ) + { + if ( FT_READ_LONG( entry_id ) ) + return error; + if ( entry_id == resource_fork_entry_id ) + { + if ( FT_READ_LONG( entry_offset ) || + FT_READ_LONG( entry_length ) ) + continue; + *result_offset = entry_offset; + + return FT_Err_Ok; + } + else + { + error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ + if ( error ) + return error; + } + } + + return FT_THROW( Unknown_File_Format ); + } + + + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char *file_name, + FT_Long *result_offset ) + { + FT_Open_Args args2; + FT_Stream stream2; + char* nouse = NULL; + FT_Error error; + + + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_name; + error = FT_Stream_New( library, &args2, &stream2 ); + if ( error ) + return error; + + error = raccess_guess_apple_double( library, stream2, file_name, + &nouse, result_offset ); + + FT_Stream_Free( stream2, 0 ); + + return error; + } + + + static char* + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ) + { + char* new_name = NULL; + const char* tmp; + const char* slash; + size_t new_length; + FT_Error error; + + + new_length = ft_strlen( original_name ) + ft_strlen( insertion ); + if ( FT_QALLOC( new_name, new_length + 1 ) ) + return NULL; + + tmp = ft_strrchr( original_name, '/' ); + if ( tmp ) + { + ft_strncpy( new_name, + original_name, + (size_t)( tmp - original_name + 1 ) ); + new_name[tmp - original_name + 1] = '\0'; + slash = tmp + 1; + } + else + { + slash = original_name; + new_name[0] = '\0'; + } + + ft_strcat( new_name, insertion ); + ft_strcat( new_name, slash ); + + return new_name; + } + + +#else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + + /************************************************************************** + * Dummy function; just sets errors + */ + + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char *base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Int i; + + FT_UNUSED( library ); + FT_UNUSED( stream ); + FT_UNUSED( base_name ); + + + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + offsets[i] = 0; + errors[i] = FT_ERR( Unimplemented_Feature ); + } + } + + +#endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftsnames.c b/Dependencies/freetype/freetype/src/base/ftsnames.c new file mode 100644 index 00000000..f7231fd6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftsnames.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * ftsnames.c + * + * Simple interface to access SFNT name tables (which are used + * to hold font names, copyright info, notices, etc.) (body). + * + * This is _not_ used to retrieve glyph names! + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_SFNT_NAMES + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + return ( face && FT_IS_SFNT( face ) ) ? ((TT_Face)face)->num_names : 0; + } + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( aname && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( idx < (FT_UInt)ttface->num_names ) + { + TT_Name entry = ttface->name_table.names + idx; + + + /* load name on demand */ + if ( entry->stringLength > 0 && !entry->string ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + + + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + + aname->platform_id = entry->platformID; + aname->encoding_id = entry->encodingID; + aname->language_id = entry->languageID; + aname->name_id = entry->nameID; + aname->string = (FT_Byte*)entry->string; + aname->string_len = entry->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + + /* documentation is in ftsnames.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + + + if ( alangTag && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->name_table.format != 1 ) + return FT_THROW( Invalid_Table ); + + if ( langID > 0x8000U && + langID - 0x8000U < ttface->name_table.numLangTagRecords ) + { + TT_LangTag entry = ttface->name_table.langTags + + ( langID - 0x8000U ); + + + /* load name on demand */ + if ( entry->stringLength > 0 && !entry->string ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + + + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + + alangTag->string = (FT_Byte*)entry->string; + alangTag->string_len = entry->stringLength; + + error = FT_Err_Ok; + } + } + + return error; + } + + +#else /* !TT_CONFIG_OPTION_SFNT_NAMES */ + + + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + FT_UNUSED( face ); + + return 0; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_UNUSED( face ); + FT_UNUSED( idx ); + FT_UNUSED( aname ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_LangTag( FT_Face face, + FT_UInt langID, + FT_SfntLangTag *alangTag ) + { + FT_UNUSED( face ); + FT_UNUSED( langID ); + FT_UNUSED( alangTag ); + + return FT_THROW( Unimplemented_Feature ); + } + + +#endif /* !TT_CONFIG_OPTION_SFNT_NAMES */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftstream.c b/Dependencies/freetype/freetype/src/base/ftstream.c new file mode 100644 index 00000000..66722246 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftstream.c @@ -0,0 +1,872 @@ +/**************************************************************************** + * + * ftstream.c + * + * I/O stream support (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT stream + + + FT_BASE_DEF( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ) + { + stream->base = (FT_Byte*) base; + stream->size = size; + stream->pos = 0; + stream->cursor = NULL; + stream->read = NULL; + stream->close = NULL; + } + + + FT_BASE_DEF( void ) + FT_Stream_Close( FT_Stream stream ) + { + if ( stream && stream->close ) + stream->close( stream ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ) + { + FT_Error error = FT_Err_Ok; + + + if ( stream->read ) + { + if ( stream->read( stream, pos, NULL, 0 ) ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + } + /* note that seeking to the first position after the file is valid */ + else if ( pos > stream->size ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + + if ( !error ) + stream->pos = pos; + + return error; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ) + { + if ( distance < 0 ) + return FT_THROW( Invalid_Stream_Operation ); + + return FT_Stream_Seek( stream, stream->pos + (FT_ULong)distance ); + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_Pos( FT_Stream stream ) + { + return stream->pos; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + if ( pos >= stream->size ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + + return FT_THROW( Invalid_Stream_Operation ); + } + + if ( stream->read ) + read_bytes = stream->read( stream, pos, buffer, count ); + else + { + read_bytes = stream->size - pos; + if ( read_bytes > count ) + read_bytes = count; + + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); + } + + stream->pos = pos + read_bytes; + + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + error = FT_THROW( Invalid_Stream_Operation ); + } + + return error; + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong read_bytes = 0; + + + if ( stream->pos >= stream->size ) + goto Exit; + + if ( stream->read ) + read_bytes = stream->read( stream, stream->pos, buffer, count ); + else + { + read_bytes = stream->size - stream->pos; + if ( read_bytes > count ) + read_bytes = count; + + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); + } + + stream->pos += read_bytes; + + Exit: + return read_bytes; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ) + { + FT_Error error; + + + error = FT_Stream_EnterFrame( stream, count ); + if ( !error ) + { + *pbytes = (FT_Byte*)stream->cursor; + + /* equivalent to FT_Stream_ExitFrame(), with no memory block release */ + stream->cursor = NULL; + stream->limit = NULL; + } + + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ) + { + if ( stream && stream->read ) + { + FT_Memory memory = stream->memory; + + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, *pbytes ); +#else + FT_FREE( *pbytes ); +#endif + } + + *pbytes = NULL; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + + + FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count )); + + /* check for nested frame access */ + FT_ASSERT( stream && stream->cursor == 0 ); + + if ( stream->read ) + { + /* allocate the frame in memory */ + FT_Memory memory = stream->memory; + + + /* simple sanity check */ + if ( count > stream->size ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " frame size (%lu) larger than stream size (%lu)\n", + count, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + +#ifdef FT_DEBUG_MEMORY + /* assume `ft_debug_file_` and `ft_debug_lineno_` are already set */ + stream->base = (unsigned char*)ft_mem_qalloc( memory, + (FT_Long)count, + &error ); + if ( error ) + goto Exit; +#else + if ( FT_QALLOC( stream->base, count ) ) + goto Exit; +#endif + /* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + + FT_FREE( stream->base ); + error = FT_THROW( Invalid_Stream_Operation ); + } + + stream->cursor = stream->base; + stream->limit = FT_OFFSET( stream->cursor, count ); + stream->pos += read_bytes; + } + else + { + /* check current and new position */ + if ( stream->pos >= stream->size || + stream->size - stream->pos < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", + stream->pos, count, stream->size )); + + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + + /* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + + Exit: + return error; + } + + + FT_BASE_DEF( void ) + FT_Stream_ExitFrame( FT_Stream stream ) + { + /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ + /* that it is possible to access a frame of length 0 in */ + /* some weird fonts (usually, when accessing an array of */ + /* 0 records, like in some strange kern tables). */ + /* */ + /* In this case, the loader code handles the 0-length table */ + /* gracefully; however, stream.cursor is really set to 0 by the */ + /* FT_Stream_EnterFrame() call, and this is not an error. */ + + FT_TRACE7(( "FT_Stream_ExitFrame\n" )); + + FT_ASSERT( stream ); + + if ( stream->read ) + { + FT_Memory memory = stream->memory; + + +#ifdef FT_DEBUG_MEMORY + ft_mem_free( memory, stream->base ); + stream->base = NULL; +#else + FT_FREE( stream->base ); +#endif + } + + stream->cursor = NULL; + stream->limit = NULL; + } + + + FT_BASE_DEF( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ) + { + FT_Byte result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + if ( stream->cursor < stream->limit ) + result = *stream->cursor++; + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_GetUShort( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt16 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_GetUShortLE( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt16 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT_LE( p ); + stream->cursor = p; + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetUOffset( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 2 < stream->limit ) + result = FT_NEXT_UOFF3( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetULong( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_GetULongLE( FT_Stream stream ) + { + FT_Byte* p; + FT_UInt32 result; + + + FT_ASSERT( stream && stream->cursor ); + + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG_LE( p ); + stream->cursor = p; + return result; + } + + + FT_BASE_DEF( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, + FT_Error* error ) + { + FT_Byte result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + result = stream->base[stream->pos]; + } + else + goto Fail; + + stream->pos++; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadByte:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p; + FT_UInt16 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_USHORT( p ); + } + else + goto Fail; + + stream->pos += 2; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUShort:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt16 ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p; + FT_UInt16 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_USHORT_LE( p ); + } + else + goto Fail; + + stream->pos += 2; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUShortLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[3]; + FT_Byte* p; + FT_ULong result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 2 < stream->size ) + { + if ( stream->read ) + { + if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_UOFF3( p ); + } + else + goto Fail; + + stream->pos += 3; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadUOffset:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p; + FT_UInt32 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_ULONG( p ); + } + else + goto Fail; + + stream->pos += 4; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadULong:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_UInt32 ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p; + FT_UInt32 result = 0; + + + FT_ASSERT( stream ); + + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + + p = reads; + } + else + p = stream->base + stream->pos; + + if ( p ) + result = FT_NEXT_ULONG_LE( p ); + } + else + goto Fail; + + stream->pos += 4; + + *error = FT_Err_Ok; + + return result; + + Fail: + *error = FT_THROW( Invalid_Stream_Operation ); + FT_ERROR(( "FT_Stream_ReadULongLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + + return result; + } + + + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + FT_Byte* cursor; + + + if ( !fields ) + return FT_THROW( Invalid_Argument ); + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + cursor = stream->cursor; + + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + + + switch ( fields->value ) + { + case ft_frame_start: /* access a new frame */ + error = FT_Stream_EnterFrame( stream, fields->offset ); + if ( error ) + goto Exit; + + frame_accessed = 1; + cursor = stream->cursor; + fields++; + continue; /* loop! */ + + case ft_frame_bytes: /* read a byte sequence */ + case ft_frame_skip: /* skip some bytes */ + { + FT_Offset len = fields->size; + + + if ( len > (FT_Offset)( stream->limit - cursor ) ) + { + error = FT_THROW( Invalid_Stream_Operation ); + goto Exit; + } + + if ( fields->value == ft_frame_bytes ) + { + p = (FT_Byte*)structure + fields->offset; + FT_MEM_COPY( p, cursor, len ); + } + cursor += len; + fields++; + continue; + } + + case ft_frame_byte: + case ft_frame_schar: /* read a single byte */ + value = FT_NEXT_BYTE( cursor ); + sign_shift = 24; + break; + + case ft_frame_short_be: + case ft_frame_ushort_be: /* read a 2-byte big-endian short */ + value = FT_NEXT_USHORT( cursor ); + sign_shift = 16; + break; + + case ft_frame_short_le: + case ft_frame_ushort_le: /* read a 2-byte little-endian short */ + value = FT_NEXT_USHORT_LE( cursor ); + sign_shift = 16; + break; + + case ft_frame_long_be: + case ft_frame_ulong_be: /* read a 4-byte big-endian long */ + value = FT_NEXT_ULONG( cursor ); + sign_shift = 0; + break; + + case ft_frame_long_le: + case ft_frame_ulong_le: /* read a 4-byte little-endian long */ + value = FT_NEXT_ULONG_LE( cursor ); + sign_shift = 0; + break; + + case ft_frame_off3_be: + case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ + value = FT_NEXT_UOFF3( cursor ); + sign_shift = 8; + break; + + case ft_frame_off3_le: + case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ + value = FT_NEXT_UOFF3_LE( cursor ); + sign_shift = 8; + break; + + default: + /* otherwise, exit the loop */ + stream->cursor = cursor; + goto Exit; + } + + /* now, compute the signed value if necessary */ + if ( fields->value & FT_FRAME_OP_SIGNED ) + value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); + + /* finally, store the value in the object */ + + p = (FT_Byte*)structure + fields->offset; + switch ( fields->size ) + { + case ( 8 / FT_CHAR_BIT ): + *(FT_Byte*)p = (FT_Byte)value; + break; + + case ( 16 / FT_CHAR_BIT ): + *(FT_UShort*)p = (FT_UShort)value; + break; + + case ( 32 / FT_CHAR_BIT ): + *(FT_UInt32*)p = (FT_UInt32)value; + break; + + default: /* for 64-bit systems */ + *(FT_ULong*)p = (FT_ULong)value; + } + + /* go to next field */ + fields++; + } + while ( 1 ); + + Exit: + /* close the frame if it was opened by this read */ + if ( frame_accessed ) + FT_Stream_ExitFrame( stream ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftstroke.c b/Dependencies/freetype/freetype/src/base/ftstroke.c new file mode 100644 index 00000000..64f46ce4 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftstroke.c @@ -0,0 +1,2403 @@ +/**************************************************************************** + * + * ftstroke.c + * + * FreeType path stroker (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include + + + /* declare an extern to access `ft_outline_glyph_class' globally */ + /* allocated in `ftglyph.c' */ + FT_CALLBACK_TABLE const FT_Glyph_Class ft_outline_glyph_class; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + + + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT + : FT_STROKER_BORDER_RIGHT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BEZIER COMPUTATIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 ) +#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 8 ) + +#define FT_EPSILON 2 + +#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON ) + + + static FT_Pos + ft_pos_abs( FT_Pos x ) + { + return x >= 0 ? x : -x; + } + + + static void + ft_conic_split( FT_Vector* base ) + { + FT_Pos a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + } + + + static FT_Bool + ft_conic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_out ) + { + FT_Vector d1, d2; + FT_Angle theta; + FT_Int close1, close2; + + + d1.x = base[1].x - base[2].x; + d1.y = base[1].y - base[2].y; + d2.x = base[0].x - base[1].x; + d2.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + + if ( close1 ) + { + if ( close2 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else + { + *angle_in = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + else /* !close1 */ + { + if ( close2 ) + { + *angle_in = + *angle_out = FT_Atan2( d1.x, d1.y ); + } + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + + theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); + + return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); + } + + + static void + ft_cubic_split( FT_Vector* base ) + { + FT_Pos a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + /* Return the average of `angle1' and `angle2'. */ + /* This gives correct result even if `angle1' and `angle2' */ + /* have opposite signs. */ + static FT_Angle + ft_angle_mean( FT_Angle angle1, + FT_Angle angle2 ) + { + return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2; + } + + + static FT_Bool + ft_cubic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_mid, + FT_Angle *angle_out ) + { + FT_Vector d1, d2, d3; + FT_Angle theta1, theta2; + FT_Int close1, close2, close3; + + + d1.x = base[2].x - base[3].x; + d1.y = base[2].y - base[3].y; + d2.x = base[1].x - base[2].x; + d2.y = base[1].y - base[2].y; + d3.x = base[0].x - base[1].x; + d3.y = base[0].y - base[1].y; + + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y ); + + if ( close1 ) + { + if ( close2 ) + { + if ( close3 ) + { + /* basically a point; */ + /* do nothing to retain original direction */ + } + else /* !close3 */ + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } + else /* !close1 */ + { + if ( close2 ) + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d1.x, d1.y ); + } + else /* !close3 */ + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + *angle_mid = ft_angle_mean( *angle_in, *angle_out ); + } + } + else /* !close2 */ + { + if ( close3 ) + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + else /* !close3 */ + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } + + theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); + theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); + + return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && + theta2 < FT_SMALL_CUBIC_THRESHOLD ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKE BORDERS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum FT_StrokeTags_ + { + FT_STROKE_TAG_ON = 1, /* on-curve point */ + FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ + FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ + FT_STROKE_TAG_END = 8 /* sub-path end */ + + } FT_StrokeTags; + +#define FT_STROKE_TAG_BEGIN_END ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END ) + + typedef struct FT_StrokeBorderRec_ + { + FT_UInt num_points; + FT_UInt max_points; + FT_Vector* points; + FT_Byte* tags; + FT_Bool movable; /* TRUE for ends of lineto borders */ + FT_Int start; /* index of current sub-path start point */ + FT_Memory memory; + FT_Bool valid; + + } FT_StrokeBorderRec, *FT_StrokeBorder; + + + static FT_Error + ft_stroke_border_grow( FT_StrokeBorder border, + FT_UInt new_points ) + { + FT_UInt old_max = border->max_points; + FT_UInt new_max = border->num_points + new_points; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + FT_UInt cur_max = old_max; + FT_Memory memory = border->memory; + + + while ( cur_max < new_max ) + cur_max += ( cur_max >> 1 ) + 16; + + if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || + FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) + goto Exit; + + border->max_points = cur_max; + } + + Exit: + return error; + } + + + static void + ft_stroke_border_close( FT_StrokeBorder border, + FT_Bool reverse ) + { + FT_UInt start = (FT_UInt)border->start; + FT_UInt count = border->num_points; + + + FT_ASSERT( border->start >= 0 ); + + /* don't record empty paths! */ + if ( count <= start + 1U ) + border->num_points = start; + else + { + /* copy the last point to the start of this sub-path, since */ + /* it contains the `adjusted' starting coordinates */ + border->num_points = --count; + border->points[start] = border->points[count]; + border->tags[start] = border->tags[count]; + + if ( reverse ) + { + /* reverse the points */ + { + FT_Vector* vec1 = border->points + start + 1; + FT_Vector* vec2 = border->points + count - 1; + + + for ( ; vec1 < vec2; vec1++, vec2-- ) + { + FT_Vector tmp; + + + tmp = *vec1; + *vec1 = *vec2; + *vec2 = tmp; + } + } + + /* then the tags */ + { + FT_Byte* tag1 = border->tags + start + 1; + FT_Byte* tag2 = border->tags + count - 1; + + + for ( ; tag1 < tag2; tag1++, tag2-- ) + { + FT_Byte tmp; + + + tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + } + + border->tags[start ] |= FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= FT_STROKE_TAG_END; + } + + border->start = -1; + border->movable = FALSE; + } + + + static FT_Error + ft_stroke_border_lineto( FT_StrokeBorder border, + FT_Vector* to, + FT_Bool movable ) + { + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( border->start >= 0 ); + + if ( border->movable ) + { + /* move last point */ + border->points[border->num_points - 1] = *to; + } + else + { + /* don't add zero-length lineto, but always add moveto */ + if ( border->num_points > (FT_UInt)border->start && + FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) && + FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) ) + return error; + + /* add one point */ + error = ft_stroke_border_grow( border, 1 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *to; + tag[0] = FT_STROKE_TAG_ON; + + border->num_points += 1; + } + } + border->movable = movable; + return error; + } + + + static FT_Error + ft_stroke_border_conicto( FT_StrokeBorder border, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 2 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control; + vec[1] = *to; + + tag[0] = 0; + tag[1] = FT_STROKE_TAG_ON; + + border->num_points += 2; + } + + border->movable = FALSE; + + return error; + } + + + static FT_Error + ft_stroke_border_cubicto( FT_StrokeBorder border, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error; + + + FT_ASSERT( border->start >= 0 ); + + error = ft_stroke_border_grow( border, 3 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + + tag[0] = FT_STROKE_TAG_CUBIC; + tag[1] = FT_STROKE_TAG_CUBIC; + tag[2] = FT_STROKE_TAG_ON; + + border->num_points += 3; + } + + border->movable = FALSE; + + return error; + } + + +#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 ) + + + static FT_Error + ft_stroke_border_arcto( FT_StrokeBorder border, + FT_Vector* center, + FT_Fixed radius, + FT_Angle angle_start, + FT_Angle angle_diff ) + { + FT_Fixed coef; + FT_Vector a0, a1, a2, a3; + FT_Int i, arcs = 1; + FT_Error error = FT_Err_Ok; + + + /* number of cubic arcs to draw */ + while ( angle_diff > FT_ARC_CUBIC_ANGLE * arcs || + -angle_diff > FT_ARC_CUBIC_ANGLE * arcs ) + arcs++; + + /* control tangents */ + coef = FT_Tan( angle_diff / ( 4 * arcs ) ); + coef += coef / 3; + + /* compute start and first control point */ + FT_Vector_From_Polar( &a0, radius, angle_start ); + a1.x = FT_MulFix( -a0.y, coef ); + a1.y = FT_MulFix( a0.x, coef ); + + a0.x += center->x; + a0.y += center->y; + a1.x += a0.x; + a1.y += a0.y; + + for ( i = 1; i <= arcs; i++ ) + { + /* compute end and second control point */ + FT_Vector_From_Polar( &a3, radius, + angle_start + i * angle_diff / arcs ); + a2.x = FT_MulFix( a3.y, coef ); + a2.y = FT_MulFix( -a3.x, coef ); + + a3.x += center->x; + a3.y += center->y; + a2.x += a3.x; + a2.y += a3.y; + + /* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a1, &a2, &a3 ); + if ( error ) + break; + + /* a0 = a3; */ + a1.x = a3.x - a2.x + a3.x; + a1.y = a3.y - a2.y + a3.y; + } + + return error; + } + + + static FT_Error + ft_stroke_border_moveto( FT_StrokeBorder border, + FT_Vector* to ) + { + /* close current open path if any ? */ + if ( border->start >= 0 ) + ft_stroke_border_close( border, FALSE ); + + border->start = (FT_Int)border->num_points; + border->movable = FALSE; + + return ft_stroke_border_lineto( border, to, FALSE ); + } + + + static void + ft_stroke_border_init( FT_StrokeBorder border, + FT_Memory memory ) + { + border->memory = memory; + border->points = NULL; + border->tags = NULL; + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_reset( FT_StrokeBorder border ) + { + border->num_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static void + ft_stroke_border_done( FT_StrokeBorder border ) + { + FT_Memory memory = border->memory; + + + FT_FREE( border->points ); + FT_FREE( border->tags ); + + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + + + static FT_Error + ft_stroke_border_get_counts( FT_StrokeBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_Error error = FT_Err_Ok; + FT_UInt num_points = 0; + FT_UInt num_contours = 0; + + FT_UInt count = border->num_points; + FT_Vector* point = border->points; + FT_Byte* tags = border->tags; + FT_Int in_contour = 0; + + + for ( ; count > 0; count--, num_points++, point++, tags++ ) + { + if ( tags[0] & FT_STROKE_TAG_BEGIN ) + { + if ( in_contour != 0 ) + goto Fail; + + in_contour = 1; + } + else if ( in_contour == 0 ) + goto Fail; + + if ( tags[0] & FT_STROKE_TAG_END ) + { + in_contour = 0; + num_contours++; + } + } + + if ( in_contour != 0 ) + goto Fail; + + border->valid = TRUE; + + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + + Fail: + num_points = 0; + num_contours = 0; + goto Exit; + } + + + static void + ft_stroke_border_export( FT_StrokeBorder border, + FT_Outline* outline ) + { + /* copy point locations */ + if ( border->num_points ) + FT_ARRAY_COPY( outline->points + outline->n_points, + border->points, + border->num_points ); + + /* copy tags */ + { + FT_UInt count = border->num_points; + FT_Byte* read = border->tags; + FT_Byte* write = outline->tags + outline->n_points; + + + for ( ; count > 0; count--, read++, write++ ) + { + if ( *read & FT_STROKE_TAG_ON ) + *write = FT_CURVE_TAG_ON; + else if ( *read & FT_STROKE_TAG_CUBIC ) + *write = FT_CURVE_TAG_CUBIC; + else + *write = FT_CURVE_TAG_CONIC; + } + } + + /* copy contours */ + { + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_UShort* write = outline->contours + outline->n_contours; + FT_UShort idx = outline->n_points; + + + for ( ; count > 0; count--, tags++, idx++ ) + { + if ( *tags & FT_STROKE_TAG_END ) + { + *write++ = idx; + outline->n_contours++; + } + } + } + + outline->n_points += (FT_UShort)border->num_points; + + FT_ASSERT( FT_Outline_Check( outline ) == 0 ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STROKER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI ) + + typedef struct FT_StrokerRec_ + { + FT_Angle angle_in; /* direction into curr join */ + FT_Angle angle_out; /* direction out of join */ + FT_Vector center; /* current position */ + FT_Fixed line_length; /* length of last lineto */ + FT_Bool first_point; /* is this the start? */ + FT_Bool subpath_open; /* is the subpath open? */ + FT_Angle subpath_angle; /* subpath start direction */ + FT_Vector subpath_start; /* subpath start position */ + FT_Fixed subpath_line_length; /* subpath start lineto len */ + FT_Bool handle_wide_strokes; /* use wide strokes logic? */ + + FT_Stroker_LineCap line_cap; + FT_Stroker_LineJoin line_join; + FT_Stroker_LineJoin line_join_saved; + FT_Fixed miter_limit; + FT_Fixed radius; + + FT_StrokeBorderRec borders[2]; + FT_Library library; + + } FT_StrokerRec; + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ) + { + FT_Error error; /* assigned in FT_NEW */ + FT_Memory memory; + FT_Stroker stroker = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !astroker ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( !FT_NEW( stroker ) ) + { + stroker->library = library; + + ft_stroke_border_init( &stroker->borders[0], memory ); + ft_stroke_border_init( &stroker->borders[1], memory ); + } + + *astroker = stroker; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ) + { + if ( !stroker ) + return; + + stroker->radius = radius; + stroker->line_cap = line_cap; + stroker->line_join = line_join; + stroker->miter_limit = miter_limit; + + /* ensure miter limit has sensible value */ + if ( stroker->miter_limit < 0x10000L ) + stroker->miter_limit = 0x10000L; + + /* save line join style: */ + /* line join style can be temporarily changed when stroking curves */ + stroker->line_join_saved = line_join; + + FT_Stroker_Rewind( stroker ); + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Rewind( FT_Stroker stroker ) + { + if ( stroker ) + { + ft_stroke_border_reset( &stroker->borders[0] ); + ft_stroke_border_reset( &stroker->borders[1] ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Done( FT_Stroker stroker ) + { + if ( stroker ) + { + FT_Memory memory = stroker->library->memory; + + + ft_stroke_border_done( &stroker->borders[0] ); + ft_stroke_border_done( &stroker->borders[1] ); + + stroker->library = NULL; + FT_FREE( stroker ); + } + } + + + /* create a circular arc at a corner or cap */ + static FT_Error + ft_stroker_arcto( FT_Stroker stroker, + FT_Int side ) + { + FT_Angle total, rotate; + FT_Fixed radius = stroker->radius; + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border = stroker->borders + side; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( total == FT_ANGLE_PI ) + total = -rotate * 2; + + error = ft_stroke_border_arcto( border, + &stroker->center, + radius, + stroker->angle_in + rotate, + total ); + border->movable = FALSE; + return error; + } + + + /* add a cap at the end of an opened path */ + static FT_Error + ft_stroker_cap( FT_Stroker stroker, + FT_Angle angle, + FT_Int side ) + { + FT_Error error = FT_Err_Ok; + + + if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) + { + /* add a round cap */ + stroker->angle_in = angle; + stroker->angle_out = angle + FT_ANGLE_PI; + + error = ft_stroker_arcto( stroker, side ); + } + else + { + /* add a square or butt cap */ + FT_Vector middle, delta; + FT_Fixed radius = stroker->radius; + FT_StrokeBorder border = stroker->borders + side; + + + /* compute middle point and first angle point */ + FT_Vector_From_Polar( &middle, radius, angle ); + delta.x = side ? middle.y : -middle.y; + delta.y = side ? -middle.x : middle.x; + + if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + { + middle.x += stroker->center.x; + middle.y += stroker->center.y; + } + else /* FT_STROKER_LINECAP_BUTT */ + { + middle.x = stroker->center.x; + middle.y = stroker->center.y; + } + + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + + Exit: + return error; + } + + + /* process an inside corner, i.e. compute intersection */ + static FT_Error + ft_stroker_inside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Angle phi, theta, rotate; + FT_Fixed length; + FT_Vector sigma = { 0, 0 }; + FT_Vector delta; + FT_Error error = FT_Err_Ok; + FT_Bool intersect; /* use intersection of lines? */ + + + rotate = FT_SIDE_TO_ROTATE( side ); + + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + + /* Only intersect borders if between two lineto's and both */ + /* lines are long enough (line_length is zero for curves). */ + /* Also avoid U-turns of nearly 180 degree. */ + if ( !border->movable || line_length == 0 || + theta > 0x59C000 || theta < -0x59C000 ) + intersect = FALSE; + else + { + /* compute minimum required length of lines */ + FT_Fixed min_length; + + + FT_Vector_Unit( &sigma, theta ); + min_length = + ft_pos_abs( FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); + + intersect = FT_BOOL( min_length && + stroker->line_length >= min_length && + line_length >= min_length ); + } + + if ( !intersect ) + { + FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + } + else + { + /* compute median angle */ + phi = stroker->angle_in + theta + rotate; + + length = FT_DivFix( stroker->radius, sigma.x ); + + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + } + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + + return error; + } + + + /* process an outside corner, i.e. compute bevel/miter/round */ + static FT_Error + ft_stroker_outside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Error error; + FT_Angle rotate; + + + if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) + error = ft_stroker_arcto( stroker, side ); + else + { + /* this is a mitered (pointed) or beveled (truncated) corner */ + FT_Fixed radius = stroker->radius; + FT_Vector sigma = { 0, 0 }; + FT_Angle theta = 0, phi = 0; + FT_Bool bevel, fixed_bevel; + + + rotate = FT_SIDE_TO_ROTATE( side ); + + bevel = + FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL ); + + fixed_bevel = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE ); + + /* check miter limit first */ + if ( !bevel ) + { + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + + if ( theta == FT_ANGLE_PI2 ) + theta = -rotate; + + phi = stroker->angle_in + theta + rotate; + + FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); + + /* is miter limit exceeded? */ + if ( sigma.x < 0x10000L ) + { + /* don't create variable bevels for very small deviations; */ + /* FT_Sin(x) = 0 for x <= 57 */ + if ( fixed_bevel || ft_pos_abs( theta ) > 57 ) + bevel = TRUE; + } + } + + if ( bevel ) /* this is a bevel (broken angle) */ + { + if ( fixed_bevel ) + { + /* the outer corners are simply joined together */ + FT_Vector delta; + + + /* add bevel */ + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else /* variable bevel or clipped miter */ + { + /* the miter is truncated */ + FT_Vector middle, delta; + FT_Fixed coef; + + + /* compute middle point and first angle point */ + FT_Vector_From_Polar( &middle, + FT_MulFix( radius, stroker->miter_limit ), + phi ); + + coef = FT_DivFix( 0x10000L - sigma.x, sigma.y ); + delta.x = FT_MulFix( middle.y, coef ); + delta.y = FT_MulFix( -middle.x, coef ); + + middle.x += stroker->center.x; + middle.y += stroker->center.y; + delta.x += middle.x; + delta.y += middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* finally, add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + else /* this is a miter (intersection) */ + { + FT_Fixed length; + FT_Vector delta; + + + length = FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); + + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* now add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + + Exit: + return error; + } + + + static FT_Error + ft_stroker_process_corner( FT_Stroker stroker, + FT_Fixed line_length ) + { + FT_Error error = FT_Err_Ok; + FT_Angle turn; + FT_Int inside_side; + + + turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + + /* no specific corner processing is required if the turn is 0 */ + if ( turn == 0 ) + goto Exit; + + /* when we turn to the right, the inside side is 0 */ + /* otherwise, the inside side is 1 */ + inside_side = ( turn < 0 ); + + /* process the inside side */ + error = ft_stroker_inside( stroker, inside_side, line_length ); + if ( error ) + goto Exit; + + /* process the outside side */ + error = ft_stroker_outside( stroker, !inside_side, line_length ); + + Exit: + return error; + } + + + /* add two points to the left and right borders corresponding to the */ + /* start of the subpath */ + static FT_Error + ft_stroker_subpath_start( FT_Stroker stroker, + FT_Angle start_angle, + FT_Fixed line_length ) + { + FT_Vector delta; + FT_Vector point; + FT_Error error; + FT_StrokeBorder border; + + + FT_Vector_From_Polar( &delta, stroker->radius, + start_angle + FT_ANGLE_PI2 ); + + point.x = stroker->center.x + delta.x; + point.y = stroker->center.y + delta.y; + + border = stroker->borders; + error = ft_stroke_border_moveto( border, &point ); + if ( error ) + goto Exit; + + point.x = stroker->center.x - delta.x; + point.y = stroker->center.y - delta.y; + + border++; + error = ft_stroke_border_moveto( border, &point ); + + /* save angle, position, and line length for last join */ + /* (line_length is zero for curves) */ + stroker->subpath_angle = start_angle; + stroker->first_point = FALSE; + stroker->subpath_line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border; + FT_Vector delta; + FT_Angle angle; + FT_Int side; + FT_Fixed line_length; + + + if ( !stroker || !to ) + return FT_THROW( Invalid_Argument ); + + delta.x = to->x - stroker->center.x; + delta.y = to->y - stroker->center.y; + + /* a zero-length lineto is a no-op; avoid creating a spurious corner */ + if ( delta.x == 0 && delta.y == 0 ) + goto Exit; + + /* compute length of line */ + line_length = FT_Vector_Length( &delta ); + + angle = FT_Atan2( delta.x, delta.y ); + FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); + + /* process corner if necessary */ + if ( stroker->first_point ) + { + /* This is the first segment of a subpath. We need to */ + /* add a point to each border at their respective starting */ + /* point locations. */ + error = ft_stroker_subpath_start( stroker, angle, line_length ); + if ( error ) + goto Exit; + } + else + { + /* process the current corner */ + stroker->angle_out = angle; + error = ft_stroker_process_corner( stroker, line_length ); + if ( error ) + goto Exit; + } + + /* now add a line segment to both the `inside' and `outside' paths */ + for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) + { + FT_Vector point; + + + point.x = to->x + delta.x; + point.y = to->y + delta.y; + + /* the ends of lineto borders are movable */ + error = ft_stroke_border_lineto( border, &point, TRUE ); + if ( error ) + goto Exit; + + delta.x = -delta.x; + delta.y = -delta.y; + } + + stroker->angle_in = angle; + stroker->center = *to; + stroker->line_length = line_length; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[34]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 30; + FT_Bool first_arc = TRUE; + + + if ( !stroker || !control || !to ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control->x ) && + FT_IS_SMALL( stroker->center.y - control->y ) && + FT_IS_SMALL( control->x - to->x ) && + FT_IS_SMALL( control->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control; + arc[2] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = stroker->angle_in; + + if ( arc < limit && + !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_conic_split( arc ); + arc += 2; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CONIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[2]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl, end; + FT_Angle theta, phi, rotate, alpha0 = 0; + FT_Fixed length; + FT_StrokeBorder border; + FT_Int side; + + + theta = FT_Angle_Diff( angle_in, angle_out ) / 2; + phi = angle_in + theta; + length = FT_DivFix( stroker->radius, FT_Cos( theta ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control point */ + FT_Vector_From_Polar( &ctrl, length, phi + rotate ); + ctrl.x += arc[1].x; + ctrl.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + + alen = FT_MulDiv( blen, sinA, sinB ); + + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_conicto( border, &ctrl, &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_conicto( border, &ctrl, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 2; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + stroker->line_length = 0; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[37]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 32; + FT_Bool first_arc = TRUE; + + + if ( !stroker || !control1 || !control2 || !to ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* if all control points are coincident, this is a no-op; */ + /* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control1->x ) && + FT_IS_SMALL( stroker->center.y - control1->y ) && + FT_IS_SMALL( control1->x - control2->x ) && + FT_IS_SMALL( control1->y - control2->y ) && + FT_IS_SMALL( control2->x - to->x ) && + FT_IS_SMALL( control2->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + + arc = bez_stack; + arc[0] = *to; + arc[1] = *control2; + arc[2] = *control1; + arc[3] = stroker->center; + + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_mid, angle_out; + + + /* initialize with current direction */ + angle_in = angle_out = angle_mid = stroker->angle_in; + + if ( arc < limit && + !ft_cubic_is_small_enough( arc, &angle_in, + &angle_mid, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + + ft_cubic_split( arc ); + arc += 3; + continue; + } + + if ( first_arc ) + { + first_arc = FALSE; + + /* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CUBIC_THRESHOLD / 4 ) + { + /* if the deviation from one arc to the next is too great, */ + /* add a round corner */ + stroker->center = arc[3]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + + error = ft_stroker_process_corner( stroker, 0 ); + + /* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + + if ( error ) + goto Exit; + + /* the arc's angle is small enough; we can add it directly to each */ + /* border */ + { + FT_Vector ctrl1, ctrl2, end; + FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; + FT_Fixed length1, length2; + FT_StrokeBorder border; + FT_Int side; + + + theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2; + theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2; + phi1 = ft_angle_mean( angle_in, angle_mid ); + phi2 = ft_angle_mean( angle_mid, angle_out ); + length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) ); + length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) ); + + /* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y ); + + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); + + /* compute control points */ + FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); + ctrl1.x += arc[2].x; + ctrl1.y += arc[2].y; + + FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); + ctrl2.x += arc[1].x; + ctrl2.y += arc[1].y; + + /* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; + + + /* determine whether the border radius is greater than the */ + /* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); + + /* is the direction of the border arc opposite to */ + /* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; + + + /* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + + blen = FT_Vector_Length( &bvec ); + + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + + alen = FT_MulDiv( blen, sinA, sinB ); + + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; + + /* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_cubicto( border, + &ctrl2, + &ctrl1, + &start ); + if ( error ) + goto Exit; + /* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + + continue; + } + + /* else fall through */ + } + + /* simply add an arc */ + error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end ); + if ( error ) + goto Exit; + } + } + + arc -= 3; + + stroker->angle_in = angle_out; + } + + stroker->center = *to; + stroker->line_length = 0; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ) + { + if ( !stroker || !to ) + return FT_THROW( Invalid_Argument ); + + /* We cannot process the first point, because there is not enough */ + /* information regarding its corner/cap. The latter will be processed */ + /* in the `FT_Stroker_EndSubPath' routine. */ + /* */ + stroker->first_point = TRUE; + stroker->center = *to; + stroker->subpath_open = open; + + /* Determine if we need to check whether the border radius is greater */ + /* than the radius of curvature of a curve, to handle this case */ + /* specially. This is only required if bevel joins or butt caps may */ + /* be created, because round & miter joins and round & square caps */ + /* cover the negative sector created with wide strokes. */ + stroker->handle_wide_strokes = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND || + ( stroker->subpath_open && + stroker->line_cap == FT_STROKER_LINECAP_BUTT ) ); + + /* record the subpath start point for each border */ + stroker->subpath_start = *to; + + stroker->angle_in = 0; + + return FT_Err_Ok; + } + + + static FT_Error + ft_stroker_add_reverse_left( FT_Stroker stroker, + FT_Bool open ) + { + FT_StrokeBorder right = stroker->borders + 0; + FT_StrokeBorder left = stroker->borders + 1; + FT_Int new_points; + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( left->start >= 0 ); + + new_points = (FT_Int)left->num_points - left->start; + if ( new_points > 0 ) + { + error = ft_stroke_border_grow( right, (FT_UInt)new_points ); + if ( error ) + goto Exit; + + { + FT_Vector* dst_point = right->points + right->num_points; + FT_Byte* dst_tag = right->tags + right->num_points; + FT_Vector* src_point = left->points + left->num_points - 1; + FT_Byte* src_tag = left->tags + left->num_points - 1; + + + while ( src_point >= left->points + left->start ) + { + *dst_point = *src_point; + *dst_tag = *src_tag; + + if ( open ) + dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END; + else + { + FT_Byte ttag = + (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END ); + + + /* switch begin/end tags if necessary */ + if ( ttag == FT_STROKE_TAG_BEGIN || + ttag == FT_STROKE_TAG_END ) + dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END; + } + + src_point--; + src_tag--; + dst_point++; + dst_tag++; + } + } + + left->num_points = (FT_UInt)left->start; + right->num_points += (FT_UInt)new_points; + + right->movable = FALSE; + left->movable = FALSE; + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + /* there's a lot of magic in this function! */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ) + { + FT_Error error = FT_Err_Ok; + + + if ( !stroker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( stroker->subpath_open ) + { + FT_StrokeBorder right = stroker->borders; + + + /* All right, this is an opened path, we need to add a cap between */ + /* right & left, add the reverse of left, then add a final cap */ + /* between left & right. */ + error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); + if ( error ) + goto Exit; + + /* add reversed points from `left' to `right' */ + error = ft_stroker_add_reverse_left( stroker, TRUE ); + if ( error ) + goto Exit; + + /* now add the final cap */ + stroker->center = stroker->subpath_start; + error = ft_stroker_cap( stroker, + stroker->subpath_angle + FT_ANGLE_PI, 0 ); + if ( error ) + goto Exit; + + /* Now end the right subpath accordingly. The left one is */ + /* rewind and doesn't need further processing. */ + ft_stroke_border_close( right, FALSE ); + } + else + { + /* close the path if needed */ + if ( !FT_IS_SMALL( stroker->center.x - stroker->subpath_start.x ) || + !FT_IS_SMALL( stroker->center.y - stroker->subpath_start.y ) ) + { + error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); + if ( error ) + goto Exit; + } + + /* process the corner */ + stroker->angle_out = stroker->subpath_angle; + + error = ft_stroker_process_corner( stroker, + stroker->subpath_line_length ); + if ( error ) + goto Exit; + + /* then end our two subpaths */ + ft_stroke_border_close( stroker->borders + 0, FALSE ); + ft_stroke_border_close( stroker->borders + 1, TRUE ); + } + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt num_points = 0, num_contours = 0; + FT_Error error; + + + if ( !stroker || border > 1 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt count1, count2, num_points = 0; + FT_UInt count3, count4, num_contours = 0; + FT_Error error; + + + if ( !stroker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + 0, + &count1, &count2 ); + if ( error ) + goto Exit; + + error = ft_stroke_border_get_counts( stroker->borders + 1, + &count3, &count4 ); + if ( error ) + goto Exit; + + num_points = count1 + count3; + num_contours = count2 + count4; + + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ) + { + if ( !stroker || !outline ) + return; + + if ( border == FT_STROKER_BORDER_LEFT || + border == FT_STROKER_BORDER_RIGHT ) + { + FT_StrokeBorder sborder = & stroker->borders[border]; + + + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); + } + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ) + { + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); + } + + + /* documentation is in ftstroke.h */ + + /* + * The following is very similar to FT_Outline_Decompose, except + * that we do support opened paths, and do not scale the outline. + */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + FT_Byte* tags; + + FT_Error error; + + FT_Int n; /* index of contour in outline */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + + FT_Int tag; /* current point's state */ + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !stroker ) + return FT_THROW( Invalid_Argument ); + + FT_Stroker_Rewind( stroker ); + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + first = last + 1; + last = outline->contours[n]; + + /* skip empty points; we don't stroke these */ + if ( last <= first ) + continue; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* First point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + } + point--; + tags--; + } + + error = FT_Stroker_BeginSubPath( stroker, &v_start, opened ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = point->x; + vec.y = point->y; + + error = FT_Stroker_LineTo( stroker, &vec ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = point->x; + v_control.y = point->y; + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec = point[0]; + + if ( tag == FT_CURVE_TAG_ON ) + { + error = FT_Stroker_ConicTo( stroker, &v_control, &vec ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = FT_Stroker_ConicTo( stroker, &v_control, &v_start ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1 = point[-2]; + vec2 = point[-1]; + + if ( point <= limit ) + { + FT_Vector vec; + + + vec = point[0]; + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); + if ( error ) + goto Exit; + continue; + } + + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); + goto Close; + } + } + } + + Close: + if ( error ) + goto Exit; + + /* don't try to end the path if no segments have been generated */ + if ( !stroker->first_point ) + { + error = FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; + } + } + + return FT_Err_Ok; + + Exit: + return error; + + Invalid_Outline: + return FT_THROW( Invalid_Outline ); + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Glyph glyph = NULL; + + + if ( !pglyph ) + goto Exit; + + glyph = *pglyph; + if ( !glyph || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + + FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, + (FT_Int)num_contours, + outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_Export( stroker, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + + /* documentation is in ftstroke.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FT_Glyph glyph = NULL; + + + if ( !pglyph ) + goto Exit; + + glyph = *pglyph; + if ( !glyph || glyph->clazz != &ft_outline_glyph_class ) + goto Exit; + + { + FT_Glyph copy; + + + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + + glyph = copy; + } + + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_StrokerBorder border; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + + + border = FT_Outline_GetOutsideBorder( outline ); + if ( inside ) + { + if ( border == FT_STROKER_BORDER_LEFT ) + border = FT_STROKER_BORDER_RIGHT; + else + border = FT_STROKER_BORDER_LEFT; + } + + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + + FT_Stroker_GetBorderCounts( stroker, border, + &num_points, &num_contours ); + + FT_Outline_Done( glyph->library, outline ); + + error = FT_Outline_New( glyph->library, + num_points, + (FT_Int)num_contours, + outline ); + if ( error ) + goto Fail; + + outline->n_points = 0; + outline->n_contours = 0; + + FT_Stroker_ExportBorder( stroker, border, outline ); + } + + if ( destroy ) + FT_Done_Glyph( *pglyph ); + + *pglyph = glyph; + goto Exit; + + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + + if ( !destroy ) + *pglyph = NULL; + + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftsynth.c b/Dependencies/freetype/freetype/src/base/ftsynth.c new file mode 100644 index 00000000..ec05bce3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftsynth.c @@ -0,0 +1,180 @@ +/**************************************************************************** + * + * ftsynth.c + * + * FreeType synthesizing code for emboldening and slanting (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT synth + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL OBLIQUING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ) + { + /* Value '0x0366A' corresponds to a shear angle of about 12 degrees. */ + FT_GlyphSlot_Slant( slot, 0x0366A, 0 ); + } + + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ) + { + FT_Matrix transform; + FT_Outline* outline; + + + if ( !slot ) + return; + + outline = &slot->outline; + + /* only oblique outline glyphs */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return; + + /* we don't touch the advance width */ + + /* For italic, simply apply a shear transform */ + transform.xx = 0x10000L; + transform.yx = -yslant; + + transform.xy = xslant; + transform.yy = 0x10000L; + + FT_Outline_Transform( outline, &transform ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** EXPERIMENTAL EMBOLDENING SUPPORT ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ) + { + FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA ); + } + + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ) + { + FT_Library library; + FT_Size size; + FT_Error error; + FT_Pos xstr, ystr; + + + if ( !slot ) + return; + + library = slot->library; + size = slot->face->size; + + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && + slot->format != FT_GLYPH_FORMAT_BITMAP ) + return; + + /* express deltas in pixels in 26.6 format */ + xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024; + ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); + + else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ + { + /* round to full pixels */ + xstr &= ~63; + if ( xstr == 0 ) + xstr = 1 << 6; + ystr &= ~63; + + /* + * XXX: overflow check for 16-bit system, for compatibility + * with FT_GlyphSlot_Embolden() since FreeType 2.1.10. + * unfortunately, this function return no informations + * about the cause of error. + */ + if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN ) + { + FT_TRACE1(( "FT_GlyphSlot_Embolden:" )); + FT_TRACE1(( "too strong emboldening parameter ystr=%ld\n", ystr )); + return; + } + error = FT_GlyphSlot_Own_Bitmap( slot ); + if ( error ) + return; + + error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + if ( error ) + return; + } + + if ( slot->advance.x ) + slot->advance.x += xstr; + + if ( slot->advance.y ) + slot->advance.y += ystr; + + slot->metrics.width += xstr; + slot->metrics.height += ystr; + slot->metrics.horiAdvance += xstr; + slot->metrics.vertAdvance += ystr; + slot->metrics.horiBearingY += ystr; + + /* XXX: 16-bit overflow case must be excluded before here */ + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + slot->bitmap_top += (FT_Int)( ystr >> 6 ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftsystem.c b/Dependencies/freetype/freetype/src/base/ftsystem.c new file mode 100644 index 00000000..eee36423 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftsystem.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * ftsystem.c + * + * ANSI-specific FreeType low-level system interface (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file contains the default interface used by FreeType to access + * low-level, i.e. memory management, i/o access as well as thread + * synchronisation. It can be replaced by user-specific routines if + * necessary. + * + */ + + +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * MEMORY MANAGEMENT INTERFACE + * + */ + + /************************************************************************** + * + * It is not necessary to do any error checking for the + * allocation-related functions. This will be done by the higher level + * routines like ft_mem_alloc() or ft_mem_realloc(). + * + */ + + + /************************************************************************** + * + * @Function: + * ft_alloc + * + * @Description: + * The memory allocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * size :: + * The requested size in bytes. + * + * @Return: + * The address of newly allocated block. + */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + + return ft_smalloc( (size_t)size ); + } + + + /************************************************************************** + * + * @Function: + * ft_realloc + * + * @Description: + * The memory reallocation function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * cur_size :: + * The current size of the allocated memory block. + * + * new_size :: + * The newly requested size in bytes. + * + * block :: + * The current address of the block in memory. + * + * @Return: + * The address of the reallocated memory block. + */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + + return ft_srealloc( block, (size_t)new_size ); + } + + + /************************************************************************** + * + * @Function: + * ft_free + * + * @Description: + * The memory release function. + * + * @Input: + * memory :: + * A pointer to the memory object. + * + * block :: + * The address of block in memory to be freed. + */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + + ft_sfree( block ); + } + + + /************************************************************************** + * + * RESOURCE MANAGEMENT INTERFACE + * + */ + +#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT io + + /* We use the macro STREAM_FILE for convenience to extract the */ + /* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) + + + /************************************************************************** + * + * @Function: + * ft_ansi_stream_close + * + * @Description: + * The function to close a stream. + * + * @Input: + * stream :: + * A pointer to the stream object. + */ + FT_CALLBACK_DEF( void ) + ft_ansi_stream_close( FT_Stream stream ) + { + ft_fclose( STREAM_FILE( stream ) ); + + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_ansi_stream_io + * + * @Description: + * The function to open a stream. + * + * @Input: + * stream :: + * A pointer to the stream object. + * + * offset :: + * The position in the data stream to start reading. + * + * buffer :: + * The address of buffer to store the read data. + * + * count :: + * The number of bytes to read from the stream. + * + * @Return: + * The number of bytes actually read. If `count' is zero (that is, + * the function is used for seeking), a non-zero return value + * indicates an error. + */ + FT_CALLBACK_DEF( unsigned long ) + ft_ansi_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_FILE* file; + + + if ( offset > stream->size && !count ) + return 1; + + file = STREAM_FILE( stream ); + + if ( stream->pos != offset ) + ft_fseek( file, (long)offset, SEEK_SET ); + + /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */ + /* which is undefined behaviour. */ + if ( !count ) + return 0; + + return (unsigned long)ft_fread( buffer, 1, count, file ); + } + + + /* documentation is in ftstream.h */ + + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + FT_FILE* file; + + + if ( !stream ) + return FT_THROW( Invalid_Stream_Handle ); + + stream->descriptor.pointer = NULL; + stream->pathname.pointer = (char*)filepathname; + stream->base = NULL; + stream->pos = 0; + stream->read = NULL; + stream->close = NULL; + + file = ft_fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_Stream_Open:" + " could not open `%s'\n", filepathname )); + + return FT_THROW( Cannot_Open_Resource ); + } + + ft_fseek( file, 0, SEEK_END ); + stream->size = (unsigned long)ft_ftell( file ); + if ( !stream->size ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); + ft_fclose( file ); + return FT_THROW( Cannot_Open_Stream ); + } + ft_fseek( file, 0, SEEK_SET ); + + stream->descriptor.pointer = file; + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + filepathname, stream->size )); + + return FT_Err_Ok; + } + +#endif /* !FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + +#ifdef FT_DEBUG_MEMORY + + extern FT_Int + ft_mem_debug_init( FT_Memory memory ); + + extern void + ft_mem_debug_done( FT_Memory memory ); + +#endif + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + + + memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = NULL; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_init( memory ); +#endif + } + + return memory; + } + + + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { +#ifdef FT_DEBUG_MEMORY + ft_mem_debug_done( memory ); +#endif + ft_sfree( memory ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/fttrigon.c b/Dependencies/freetype/freetype/src/base/fttrigon.c new file mode 100644 index 00000000..4b1aced1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/fttrigon.c @@ -0,0 +1,517 @@ +/**************************************************************************** + * + * fttrigon.c + * + * FreeType trigonometric functions (body). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This is a fixed-point CORDIC implementation of trigonometric + * functions as well as transformations between Cartesian and polar + * coordinates. The angles are represented as 16.16 fixed-point values + * in degrees, i.e., the angular resolution is 2^-16 degrees. Note that + * only vectors longer than 2^16*180/pi (or at least 22 bits) on a + * discrete Cartesian grid can have the same or better angular + * resolution. Therefore, to maintain this precision, some functions + * require an interim upscaling of the vectors, whereas others operate + * with 24-bit long vectors directly. + * + */ + +#include +#include +#include + + + /* the Cordic shrink factor 0.858785336480436 * 2^32 */ +#define FT_TRIG_SCALE 0xDBD95B16UL + + /* the highest bit in overflow-safe vector components, */ + /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ +#define FT_TRIG_SAFE_MSB 29 + + /* this table was generated for FT_PI = 180L << 16, i.e. degrees */ +#define FT_TRIG_MAX_ITERS 23 + + static const FT_Angle + ft_trig_arctan_table[] = + { + 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, + 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L + }; + + +#ifdef FT_INT64 + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Int s = 1; + + + if ( val < 0 ) + { + val = -val; + s = -1; + } + + /* 0x40000000 comes from regression analysis between true */ + /* and CORDIC hypotenuse, so it minimizes the error */ + val = (FT_Fixed)( + ( (FT_UInt64)val * FT_TRIG_SCALE + 0x40000000UL ) >> 32 ); + + return s < 0 ? -val : val; + } + +#else /* !FT_INT64 */ + + /* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Int s = 1; + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + if ( val < 0 ) + { + val = -val; + s = -1; + } + + lo1 = (FT_UInt32)val & 0x0000FFFFU; + hi1 = (FT_UInt32)val >> 16; + lo2 = FT_TRIG_SCALE & 0x0000FFFFU; + hi2 = FT_TRIG_SCALE >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + /* 0x40000000 comes from regression analysis between true */ + /* and CORDIC hypotenuse, so it minimizes the error */ + + /* Check carry overflow of lo + 0x40000000 */ + lo += 0x40000000UL; + hi += ( lo < 0x40000000UL ); + + val = (FT_Fixed)hi; + + return s < 0 ? -val : val; + } + +#endif /* !FT_INT64 */ + + + /* undefined and never called for zero vector */ + static FT_Int + ft_trig_prenorm( FT_Vector* vec ) + { + FT_Pos x, y; + FT_Int shift; + + + x = vec->x; + y = vec->y; + + shift = FT_MSB( (FT_UInt32)( FT_ABS( x ) | FT_ABS( y ) ) ); + + if ( shift <= FT_TRIG_SAFE_MSB ) + { + shift = FT_TRIG_SAFE_MSB - shift; + vec->x = (FT_Pos)( (FT_ULong)x << shift ); + vec->y = (FT_Pos)( (FT_ULong)y << shift ); + } + else + { + shift -= FT_TRIG_SAFE_MSB; + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } + + return shift; + } + + + static void + ft_trig_pseudo_rotate( FT_Vector* vec, + FT_Angle theta ) + { + FT_Int i; + FT_Fixed x, y, xtemp, b; + const FT_Angle *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Rotate inside [-PI/4,PI/4] sector */ + while ( theta < -FT_ANGLE_PI4 ) + { + xtemp = y; + y = -x; + x = xtemp; + theta += FT_ANGLE_PI2; + } + + while ( theta > FT_ANGLE_PI4 ) + { + xtemp = -y; + y = x; + x = xtemp; + theta -= FT_ANGLE_PI2; + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( theta < 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + vec->x = x; + vec->y = y; + } + + + static void + ft_trig_pseudo_polarize( FT_Vector* vec ) + { + FT_Angle theta; + FT_Int i; + FT_Fixed x, y, xtemp, b; + const FT_Angle *arctanptr; + + + x = vec->x; + y = vec->y; + + /* Get the vector into [-PI/4,PI/4] sector */ + if ( y > x ) + { + if ( y > -x ) + { + theta = FT_ANGLE_PI2; + xtemp = y; + y = -x; + x = xtemp; + } + else + { + theta = y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI; + x = -x; + y = -y; + } + } + else + { + if ( y < -x ) + { + theta = -FT_ANGLE_PI2; + xtemp = -y; + y = x; + x = xtemp; + } + else + { + theta = 0; + } + } + + arctanptr = ft_trig_arctan_table; + + /* Pseudorotations, with right shifts */ + for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) + { + if ( y > 0 ) + { + xtemp = x + ( ( y + b ) >> i ); + y = y - ( ( x + b ) >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( ( y + b ) >> i ); + y = y + ( ( x + b ) >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } + + /* round theta to acknowledge its error that mostly comes */ + /* from accumulated rounding errors in the arctan table */ + if ( theta >= 0 ) + theta = FT_PAD_ROUND( theta, 16 ); + else + theta = -FT_PAD_ROUND( -theta, 16 ); + + vec->x = x; + vec->y = theta; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Cos( FT_Angle angle ) + { + FT_Vector v; + + + FT_Vector_Unit( &v, angle ); + + return v.x; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Sin( FT_Angle angle ) + { + FT_Vector v; + + + FT_Vector_Unit( &v, angle ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Tan( FT_Angle angle ) + { + FT_Vector v = { 1 << 24, 0 }; + + + ft_trig_pseudo_rotate( &v, angle ); + + return FT_DivFix( v.y, v.x ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Atan2( FT_Fixed dx, + FT_Fixed dy ) + { + FT_Vector v; + + + if ( dx == 0 && dy == 0 ) + return 0; + + v.x = dx; + v.y = dy; + ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + return v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ) + { + if ( !vec ) + return; + + vec->x = FT_TRIG_SCALE >> 8; + vec->y = 0; + ft_trig_pseudo_rotate( vec, angle ); + vec->x = ( vec->x + 0x80L ) >> 8; + vec->y = ( vec->y + 0x80L ) >> 8; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec || !angle ) + return; + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); + + if ( shift > 0 ) + { + FT_Int32 half = (FT_Int32)1L << ( shift - 1 ); + + + vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift; + vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift; + } + else + { + shift = -shift; + vec->x = (FT_Pos)( (FT_ULong)v.x << shift ); + vec->y = (FT_Pos)( (FT_ULong)v.y << shift ); + } + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec ) + return 0; + + v = *vec; + + /* handle trivial cases */ + if ( v.x == 0 ) + { + return FT_ABS( v.y ); + } + else if ( v.y == 0 ) + { + return FT_ABS( v.x ); + } + + /* general case */ + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + if ( shift > 0 ) + return ( v.x + ( 1L << ( shift - 1 ) ) ) >> shift; + + return (FT_Fixed)( (FT_UInt32)v.x << -shift ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ) + { + FT_Int shift; + FT_Vector v; + + + if ( !vec || !length || !angle ) + return; + + v = *vec; + + if ( v.x == 0 && v.y == 0 ) + return; + + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + + v.x = ft_trig_downscale( v.x ); + + *length = shift >= 0 ? ( v.x >> shift ) + : (FT_Fixed)( (FT_UInt32)v.x << -shift ); + *angle = v.y; + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ) + { + if ( !vec ) + return; + + vec->x = length; + vec->y = 0; + + FT_Vector_Rotate( vec, angle ); + } + + + /* documentation is in fttrigon.h */ + + FT_EXPORT_DEF( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ) + { + FT_Angle delta = angle2 - angle1; + + + while ( delta <= -FT_ANGLE_PI ) + delta += FT_ANGLE_2PI; + + while ( delta > FT_ANGLE_PI ) + delta -= FT_ANGLE_2PI; + + return delta; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/fttype1.c b/Dependencies/freetype/freetype/src/base/fttype1.c new file mode 100644 index 00000000..cedf7c40 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/fttype1.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * fttype1.c + * + * FreeType utility file for PS names support (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + FT_Error error; + FT_Service_PsInfo service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !afont_info ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_info ) + error = service->ps_get_font_info( face, afont_info ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ) + { + FT_Int result = 0; + FT_Service_PsInfo service; + + + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_has_glyph_names ) + result = service->ps_has_glyph_names( face ); + } + + return result; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec* afont_private ) + { + FT_Error error; + FT_Service_PsInfo service; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !afont_private ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_private ) + error = service->ps_get_font_private( face, afont_private ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + + /* documentation is in t1tables.h */ + + FT_EXPORT_DEF( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ) + { + FT_Int result = 0; + FT_Service_PsInfo service = NULL; + + + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + + if ( service && service->ps_get_font_value ) + result = service->ps_get_font_value( face, key, idx, + value, value_len ); + } + + return result; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftutil.c b/Dependencies/freetype/freetype/src/base/ftutil.c new file mode 100644 index 00000000..b13512f8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftutil.c @@ -0,0 +1,442 @@ +/**************************************************************************** + * + * ftutil.c + * + * FreeType utility file for memory and list management (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT memory + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** M E M O R Y M A N A G E M E N T *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer block = ft_mem_qalloc( memory, size, &error ); + + if ( !error && block && size > 0 ) + FT_MEM_ZERO( block, size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + FT_Pointer block = NULL; + + + if ( size > 0 ) + { + block = memory->alloc( memory, size ); + if ( !block ) + error = FT_THROW( Out_Of_Memory ); + } + else if ( size < 0 ) + { + /* may help catch/prevent security issues */ + error = FT_THROW( Invalid_Argument ); + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + + block = ft_mem_qrealloc( memory, item_size, + cur_count, new_count, block, &error ); + if ( !error && block && new_count > cur_count ) + FT_MEM_ZERO( (char*)block + cur_count * item_size, + ( new_count - cur_count ) * item_size ); + + *p_error = error; + return block; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + + + /* Note that we now accept `item_size == 0' as a valid parameter, in + * order to cover very weird cases where an ALLOC_MULT macro would be + * called. + */ + if ( cur_count < 0 || new_count < 0 || item_size < 0 ) + { + /* may help catch/prevent nasty security issues */ + error = FT_THROW( Invalid_Argument ); + } + else if ( new_count == 0 || item_size == 0 ) + { + ft_mem_free( memory, block ); + block = NULL; + } + else if ( new_count > FT_INT_MAX / item_size ) + { + error = FT_THROW( Array_Too_Large ); + } + else if ( cur_count == 0 ) + { + FT_ASSERT( !block ); + + block = memory->alloc( memory, new_count * item_size ); + if ( block == NULL ) + error = FT_THROW( Out_Of_Memory ); + } + else + { + FT_Pointer block2; + FT_Long cur_size = cur_count * item_size; + FT_Long new_size = new_count * item_size; + + + block2 = memory->realloc( memory, cur_size, new_size, block ); + if ( !block2 ) + error = FT_THROW( Out_Of_Memory ); + else + block = block2; + } + + *p_error = error; + return block; + } + + + FT_BASE_DEF( void ) + ft_mem_free( FT_Memory memory, + const void *P ) + { + if ( P ) + memory->free( memory, (void*)P ); + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer p = ft_mem_qalloc( memory, (FT_Long)size, &error ); + + + if ( !error && address && size > 0 ) + ft_memcpy( p, address, size ); + + *p_error = error; + return p; + } + + + FT_BASE_DEF( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ) + { + FT_ULong len = str ? (FT_ULong)ft_strlen( str ) + 1 + : 0; + + + return ft_mem_dup( memory, str, len, p_error ); + } + + + FT_BASE_DEF( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ) + { + while ( size > 1 && *src != 0 ) + { + *dst++ = *src++; + size--; + } + + *dst = 0; /* always zero-terminate */ + + return *src != 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** *****/ + /***** D O U B L Y L I N K E D L I S T S *****/ + /***** *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#undef FT_COMPONENT +#define FT_COMPONENT list + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ) + { + FT_ListNode cur; + + + if ( !list ) + return NULL; + + cur = list->head; + while ( cur ) + { + if ( cur->data == data ) + return cur; + + cur = cur->next; + } + + return NULL; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Add( FT_List list, + FT_ListNode node ) + { + FT_ListNode before; + + + if ( !list || !node ) + return; + + before = list->tail; + + node->next = NULL; + node->prev = before; + + if ( before ) + before->next = node; + else + list->head = node; + + list->tail = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ) + { + FT_ListNode after; + + + if ( !list || !node ) + return; + + after = list->head; + + node->next = after; + node->prev = NULL; + + if ( !after ) + list->tail = node; + else + after->prev = node; + + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + if ( !list || !node ) + return; + + before = node->prev; + after = node->next; + + if ( before ) + before->next = after; + else + list->head = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Up( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + + + if ( !list || !node ) + return; + + before = node->prev; + after = node->next; + + /* check whether we are already on top of the list */ + if ( !before ) + return; + + before->next = after; + + if ( after ) + after->prev = before; + else + list->tail = before; + + node->prev = NULL; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ) + { + FT_ListNode cur; + FT_Error error = FT_Err_Ok; + + + if ( !list || !iterator ) + return FT_THROW( Invalid_Argument ); + + cur = list->head; + + while ( cur ) + { + FT_ListNode next = cur->next; + + + error = iterator( cur, user ); + if ( error ) + break; + + cur = next; + } + + return error; + } + + + /* documentation is in ftlist.h */ + + FT_EXPORT_DEF( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ) + { + FT_ListNode cur; + + + if ( !list || !memory ) + return; + + cur = list->head; + while ( cur ) + { + FT_ListNode next = cur->next; + void* data = cur->data; + + + if ( destroy ) + destroy( memory, data, user ); + + FT_FREE( cur ); + cur = next; + } + + list->head = NULL; + list->tail = NULL; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/ftver.rc b/Dependencies/freetype/freetype/src/base/ftver.rc new file mode 100644 index 00000000..3175ab7d --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftver.rc @@ -0,0 +1,61 @@ +/***************************************************************************/ +/* */ +/* ftver.rc */ +/* */ +/* FreeType VERSIONINFO resource for Windows DLLs. */ +/* */ +/* Copyright (C) 2018-2024 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include + +#define FT_VERSION 2,13,3,0 +#define FT_VERSION_STR "2.13.3" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION FT_VERSION +PRODUCTVERSION FT_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG +FILEFLAGS VS_FF_DEBUG +#endif +#ifdef DLL_EXPORT +FILETYPE VFT_DLL +#define FT_FILENAME "freetype.dll" +#else +FILETYPE VFT_STATIC_LIB +#define FT_FILENAME "freetype.lib" +#endif +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "The FreeType Project" + VALUE "FileDescription", "Font Rendering Library" + VALUE "FileVersion", FT_VERSION_STR + VALUE "ProductName", "FreeType" + VALUE "ProductVersion", FT_VERSION_STR + VALUE "LegalCopyright", L"\x00A9 2000-2024 The FreeType Project www.freetype.org. All rights reserved." + VALUE "InternalName", "freetype" + VALUE "OriginalFilename", FT_FILENAME + END + END + + BLOCK "VarFileInfo" + BEGIN + /* The following line should only be modified for localized versions. */ + /* It consists of any number of WORD,WORD pairs, with each pair */ + /* describing a "language,codepage" combination supported by the file. */ + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Dependencies/freetype/freetype/src/base/ftwinfnt.c b/Dependencies/freetype/freetype/src/base/ftwinfnt.c new file mode 100644 index 00000000..e849a15f --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/ftwinfnt.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * ftwinfnt.c + * + * FreeType API for accessing Windows FNT specific info (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + + /* documentation is in ftwinfnt.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *header ) + { + FT_Service_WinFnt service; + FT_Error error; + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !header ) + return FT_THROW( Invalid_Argument ); + + FT_FACE_LOOKUP_SERVICE( face, service, WINFNT ); + + if ( service ) + error = service->get_header( face, header ); + else + error = FT_THROW( Invalid_Argument ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/base/md5.c b/Dependencies/freetype/freetype/src/base/md5.c new file mode 100644 index 00000000..b235e17a --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/md5.c @@ -0,0 +1,291 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#ifndef HAVE_OPENSSL + +#include + +#include "md5.h" + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void MD5_Init(MD5_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + available = 64 - used; + + if (size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void MD5_Final(unsigned char *result, MD5_CTX *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} + +#endif diff --git a/Dependencies/freetype/freetype/src/base/md5.h b/Dependencies/freetype/freetype/src/base/md5.h new file mode 100644 index 00000000..2da44bf3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/base/md5.h @@ -0,0 +1,45 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +#ifdef HAVE_OPENSSL +#include +#elif !defined(_MD5_H) +#define _MD5_H + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; + +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; + +extern void MD5_Init(MD5_CTX *ctx); +extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); +extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); + +#endif diff --git a/Dependencies/freetype/freetype/src/bdf/README b/Dependencies/freetype/freetype/src/bdf/README new file mode 100644 index 00000000..d7cb8c14 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/README @@ -0,0 +1,152 @@ + FreeType font driver for BDF fonts + + Francesco Zappa Nardelli + + + +Introduction +************ + +BDF (Bitmap Distribution Format) is a bitmap font format defined by Adobe, +which is intended to be easily understood by both humans and computers. +This code implements a BDF driver for the FreeType library, following the +Adobe Specification V 2.2. The specification of the BDF font format is +available from Adobe's web site: + + https://adobe-type-tools.github.io/font-tech-notes/pdfs/5005.BDF_Spec.pdf + +Many good bitmap fonts in bdf format come with XFree86 (www.XFree86.org). +They do not define vertical metrics, because the X Consortium BDF +specification has removed them. + + +Encodings +********* + +[This section is out of date, retained for historical reasons. BDF + properties can be retrieved with `FT_Get_BDF_Property`, character set ID + values with `FT_Get_BDF_Charset_ID`.] + +The variety of encodings that accompanies bdf fonts appears to encompass the +small set defined in freetype.h. On the other hand, two properties that +specify encoding and registry are usually defined in bdf fonts. + +I decided to make these two properties directly accessible, leaving to the +client application the work of interpreting them. For instance: + + + #include FT_INTERNAL_BDF_TYPES_H + + FT_Face face; + BDF_Public_Face bdfface; + + + FT_New_Face( library, ..., &face ); + + bdfface = (BDF_Public_Face)face; + + if ( ( bdfface->charset_registry == "ISO10646" ) && + ( bdfface->charset_encoding == "1" ) ) + [..] + + +Thus the driver always exports `ft_encoding_none' as face->charmap.encoding. +FT_Get_Char_Index's behavior is unmodified, that is, it converts the ULong +value given as argument into the corresponding glyph number. + +If the two properties are not available, Adobe Standard Encoding should be +assumed. + + +Anti-Aliased Bitmaps +******************** + +The driver supports an extension to the BDF format as used in Mark Leisher's +xmbdfed bitmap font editor. Microsoft's SBIT tool expects bitmap fonts in +that format for adding anti-aliased them to TrueType fonts. It introduces a +fourth field to the `SIZE' keyword which gives the bpp value (bits per +pixel) of the glyph data in the font. Possible values are 1 (the default), +2 (four gray levels), 4 (16 gray levels), and 8 (256 gray levels). The +driver returns either a bitmap with 1 bit per pixel or a pixmap with 8bits +per pixel (using 4, 16, and 256 gray levels, respectively). + + +Known problems +************** + +- A font is entirely loaded into memory. Obviously, this is not the Right + Thing(TM). If you have big fonts I suggest you convert them into PCF + format (using the bdftopcf utility): the PCF font drive of FreeType can + perform incremental glyph loading. + +When I have some time, I will implement on-demand glyph parsing. + +- Except for encodings properties, client applications have no visibility of + the PCF_Face object. This means that applications cannot directly access + font tables and must trust FreeType. + +- Currently, glyph names are ignored. + + I plan to give full visibility of the BDF_Face object in an upcoming + revision of the driver, thus implementing also glyph names. + +- As I have never seen a BDF font that defines vertical metrics, vertical + metrics are (parsed and) discarded. If you own a BDF font that defines + vertical metrics, please let me know (I will implement them in 5-10 + minutes). + + +License +******* + +Copyright (C) 2001-2002 by Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*** Portions of the driver (that is, bdflib.c and bdf.h): + +Copyright 2000 Computing Research Labs, New Mexico State University +Copyright 2001-2002, 2011 Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Credits +******* + +This driver is based on excellent Mark Leisher's bdf library. If you +find something good in this driver you should probably thank him, not +me. diff --git a/Dependencies/freetype/freetype/src/bdf/bdf.c b/Dependencies/freetype/freetype/src/bdf/bdf.c new file mode 100644 index 00000000..249012e5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdf.c @@ -0,0 +1,34 @@ +/* bdf.c + + FreeType font driver for bdf files + + Copyright (C) 2001, 2002 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "bdflib.c" +#include "bdfdrivr.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bdf/bdf.h b/Dependencies/freetype/freetype/src/bdf/bdf.h new file mode 100644 index 00000000..e2cb52c1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdf.h @@ -0,0 +1,253 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2004, 2011 Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef BDF_H_ +#define BDF_H_ + + +/* + * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher + */ + +#include +#include +#include + + +FT_BEGIN_HEADER + + +/* Imported from bdfP.h */ + +#define _bdf_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] & ( 1UL << ( (e) & 31 ) ) ) +#define _bdf_set_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] |= ( 1UL << ( (e) & 31 ) ) ) +#define _bdf_clear_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] &= ~( 1UL << ( (e) & 31 ) ) ) + +/* end of bdfP.h */ + + + /************************************************************************** + * + * BDF font options macros and types. + * + */ + + +#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */ +#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */ +#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */ +#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */ +#define BDF_MONOWIDTH 0x10 /* Font has mono width. */ +#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */ + +#define BDF_ALL_SPACING ( BDF_PROPORTIONAL | \ + BDF_MONOWIDTH | \ + BDF_CHARCELL ) + +#define BDF_DEFAULT_LOAD_OPTIONS ( BDF_CORRECT_METRICS | \ + BDF_KEEP_COMMENTS | \ + BDF_KEEP_UNENCODED | \ + BDF_PROPORTIONAL ) + + + typedef struct bdf_options_t_ + { + int correct_metrics; + int keep_unencoded; + int keep_comments; + int font_spacing; + + } bdf_options_t; + + + /* Callback function type for unknown configuration options. */ + typedef int + (*bdf_options_callback_t)( bdf_options_t* opts, + char** params, + unsigned long nparams, + void* client_data ); + + + /************************************************************************** + * + * BDF font property macros and types. + * + */ + + +#define BDF_ATOM 1 +#define BDF_INTEGER 2 +#define BDF_CARDINAL 3 + + + /* This structure represents a particular property of a font. */ + /* There are a set of defaults and each font has their own. */ + typedef struct bdf_property_t_ + { + const char* name; /* Name of the property. */ + int format; /* Format of the property. */ + int builtin; /* A builtin property. */ + union + { + char* atom; + long l; + unsigned long ul; + + } value; /* Value of the property. */ + + } bdf_property_t; + + + /************************************************************************** + * + * BDF font metric and glyph types. + * + */ + + + typedef struct bdf_bbx_t_ + { + unsigned short width; + unsigned short height; + + short x_offset; + short y_offset; + + short ascent; + short descent; + + } bdf_bbx_t; + + + typedef struct bdf_glyph_t_ + { + char* name; /* Glyph name. */ + unsigned long encoding; /* Glyph encoding. */ + unsigned short swidth; /* Scalable width. */ + unsigned short dwidth; /* Device width. */ + bdf_bbx_t bbx; /* Glyph bounding box. */ + unsigned char* bitmap; /* Glyph bitmap. */ + unsigned long bpr; /* Number of bytes used per row. */ + unsigned short bytes; /* Number of bytes used for the bitmap. */ + + } bdf_glyph_t; + + + typedef struct bdf_font_t_ + { + char* name; /* Name of the font. */ + bdf_bbx_t bbx; /* Font bounding box. */ + + unsigned long point_size; /* Point size of the font. */ + unsigned long resolution_x; /* Font horizontal resolution. */ + unsigned long resolution_y; /* Font vertical resolution. */ + + int spacing; /* Font spacing value. */ + + unsigned short monowidth; /* Logical width for monowidth font. */ + + unsigned long default_char; /* Encoding of the default glyph. */ + + long font_ascent; /* Font ascent. */ + long font_descent; /* Font descent. */ + + unsigned long glyphs_size; /* Glyph structures allocated. */ + unsigned long glyphs_used; /* Glyph structures used. */ + bdf_glyph_t* glyphs; /* Glyphs themselves. */ + + unsigned long unencoded_size; /* Unencoded glyph struct. allocated. */ + unsigned long unencoded_used; /* Unencoded glyph struct. used. */ + bdf_glyph_t* unencoded; /* Unencoded glyphs themselves. */ + + unsigned long props_size; /* Font properties allocated. */ + unsigned long props_used; /* Font properties used. */ + bdf_property_t* props; /* Font properties themselves. */ + + char* comments; /* Font comments. */ + unsigned long comments_len; /* Length of comment string. */ + + void* internal; /* Internal data for the font. */ + + unsigned short bpp; /* Bits per pixel. */ + + FT_Memory memory; + + bdf_property_t* user_props; + unsigned long nuser_props; + FT_HashRec proptbl; + + } bdf_font_t; + + + /************************************************************************** + * + * Types for load/save callbacks. + * + */ + + + /* Error codes. */ +#define BDF_MISSING_START -1 +#define BDF_MISSING_FONTNAME -2 +#define BDF_MISSING_SIZE -3 +#define BDF_MISSING_CHARS -4 +#define BDF_MISSING_STARTCHAR -5 +#define BDF_MISSING_ENCODING -6 +#define BDF_MISSING_BBX -7 + +#define BDF_OUT_OF_MEMORY -20 + +#define BDF_INVALID_LINE -100 + + + /************************************************************************** + * + * BDF font API. + * + */ + + FT_LOCAL( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory memory, + bdf_options_t* opts, + bdf_font_t* *font ); + + FT_LOCAL( void ) + bdf_free_font( bdf_font_t* font ); + + FT_LOCAL( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ); + + +FT_END_HEADER + + +#endif /* BDF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bdf/bdfdrivr.c b/Dependencies/freetype/freetype/src/bdf/bdfdrivr.c new file mode 100644 index 00000000..4b9d6347 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdfdrivr.c @@ -0,0 +1,1013 @@ +/* bdfdrivr.c + + FreeType font driver for bdf files + + Copyright (C) 2001-2008, 2011, 2013, 2014 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include +#include +#include +#include +#include + +#include +#include + +#include "bdf.h" +#include "bdfdrivr.h" + +#include "bdferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bdfdriver + + + typedef struct BDF_CMapRec_ + { + FT_CMapRec cmap; + FT_ULong num_encodings; /* ftobjs.h: FT_CMap->clazz->size */ + BDF_encoding_el* encodings; + + } BDF_CMapRec, *BDF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + bdf_cmap_init( FT_CMap bdfcmap, + FT_Pointer init_data ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap ); + FT_UNUSED( init_data ); + + + cmap->num_encodings = face->bdffont->glyphs_used; + cmap->encodings = face->en_table; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + bdf_cmap_done( FT_CMap bdfcmap ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + + + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_index( FT_CMap bdfcmap, + FT_UInt32 charcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UShort result = 0; /* encodings->glyph */ + + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; + + + while ( min < max ) + { + FT_ULong code = encodings[mid].enc; + + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + break; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + + /* reasonable prediction in a continuous block */ + mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_next( FT_CMap bdfcmap, + FT_UInt32 *acharcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; + FT_UShort result = 0; /* encodings->glyph */ + FT_ULong charcode = *acharcode + 1; + + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; + + + while ( min < max ) + { + FT_ULong code = encodings[mid].enc; + + + if ( charcode == code ) + { + /* increase glyph index by 1 -- */ + /* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + goto Exit; + } + + if ( charcode < code ) + max = mid; + else + min = mid + 1; + + /* prediction in a continuous block */ + mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; + } + + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + + Exit: + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API", + charcode )); + *acharcode = 0; + /* XXX: result should be changed to indicate an overflow error */ + } + else + *acharcode = (FT_UInt32)charcode; + return result; + } + + + static + const FT_CMap_ClassRec bdf_cmap_class = + { + sizeof ( BDF_CMapRec ), + bdf_cmap_init, + bdf_cmap_done, + bdf_cmap_char_index, + bdf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + + static FT_Error + bdf_interpret_style( BDF_Face bdf ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = FT_FACE( bdf ); + FT_Memory memory = face->memory; + bdf_font_t* font = bdf->bdffont; + bdf_property_t* prop; + + const char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t lengths[4], nn, len; + + + face->style_flags = 0; + + prop = bdf_get_font_property( font, "SLANT" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) + ? "Oblique" + : "Italic"; + } + + prop = bdf_get_font_property( font, "WEIGHT_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = "Bold"; + } + + prop = bdf_get_font_property( font, "SETWIDTH_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (const char *)(prop->value.atom); + + prop = bdf_get_font_property( font, "ADD_STYLE_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (const char *)(prop->value.atom); + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = "Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_QALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + const char* src = strings[nn]; + + + len = lengths[nn]; + + if ( !src ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + + + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + BDF_Face_Done( FT_Face face ) /* BDF_Face */ + { + BDF_Face bdfface = (BDF_Face)face; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + bdf_free_font( bdfface->bdffont ); + + FT_FREE( bdfface->en_table ); + + FT_FREE( bdfface->charset_encoding ); + FT_FREE( bdfface->charset_registry ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); + + FT_FREE( face->available_sizes ); + + FT_FREE( bdfface->bdffont ); + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Face_Init( FT_Stream stream, + FT_Face face, /* BDF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error = FT_Err_Ok; + BDF_Face bdfface = (BDF_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + bdf_font_t* font = NULL; + bdf_options_t options; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "BDF driver\n" )); + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + options.correct_metrics = 1; /* FZ XXX: options semantics */ + options.keep_unencoded = 1; + options.keep_comments = 0; + options.font_spacing = BDF_PROPORTIONAL; + + error = bdf_load_font( stream, memory, &options, &font ); + if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) + { + FT_TRACE2(( " not a BDF file\n" )); + goto Fail; + } + else if ( error ) + goto Exit; + + /* we have a bdf font: let's construct the face object */ + bdfface->bdffont = font; + + /* BDF cannot have multiple faces in a single font file. + * XXX: non-zero face_index is already invalid argument, but + * Type1, Type42 driver has a convention to return + * an invalid argument error when the font could be + * opened by the specified driver. + */ + if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "BDF_Face_Init: invalid face index\n" )); + BDF_Face_Done( face ); + return FT_THROW( Invalid_Argument ); + } + + { + bdf_property_t* prop = NULL; + + + FT_TRACE4(( " number of glyphs: allocated %ld (used %ld)\n", + font->glyphs_size, + font->glyphs_used )); + FT_TRACE4(( " number of unencoded glyphs: allocated %ld (used %ld)\n", + font->unencoded_size, + font->unencoded_used )); + + face->num_faces = 1; + face->face_index = 0; + + face->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + prop = bdf_get_font_property( font, "SPACING" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || + *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) + face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ + /* FZ XXX: I need a font to implement this */ + + prop = bdf_get_font_property( font, "FAMILY_NAME" ); + if ( prop && prop->value.atom ) + { + if ( FT_STRDUP( face->family_name, prop->value.atom ) ) + goto Exit; + } + else + face->family_name = NULL; + + if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) ) + goto Exit; + + /* the number of glyphs (with one slot for the undefined glyph */ + /* at position 0 and all unencoded glyphs) */ + face->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); + + face->num_fixed_sizes = 1; + if ( FT_NEW( face->available_sizes ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = face->available_sizes; + FT_Short resolution_x = 0; + FT_Short resolution_y = 0; + long value; + + + /* sanity checks */ + if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) + { + font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n", + font->font_ascent )); + } + if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) + { + font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n", + font->font_descent )); + } + + bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); + + prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative average width\n" )); +#endif + if ( prop->value.l > 0x7FFFL * 10 - 5 || + prop->value.l < -( 0x7FFFL * 10 - 5 ) ) + { + bsize->width = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n", + bsize->width )); + } + else + bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); + } + else + { + /* this is a heuristical value */ + bsize->width = ( bsize->height * 2 + 1 ) / 3; + } + + prop = bdf_get_font_property( font, "POINT_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative point size\n" )); +#endif + /* convert from 722.7 decipoints to 72 points per inch */ + if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */ + prop->value.l < -0x504C2L ) + { + bsize->size = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), + 64 * 7200, + 72270L ); + } + else if ( font->point_size ) + { + if ( font->point_size > 0x7FFF ) + { + bsize->size = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = (FT_Pos)font->point_size << 6; + } + else + { + /* this is a heuristical value */ + bsize->size = bsize->width * 64; + } + + prop = bdf_get_font_property( font, "PIXEL_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" )); +#endif + if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) + { + bsize->y_ppem = 0x7FFF << 6; + FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n", + bsize->y_ppem )); + } + else + bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; + } + + prop = bdf_get_font_property( font, "RESOLUTION_X" ); + if ( prop ) + value = prop->value.l; + else + value = (long)font->resolution_x; + if ( value ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( value < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" )); +#endif + if ( value > 0x7FFF || value < -0x7FFF ) + { + resolution_x = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n", + resolution_x )); + } + else + resolution_x = FT_ABS( (FT_Short)value ); + } + + prop = bdf_get_font_property( font, "RESOLUTION_Y" ); + if ( prop ) + value = prop->value.l; + else + value = (long)font->resolution_y; + if ( value ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( value < 0 ) + FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" )); +#endif + if ( value > 0x7FFF || value < -0x7FFF ) + { + resolution_y = 0x7FFF; + FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n", + resolution_y )); + } + else + resolution_y = FT_ABS( (FT_Short)value ); + } + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = FT_MulDiv( bsize->y_ppem, + resolution_x, + resolution_y ); + else + bsize->x_ppem = bsize->y_ppem; + } + + /* encoding table */ + { + bdf_glyph_t* cur = font->glyphs; + unsigned long n; + + + if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) ) + goto Exit; + + bdfface->default_glyph = 0; + for ( n = 0; n < font->glyphs_size; n++ ) + { + (bdfface->en_table[n]).enc = cur[n].encoding; + FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding )); + (bdfface->en_table[n]).glyph = (FT_UShort)n; + + if ( cur[n].encoding == font->default_char ) + { + if ( n < FT_UINT_MAX ) + bdfface->default_glyph = (FT_UInt)n; + else + FT_TRACE1(( "BDF_Face_Init:" + " idx %ld is too large for this system\n", n )); + } + } + } + + /* charmaps */ + { + bdf_property_t *charset_registry, *charset_encoding; + FT_Bool unicode_charmap = 0; + + + charset_registry = + bdf_get_font_property( font, "CHARSET_REGISTRY" ); + charset_encoding = + bdf_get_font_property( font, "CHARSET_ENCODING" ); + if ( charset_registry && charset_encoding ) + { + if ( charset_registry->format == BDF_ATOM && + charset_encoding->format == BDF_ATOM && + charset_registry->value.atom && + charset_encoding->value.atom ) + { + const char* s; + + + if ( FT_STRDUP( bdfface->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( bdfface->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + + /* Uh, oh, compare first letters manually to avoid dependency */ + /* on locales. */ + s = bdfface->charset_registry; + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( bdfface->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + /* another name for ASCII */ + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( bdfface->charset_encoding, "IRV" ) ) + unicode_charmap = 1; + } + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + } + + goto Exit; + } + } + + /* otherwise assume Adobe standard encoding */ + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.platform_id = TT_PLATFORM_ADOBE; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); + + /* Select default charmap */ + if ( face->num_charmaps ) + face->charmap = face->charmaps[0]; + } + } + } + + Exit: + return error; + + Fail: + BDF_Face_Done( face ); + return FT_THROW( Unknown_File_Format ); + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = bdffont->font_ascent * 64; + size->metrics.descender = -bdffont->font_descent * 64; + size->metrics.max_advance = bdffont->bbx.width * 64; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FT_Face face = size->face; + FT_Bitmap_Size* bsize = face->available_sizes; + bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( bdffont->font_ascent + + bdffont->font_descent ) ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return BDF_Size_Select( size, 0 ); + } + + + + FT_CALLBACK_DEF( FT_Error ) + BDF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Face face = size->face; + BDF_Face bdf = (BDF_Face)face; + FT_Error error = FT_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + bdf_glyph_t glyph; + int bpp = bdf->bdffont->bpp; + + FT_UNUSED( load_flags ); + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( glyph_index >= (FT_UInt)face->num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); + + /* index 0 is the undefined glyph */ + if ( glyph_index == 0 ) + glyph_index = bdf->default_glyph; + else + glyph_index--; + + /* slot, bitmap => freetype, glyph => bdflib */ + glyph = bdf->bdffont->glyphs[glyph_index]; + + bitmap->rows = glyph.bbx.height; + bitmap->width = glyph.bbx.width; + if ( glyph.bpr > FT_INT_MAX ) + FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n", + glyph.bpr )); + bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ + + /* note: we don't allocate a new array to hold the bitmap; */ + /* we can simply point to it */ + ft_glyphslot_set_bitmap( slot, glyph.bitmap ); + + switch ( bpp ) + { + case 1: + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + break; + case 2: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; + break; + case 4: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; + break; + case 8: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + break; + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = glyph.bbx.x_offset; + slot->bitmap_top = glyph.bbx.ascent; + + slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 ); + slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); + slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); + slot->metrics.width = (FT_Pos)( bitmap->width * 64 ); + slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); + + /* + * XXX DWIDTH1 and VVECTOR should be parsed and + * used here, provided such fonts do exist. + */ + ft_synthesize_vertical_metrics( &slot->metrics, + bdf->bdffont->bbx.height * 64 ); + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + bdf_get_bdf_property( FT_Face face, /* BDF_Face */ + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + BDF_Face bdfface = (BDF_Face)face; + bdf_property_t* prop; + + + FT_ASSERT( bdfface && bdfface->bdffont ); + + prop = bdf_get_font_property( bdfface->bdffont, prop_name ); + if ( prop ) + { + switch ( prop->format ) + { + case BDF_ATOM: + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + break; + + case BDF_INTEGER: + if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large integer 0x%lx is truncated\n", + prop->value.l )); + } + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + break; + + case BDF_CARDINAL: + if ( prop->value.ul > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large cardinal 0x%lx is truncated\n", + prop->value.ul )); + } + aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; + aproperty->u.cardinal = (FT_UInt32)prop->value.ul; + break; + + default: + goto Fail; + } + return 0; + } + + Fail: + return FT_THROW( Invalid_Argument ); + } + + + FT_CALLBACK_DEF( FT_Error ) + bdf_get_charset_id( FT_Face face, /* BDF_Face */ + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_Face bdfface = (BDF_Face)face; + + + *acharset_encoding = bdfface->charset_encoding; + *acharset_registry = bdfface->charset_registry; + + return 0; + } + + + static const FT_Service_BDFRec bdf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */ + (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */ + }; + + + /* + * + * SERVICES LIST + * + */ + + static const FT_ServiceDescRec bdf_services[] = + { + { FT_SERVICE_ID_BDF, &bdf_service_bdf }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + bdf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( bdf_services, name ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec bdf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "bdf", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + bdf_driver_requester /* FT_Module_Requester get_interface */ + }, + + sizeof ( BDF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + BDF_Face_Init, /* FT_Face_InitFunc init_face */ + BDF_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + BDF_Size_Request, /* FT_Size_RequestFunc request_size */ + BDF_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bdf/bdfdrivr.h b/Dependencies/freetype/freetype/src/bdf/bdfdrivr.h new file mode 100644 index 00000000..54aaa335 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdfdrivr.h @@ -0,0 +1,72 @@ +/* bdfdrivr.h + + FreeType font driver for bdf fonts + + Copyright (C) 2001, 2002, 2003, 2004 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef BDFDRIVR_H_ +#define BDFDRIVR_H_ + +#include + +#include "bdf.h" + + +FT_BEGIN_HEADER + + + typedef struct BDF_encoding_el_ + { + FT_ULong enc; + FT_UShort glyph; + + } BDF_encoding_el; + + + typedef struct BDF_FaceRec_ + { + FT_FaceRec root; + + char* charset_encoding; + char* charset_registry; + + bdf_font_t* bdffont; + + BDF_encoding_el* en_table; + + FT_UInt default_glyph; + + } BDF_FaceRec, *BDF_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class; + + +FT_END_HEADER + + +#endif /* BDFDRIVR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bdf/bdferror.h b/Dependencies/freetype/freetype/src/bdf/bdferror.h new file mode 100644 index 00000000..c1b54448 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdferror.h @@ -0,0 +1,45 @@ +/* + * Copyright 2001, 2002, 2012 Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is used to define the BDF error enumeration constants. + * + */ + +#ifndef BDFERROR_H_ +#define BDFERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX BDF_Err_ +#define FT_ERR_BASE FT_Mod_Err_BDF + +#include + +#endif /* BDFERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bdf/bdflib.c b/Dependencies/freetype/freetype/src/bdf/bdflib.c new file mode 100644 index 00000000..813a4d83 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bdf/bdflib.c @@ -0,0 +1,2378 @@ +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-2014 + * Francesco Zappa Nardelli + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + /************************************************************************** + * + * This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 + * + * taken from Mark Leisher's xmbdfed package + * + */ + + + +#include +#include +#include +#include + +#include "bdf.h" +#include "bdferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bdflib + + +#define BUFSIZE 128 + + + /************************************************************************** + * + * Default BDF font options. + * + */ + + + static const bdf_options_t bdf_opts_ = + { + 1, /* Correct metrics. */ + 1, /* Preserve unencoded glyphs. */ + 0, /* Preserve comments. */ + BDF_PROPORTIONAL /* Default spacing. */ + }; + + + /************************************************************************** + * + * Builtin BDF font properties. + * + */ + + /* List of most properties that might appear in a font. Doesn't include */ + /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ + + static const bdf_property_t bdf_properties_[] = + { + { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, + { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, + { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, + { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, + { "COMMENT", BDF_ATOM, 1, { 0 } }, + { "COPYRIGHT", BDF_ATOM, 1, { 0 } }, + { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, + { "DESTINATION", BDF_CARDINAL, 1, { 0 } }, + { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, + { "END_SPACE", BDF_INTEGER, 1, { 0 } }, + { "FACE_NAME", BDF_ATOM, 1, { 0 } }, + { "FAMILY_NAME", BDF_ATOM, 1, { 0 } }, + { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "FONT", BDF_ATOM, 1, { 0 } }, + { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, + { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "FOUNDRY", BDF_ATOM, 1, { 0 } }, + { "FULL_NAME", BDF_ATOM, 1, { 0 } }, + { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, + { "MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { "MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { "NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { "NOTICE", BDF_ATOM, 1, { 0 } }, + { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { "POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, + { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { "RESOLUTION", BDF_INTEGER, 1, { 0 } }, + { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, + { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, + { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, + { "SLANT", BDF_ATOM, 1, { 0 } }, + { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SPACING", BDF_ATOM, 1, { 0 } }, + { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { "WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, + { "X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, + { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, + }; + + static const unsigned long + num_bdf_properties_ = sizeof ( bdf_properties_ ) / + sizeof ( bdf_properties_[0] ); + + + /* An auxiliary macro to parse properties, to be used in conditionals. */ + /* It behaves like `strncmp' but also tests the following character */ + /* whether it is a whitespace or null. */ + /* `property' is a constant string of length `n' to compare with. */ +#define _bdf_strncmp( name, property, n ) \ + ( ft_strncmp( name, property, n ) || \ + !( name[n] == ' ' || \ + name[n] == '\0' || \ + name[n] == '\n' || \ + name[n] == '\r' || \ + name[n] == '\t' ) ) + + /* Auto correction messages. */ +#define ACMSG1 "FONT_ASCENT property missing. " \ + "Added `FONT_ASCENT %hd'.\n" +#define ACMSG2 "FONT_DESCENT property missing. " \ + "Added `FONT_DESCENT %hd'.\n" +#define ACMSG3 "Font width != actual width. Old: %d New: %d.\n" +#define ACMSG4 "Font left bearing != actual left bearing. " \ + "Old: %hd New: %hd.\n" +#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" +#define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n" +#define ACMSG7 "Font height != actual height. Old: %d New: %d.\n" +#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" +#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" +#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" +#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" +#define ACMSG13 "Glyph %lu extra rows removed.\n" +#define ACMSG14 "Glyph %lu extra columns removed.\n" +#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" +#define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n" +#define ACMSG17 "Adjusting number of glyphs to %ld.\n" + + /* Error messages. */ +#define ERRMSG1 "[line %ld] Missing `%s' line.\n" +#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" +#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" +#define ERRMSG4 "[line %ld] BBX too big.\n" +#define ERRMSG5 "[line %ld] `%s' value too big.\n" +#define ERRMSG6 "[line %ld] Input line too long.\n" +#define ERRMSG7 "[line %ld] Font name too long.\n" +#define ERRMSG8 "[line %ld] Invalid `%s' value.\n" +#define ERRMSG9 "[line %ld] Invalid keyword.\n" + + /* Debug messages. */ +#define DBGMSG1 " [%6ld] %s" /* no \n */ +#define DBGMSG2 " (0x%lX)\n" + + + /************************************************************************** + * + * Utility types and functions. + * + */ + + + /* Function type for parsing lines of a BDF font. */ + + typedef FT_Error + (*bdf_line_func_t_)( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ); + + + /* List structure for splitting lines into fields. */ + + typedef struct bdf_list_t__ + { + char** field; + unsigned long size; + unsigned long used; + FT_Memory memory; + + } bdf_list_t_; + + + /* Structure used while loading BDF fonts. */ + + typedef struct bdf_parse_t__ + { + unsigned long flags; + unsigned long cnt; + unsigned long row; + + short minlb; + short maxlb; + short maxrb; + short maxas; + short maxds; + + short rbearing; + + char* glyph_name; + long glyph_enc; + + bdf_font_t* font; + bdf_options_t* opts; + + bdf_list_t_ list; + + FT_Memory memory; + unsigned long size; /* the stream size */ + + } bdf_parse_t_; + + +#define setsbit( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) +#define sbitset( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) + + + static void + bdf_list_init_( bdf_list_t_* list, + FT_Memory memory ) + { + FT_ZERO( list ); + list->memory = memory; + } + + + static void + bdf_list_done_( bdf_list_t_* list ) + { + FT_Memory memory = list->memory; + + + if ( memory ) + { + FT_FREE( list->field ); + FT_ZERO( list ); + } + } + + + static FT_Error + bdf_list_ensure_( bdf_list_t_* list, + unsigned long num_items ) /* same as bdf_list_t_.used */ + { + FT_Error error = FT_Err_Ok; + + + if ( num_items > list->size ) + { + unsigned long oldsize = list->size; /* same as bdf_list_t_.size */ + unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5; + unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); + FT_Memory memory = list->memory; + + + if ( oldsize == bigsize ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + else if ( newsize < oldsize || newsize > bigsize ) + newsize = bigsize; + + if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) ) + goto Exit; + + list->size = newsize; + } + + Exit: + return error; + } + + + static void + bdf_list_shift_( bdf_list_t_* list, + unsigned long n ) + { + unsigned long i, u; + + + if ( list == NULL || list->used == 0 || n == 0 ) + return; + + if ( n >= list->used ) + { + list->used = 0; + return; + } + + for ( u = n, i = 0; u < list->used; i++, u++ ) + list->field[i] = list->field[u]; + list->used -= n; + } + + + /* An empty string for empty fields. */ + + static const char empty[] = ""; /* XXX eliminate this */ + + + static char * + bdf_list_join_( bdf_list_t_* list, + int c, + unsigned long *alen ) + { + unsigned long i, j; + char* dp; + + + *alen = 0; + + if ( list == NULL || list->used == 0 ) + return NULL; + + dp = list->field[0]; + for ( i = j = 0; i < list->used; i++ ) + { + char* fp = list->field[i]; + + + while ( *fp ) + dp[j++] = *fp++; + + if ( i + 1 < list->used ) + dp[j++] = (char)c; + } + if ( dp != empty ) + dp[j] = 0; + + *alen = j; + return dp; + } + + + /* The code below ensures that we have at least 4 + 1 `field' */ + /* elements in `list' (which are possibly NULL) so that we */ + /* don't have to check the number of fields in most cases. */ + + static FT_Error + bdf_list_split_( bdf_list_t_* list, + const char* separators, + char* line, + unsigned long linelen ) + { + unsigned long final_empty; + int mult; + const char *sp, *end; + char *ep; + char seps[32]; + FT_Error error = FT_Err_Ok; + + + /* Initialize the list. */ + list->used = 0; + if ( list->size ) + { + list->field[0] = (char*)empty; + list->field[1] = (char*)empty; + list->field[2] = (char*)empty; + list->field[3] = (char*)empty; + list->field[4] = (char*)empty; + } + + /* If the line is empty, then simply return. */ + if ( linelen == 0 || line[0] == 0 ) + goto Exit; + + /* In the original code, if the `separators' parameter is NULL or */ + /* empty, the list is split into individual bytes. We don't need */ + /* this, so an error is signaled. */ + if ( separators == NULL || *separators == 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Prepare the separator bitmap. */ + FT_MEM_ZERO( seps, 32 ); + + /* If the very last character of the separator string is a plus, then */ + /* set the `mult' flag to indicate that multiple separators should be */ + /* collapsed into one. */ + for ( mult = 0, sp = separators; sp && *sp; sp++ ) + { + if ( *sp == '+' && *( sp + 1 ) == 0 ) + mult = 1; + else + setsbit( seps, *sp ); + } + + /* Break the line up into fields. */ + for ( final_empty = 0, sp = ep = line, end = sp + linelen; + sp < end && *sp; ) + { + /* Collect everything that is not a separator. */ + for ( ; *ep && !sbitset( seps, *ep ); ep++ ) + ; + + /* Resize the list if necessary. */ + if ( list->used == list->size ) + { + error = bdf_list_ensure_( list, list->used + 1 ); + if ( error ) + goto Exit; + } + + /* Assign the field appropriately. */ + list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty; + + sp = ep; + + if ( mult ) + { + /* If multiple separators should be collapsed, do it now by */ + /* setting all the separator characters to 0. */ + for ( ; *ep && sbitset( seps, *ep ); ep++ ) + *ep = 0; + } + else if ( *ep != 0 ) + /* Don't collapse multiple separators by making them 0, so just */ + /* make the one encountered 0. */ + *ep++ = 0; + + final_empty = ( ep > sp && *ep == 0 ); + sp = ep; + } + + /* Finally, NULL-terminate the list. */ + if ( list->used + final_empty >= list->size ) + { + error = bdf_list_ensure_( list, list->used + final_empty + 1 ); + if ( error ) + goto Exit; + } + + if ( final_empty ) + list->field[list->used++] = (char*)empty; + + list->field[list->used] = NULL; + + Exit: + return error; + } + + +#define NO_SKIP 256 /* this value cannot be stored in a 'char' */ + + + static FT_Error + bdf_readstream_( FT_Stream stream, + bdf_line_func_t_ callback, + void* client_data, + unsigned long *lno ) + { + bdf_line_func_t_ cb; + unsigned long lineno, buf_size; + int refill, hold, to_skip; + ptrdiff_t bytes, start, end, cursor, avail; + char* buf = NULL; + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + + if ( callback == NULL ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* initial size and allocation of the input buffer */ + buf_size = 1024; + + if ( FT_QALLOC( buf, buf_size ) ) + goto Exit; + + cb = callback; + lineno = 1; + buf[0] = 0; + start = 0; + avail = 0; + cursor = 0; + refill = 1; + to_skip = NO_SKIP; + bytes = 0; /* make compiler happy */ + + for (;;) + { + if ( refill ) + { + bytes = (ptrdiff_t)FT_Stream_TryRead( + stream, (FT_Byte*)buf + cursor, + buf_size - (unsigned long)cursor ); + avail = cursor + bytes; + cursor = 0; + refill = 0; + } + + end = start; + + /* should we skip an optional character like \n or \r? */ + if ( start < avail && buf[start] == to_skip ) + { + start += 1; + to_skip = NO_SKIP; + continue; + } + + /* try to find the end of the line */ + while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) + end++; + + /* if we hit the end of the buffer, try shifting its content */ + /* or even resizing it */ + if ( end >= avail ) + { + if ( bytes == 0 ) + { + /* last line in file doesn't end in \r or \n; */ + /* ignore it then exit */ + if ( lineno == 1 ) + error = FT_THROW( Missing_Startfont_Field ); + break; + } + + if ( start == 0 ) + { + /* this line is definitely too long; try resizing the input */ + /* buffer a bit to handle it. */ + FT_ULong new_size; + + + if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ + { + if ( lineno == 1 ) + error = FT_THROW( Missing_Startfont_Field ); + else + { + FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno )); + error = FT_THROW( Invalid_Argument ); + } + goto Exit; + } + + new_size = buf_size * 2; + if ( FT_QREALLOC( buf, buf_size, new_size ) ) + goto Exit; + + cursor = avail; + buf_size = new_size; + } + else + { + bytes = avail - start; + + FT_MEM_MOVE( buf, buf + start, bytes ); + + cursor = bytes; + start = 0; + } + refill = 1; + continue; + } + + /* Temporarily NUL-terminate the line. */ + hold = buf[end]; + buf[end] = 0; + + /* XXX: Use encoding independent value for 0x1A */ + if ( buf[start] != '#' && buf[start] != 0x1A && end > start ) + { + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); + /* Redo if we have encountered CHARS without properties. */ + if ( error == -1 ) + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); + if ( error ) + break; + } + + lineno += 1; + buf[end] = (char)hold; + start = end + 1; + + if ( hold == '\n' ) + to_skip = '\r'; + else if ( hold == '\r' ) + to_skip = '\n'; + else + to_skip = NO_SKIP; + } + + *lno = lineno; + + Exit: + FT_FREE( buf ); + return error; + } + + + /* XXX: make this work with EBCDIC also */ + + static const unsigned char a2i[128] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + static const unsigned char ddigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const unsigned char hdigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + + /* Routine to convert a decimal ASCII string to an unsigned long integer. */ + static unsigned long + bdf_atoul_( const char* s ) + { + unsigned long v; + + + if ( s == NULL || *s == 0 ) + return 0; + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_ULONG_MAX - 9 ) / 10 ) + v = v * 10 + a2i[(int)*s]; + else + { + v = FT_ULONG_MAX; + break; + } + } + + return v; + } + + + /* Routine to convert a decimal ASCII string to a signed long integer. */ + static long + bdf_atol_( const char* s ) + { + long v, neg; + + + if ( s == NULL || *s == 0 ) + return 0; + + /* Check for a minus sign. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_LONG_MAX - 9 ) / 10 ) + v = v * 10 + a2i[(int)*s]; + else + { + v = FT_LONG_MAX; + break; + } + } + + return ( !neg ) ? v : -v; + } + + + /* Routine to convert a decimal ASCII string to an unsigned short integer. */ + static unsigned short + bdf_atous_( const char* s ) + { + unsigned short v; + + + if ( s == NULL || *s == 0 ) + return 0; + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( FT_USHORT_MAX - 9 ) / 10 ) + v = (unsigned short)( v * 10 + a2i[(int)*s] ); + else + { + v = FT_USHORT_MAX; + break; + } + } + + return v; + } + + + /* Routine to convert a decimal ASCII string to a signed short integer. */ + static short + bdf_atos_( const char* s ) + { + short v, neg; + + + if ( s == NULL || *s == 0 ) + return 0; + + /* Check for a minus. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } + + for ( v = 0; sbitset( ddigits, *s ); s++ ) + { + if ( v < ( SHRT_MAX - 9 ) / 10 ) + v = (short)( v * 10 + a2i[(int)*s] ); + else + { + v = SHRT_MAX; + break; + } + } + + return (short)( ( !neg ) ? v : -v ); + } + + + /* Routine to compare two glyphs by encoding so they can be sorted. */ + FT_COMPARE_DEF( int ) + by_encoding( const void* a, + const void* b ) + { + bdf_glyph_t *c1, *c2; + + + c1 = (bdf_glyph_t *)a; + c2 = (bdf_glyph_t *)b; + + if ( c1->encoding < c2->encoding ) + return -1; + + if ( c1->encoding > c2->encoding ) + return 1; + + return 0; + } + + + static FT_Error + bdf_create_property( const char* name, + int format, + bdf_font_t* font ) + { + size_t n; + bdf_property_t* p; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + + /* First check whether the property has */ + /* already been added or not. If it has, then */ + /* simply ignore it. */ + if ( ft_hash_str_lookup( name, &(font->proptbl) ) ) + goto Exit; + + if ( FT_QRENEW_ARRAY( font->user_props, + font->nuser_props, + font->nuser_props + 1 ) ) + goto Exit; + + p = font->user_props + font->nuser_props; + + if ( FT_STRDUP( p->name, name ) ) + goto Exit; + + p->format = format; + p->builtin = 0; + p->value.atom = NULL; /* nothing is ever stored here */ + + n = num_bdf_properties_ + font->nuser_props; + + error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory ); + if ( error ) + goto Exit; + + font->nuser_props++; + + Exit: + return error; + } + + + static bdf_property_t* + bdf_get_property( const char* name, + bdf_font_t* font ) + { + size_t* propid; + + + if ( name == NULL || *name == 0 ) + return NULL; + + if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL ) + return NULL; + + if ( *propid >= num_bdf_properties_ ) + return font->user_props + ( *propid - num_bdf_properties_ ); + + return (bdf_property_t*)bdf_properties_ + *propid; + } + + + /************************************************************************** + * + * BDF font file parsing flags and functions. + * + */ + + + /* Parse flags. */ + +#define BDF_START_ 0x0001U +#define BDF_FONT_NAME_ 0x0002U +#define BDF_SIZE_ 0x0004U +#define BDF_FONT_BBX_ 0x0008U +#define BDF_PROPS_ 0x0010U +#define BDF_GLYPHS_ 0x0020U +#define BDF_GLYPH_ 0x0040U +#define BDF_ENCODING_ 0x0080U +#define BDF_SWIDTH_ 0x0100U +#define BDF_DWIDTH_ 0x0200U +#define BDF_BBX_ 0x0400U +#define BDF_BITMAP_ 0x0800U + +#define BDF_SWIDTH_ADJ_ 0x1000U + +#define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \ + BDF_ENCODING_ | \ + BDF_SWIDTH_ | \ + BDF_DWIDTH_ | \ + BDF_BBX_ | \ + BDF_BITMAP_ ) + +#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL +#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL + + + static FT_Error + bdf_add_comment_( bdf_font_t* font, + const char* comment, + unsigned long len ) + { + char* cp; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + + if ( FT_QRENEW_ARRAY( font->comments, + font->comments_len, + font->comments_len + len + 1 ) ) + goto Exit; + + cp = font->comments + font->comments_len; + + FT_MEM_COPY( cp, comment, len ); + cp[len] = '\0'; + + font->comments_len += len + 1; + + Exit: + return error; + } + + + /* Set the spacing from the font name if it exists, or set it to the */ + /* default specified in the options. */ + static FT_Error + bdf_set_default_spacing_( bdf_font_t* font, + bdf_options_t* opts, + unsigned long lineno ) + { + size_t len; + char name[256]; + bdf_list_t_ list; + FT_Memory memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + if ( font == NULL || font->name == NULL || font->name[0] == 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = font->memory; + + bdf_list_init_( &list, memory ); + + font->spacing = opts->font_spacing; + + len = ft_strlen( font->name ) + 1; + /* Limit ourselves to 256 characters in the font name. */ + if ( len >= 256 ) + { + FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_MEM_COPY( name, font->name, len ); + + error = bdf_list_split_( &list, "-", name, (unsigned long)len ); + if ( error ) + goto Fail; + + if ( list.used == 15 ) + { + switch ( list.field[11][0] ) + { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + + Fail: + bdf_list_done_( &list ); + + Exit: + return error; + } + + + /* Determine whether the property is an atom or not. If it is, then */ + /* clean it up so the double quotes are removed if they exist. */ + static int + bdf_is_atom_( char* line, + unsigned long linelen, + char** name, + char** value, + bdf_font_t* font ) + { + int hold; + char *sp, *ep; + bdf_property_t* p; + + + sp = ep = line; + + while ( *ep && *ep != ' ' && *ep != '\t' ) + ep++; + + hold = *ep; + *ep = '\0'; + + p = bdf_get_property( sp, font ); + + /* If the property exists and is not an atom, just return here. */ + if ( p && p->format != BDF_ATOM ) + { + *ep = (char)hold; /* Undo NUL-termination. */ + return 0; + } + + *name = sp; + + /* The property is an atom. Trim all leading and trailing whitespace */ + /* and double quotes for the atom value. */ + sp = ep; + ep = line + linelen; + + /* Trim the leading whitespace if it exists. */ + if ( sp < ep ) + do + sp++; + while ( *sp == ' ' || *sp == '\t' ); + + /* Trim the leading double quote if it exists. */ + if ( *sp == '"' ) + sp++; + + *value = sp; + + /* Trim the trailing whitespace if it exists. */ + if ( sp < ep ) + do + *ep-- = '\0'; + while ( *ep == ' ' || *ep == '\t' ); + + /* Trim the trailing double quote if it exists. */ + if ( *ep == '"' ) + *ep = '\0'; + + return 1; + } + + + static FT_Error + bdf_add_property_( bdf_font_t* font, + const char* name, + char* value, + unsigned long lineno ) + { + size_t* propid; + bdf_property_t *prop, *fp; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + /* First, check whether the property already exists in the font. */ + if ( ( propid = ft_hash_str_lookup( name, + (FT_Hash)font->internal ) ) != NULL ) + { + /* The property already exists in the font, so simply replace */ + /* the value of the property with the current value. */ + fp = font->props + *propid; + + switch ( fp->format ) + { + case BDF_ATOM: + /* Delete the current atom if it exists. */ + FT_FREE( fp->value.atom ); + + if ( value && value[0] != 0 ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.l = bdf_atol_( value ); + break; + + case BDF_CARDINAL: + fp->value.ul = bdf_atoul_( value ); + break; + + default: + ; + } + + goto Exit; + } + + /* See whether this property type exists yet or not. */ + /* If not, create it. */ + propid = ft_hash_str_lookup( name, &(font->proptbl) ); + if ( !propid ) + { + error = bdf_create_property( name, BDF_ATOM, font ); + if ( error ) + goto Exit; + propid = ft_hash_str_lookup( name, &(font->proptbl) ); + } + + /* Allocate another property if this is overflowing. */ + if ( font->props_used == font->props_size ) + { + if ( FT_QRENEW_ARRAY( font->props, + font->props_size, + font->props_size + 1 ) ) + goto Exit; + + font->props_size++; + } + + if ( *propid >= num_bdf_properties_ ) + prop = font->user_props + ( *propid - num_bdf_properties_ ); + else + prop = (bdf_property_t*)bdf_properties_ + *propid; + + fp = font->props + font->props_used; + + fp->name = prop->name; + fp->format = prop->format; + fp->builtin = prop->builtin; + + switch ( prop->format ) + { + case BDF_ATOM: + fp->value.atom = NULL; + if ( value && value[0] ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + + case BDF_INTEGER: + fp->value.l = bdf_atol_( value ); + break; + + case BDF_CARDINAL: + fp->value.ul = bdf_atoul_( value ); + break; + } + + /* If the property happens to be a comment, then it doesn't need */ + /* to be added to the internal hash table. */ + if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 ) + { + /* Add the property to the font property table. */ + error = ft_hash_str_insert( fp->name, + font->props_used, + (FT_Hash)font->internal, + memory ); + if ( error ) + goto Exit; + } + + font->props_used++; + + /* Some special cases need to be handled here. The DEFAULT_CHAR */ + /* property needs to be located if it exists in the property list, the */ + /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ + /* present, and the SPACING property should override the default */ + /* spacing. */ + if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 ) + font->default_char = fp->value.ul; + else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 ) + font->font_ascent = fp->value.l; + else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 ) + font->font_descent = fp->value.l; + else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 ) + { + if ( !fp->value.atom ) + { + FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) + font->spacing = BDF_PROPORTIONAL; + else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) + font->spacing = BDF_MONOWIDTH; + else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) + font->spacing = BDF_CHARCELL; + } + + Exit: + return error; + } + + + static const unsigned char nibble_mask[8] = + { + 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE + }; + + + static FT_Error + bdf_parse_end_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + /* a no-op; we ignore everything after `ENDFONT' */ + + FT_UNUSED( line ); + FT_UNUSED( linelen ); + FT_UNUSED( lineno ); + FT_UNUSED( call_data ); + FT_UNUSED( client_data ); + + return FT_Err_Ok; + } + + + /* Actually parse the glyph info and bitmaps. */ + static FT_Error + bdf_parse_glyphs_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + int c, mask_index; + char* s; + unsigned char* bp; + unsigned long i, slen, nibbles; + + bdf_line_func_t_* next; + bdf_parse_t_* p; + bdf_glyph_t* glyph; + bdf_font_t* font; + + FT_Memory memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + font = p->font; + memory = font->memory; + + /* Check for a comment. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = bdf_add_comment_( p->font, s, linelen ); + } + goto Exit; + } + + /* The very first thing expected is the number of glyphs. */ + if ( !( p->flags & BDF_GLYPHS_ ) ) + { + if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" )); + error = FT_THROW( Missing_Chars_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] ); + + /* We need at least 20 bytes per glyph. */ + if ( p->cnt > p->size / 20 ) + { + p->cnt = font->glyphs_size = p->size / 20; + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt )); + } + + /* Make sure the number of glyphs is non-zero. */ + if ( p->cnt == 0 ) + font->glyphs_size = 64; + + /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ + /* number of code points available in Unicode). */ + if ( p->cnt >= 0x110000UL ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) + goto Exit; + + p->flags |= BDF_GLYPHS_; + + goto Exit; + } + + /* Check for the ENDFONT field. */ + if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 ) + { + if ( p->flags & BDF_GLYPH_BITS_ ) + { + /* Missing ENDCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); + error = FT_THROW( Corrupted_Font_Glyphs ); + goto Exit; + } + + /* Sort the glyphs by encoding. */ + ft_qsort( (char *)font->glyphs, + font->glyphs_used, + sizeof ( bdf_glyph_t ), + by_encoding ); + + p->flags &= ~BDF_START_; + *next = bdf_parse_end_; + + goto Exit; + } + + /* Check for the ENDCHAR field. */ + if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 ) + { + p->glyph_enc = 0; + p->flags &= ~BDF_GLYPH_BITS_; + + goto Exit; + } + + /* Check whether a glyph is being scanned but should be */ + /* ignored because it is an unencoded glyph. */ + if ( ( p->flags & BDF_GLYPH_ ) && + p->glyph_enc == -1 && + p->opts->keep_unencoded == 0 ) + goto Exit; + + /* Check for the STARTCHAR field. */ + if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 ) + { + if ( p->flags & BDF_GLYPH_BITS_ ) + { + /* Missing ENDCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); + error = FT_THROW( Missing_Startchar_Field ); + goto Exit; + } + + /* Set the character name in the parse info first until the */ + /* encoding can be checked for an unencoded character. */ + FT_FREE( p->glyph_name ); + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + bdf_list_shift_( &p->list, 1 ); + + s = bdf_list_join_( &p->list, ' ', &slen ); + + if ( !s ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( FT_DUP( p->glyph_name, s, slen + 1 ) ) + goto Exit; + + p->flags |= BDF_GLYPH_; + + FT_TRACE4(( DBGMSG1, lineno, s )); + + goto Exit; + } + + /* Check for the ENCODING field. */ + if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 ) + { + if ( !( p->flags & BDF_GLYPH_ ) ) + { + /* Missing STARTCHAR field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" )); + error = FT_THROW( Missing_Startchar_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->glyph_enc = bdf_atol_( p->list.field[1] ); + + /* Normalize negative encoding values. The specification only */ + /* allows -1, but we can be more generous here. */ + if ( p->glyph_enc < -1 ) + p->glyph_enc = -1; + + /* Check for alternative encoding format. */ + if ( p->glyph_enc == -1 && p->list.used > 2 ) + p->glyph_enc = bdf_atol_( p->list.field[2] ); + + if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L ) + p->glyph_enc = -1; + + FT_TRACE4(( DBGMSG2, p->glyph_enc )); + + if ( p->glyph_enc >= 0 ) + { + /* Make sure there are enough glyphs allocated in case the */ + /* number of characters happen to be wrong. */ + if ( font->glyphs_used == font->glyphs_size ) + { + if ( FT_RENEW_ARRAY( font->glyphs, + font->glyphs_size, + font->glyphs_size + 64 ) ) + goto Exit; + + font->glyphs_size += 64; + } + + glyph = font->glyphs + font->glyphs_used++; + glyph->name = p->glyph_name; + glyph->encoding = (unsigned long)p->glyph_enc; + + /* Reset the initial glyph info. */ + p->glyph_name = NULL; + } + else + { + /* Unencoded glyph. Check whether it should */ + /* be added or not. */ + if ( p->opts->keep_unencoded ) + { + /* Allocate the next unencoded glyph. */ + if ( font->unencoded_used == font->unencoded_size ) + { + if ( FT_RENEW_ARRAY( font->unencoded , + font->unencoded_size, + font->unencoded_size + 4 ) ) + goto Exit; + + font->unencoded_size += 4; + } + + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; + + /* Reset the initial glyph info. */ + p->glyph_name = NULL; + } + else + { + /* Free up the glyph name if the unencoded shouldn't be */ + /* kept. */ + FT_FREE( p->glyph_name ); + } + } + + /* Clear the flags that might be added when width and height are */ + /* checked for consistency. */ + p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ ); + + p->flags |= BDF_ENCODING_; + + goto Exit; + } + + if ( !( p->flags & BDF_ENCODING_ ) ) + goto Missing_Encoding; + + /* Point at the glyph being constructed. */ + if ( p->glyph_enc == -1 ) + glyph = font->unencoded + ( font->unencoded_used - 1 ); + else + glyph = font->glyphs + ( font->glyphs_used - 1 ); + + /* Check whether a bitmap is being constructed. */ + if ( p->flags & BDF_BITMAP_ ) + { + /* If there are more rows than are specified in the glyph metrics, */ + /* ignore the remaining lines. */ + if ( p->row >= (unsigned long)glyph->bbx.height ) + { + if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding )); + p->flags |= BDF_GLYPH_HEIGHT_CHECK_; + } + + goto Exit; + } + + /* Only collect the number of nibbles indicated by the glyph */ + /* metrics. If there are more columns, they are simply ignored. */ + nibbles = glyph->bpr << 1; + bp = glyph->bitmap + p->row * glyph->bpr; + + for ( i = 0; i < nibbles; i++ ) + { + c = line[i]; + if ( !sbitset( hdigits, c ) ) + break; + *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); + if ( i + 1 < nibbles && ( i & 1 ) ) + *++bp = 0; + } + + /* If any line has not enough columns, */ + /* indicate they have been padded with zero bits. */ + if ( i < nibbles && + !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding )); + p->flags |= BDF_GLYPH_WIDTH_CHECK_; + } + + /* Remove possible garbage at the right. */ + mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; + if ( glyph->bbx.width ) + *bp &= nibble_mask[mask_index]; + + /* If any line has extra columns, indicate they have been removed. */ + if ( i == nibbles && + sbitset( hdigits, line[nibbles] ) && + !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) + { + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding )); + p->flags |= BDF_GLYPH_WIDTH_CHECK_; + } + + p->row++; + goto Exit; + } + + /* Expect the SWIDTH (scalable width) field next. */ + if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->swidth = bdf_atous_( p->list.field[1] ); + p->flags |= BDF_SWIDTH_; + + goto Exit; + } + + /* Expect the DWIDTH (device width) field next. */ + if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->dwidth = bdf_atous_( p->list.field[1] ); + + if ( !( p->flags & BDF_SWIDTH_ ) ) + { + /* Missing SWIDTH field. Emit an auto correction message and set */ + /* the scalable width from the device width. */ + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno )); + + glyph->swidth = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + } + + p->flags |= BDF_DWIDTH_; + goto Exit; + } + + /* Expect the BBX field next. */ + if ( _bdf_strncmp( line, "BBX", 3 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + glyph->bbx.width = bdf_atous_( p->list.field[1] ); + glyph->bbx.height = bdf_atous_( p->list.field[2] ); + glyph->bbx.x_offset = bdf_atos_( p->list.field[3] ); + glyph->bbx.y_offset = bdf_atos_( p->list.field[4] ); + + /* Generate the ascent and descent of the character. */ + glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); + glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); + + /* Determine the overall font bounding box as the characters are */ + /* loaded so corrections can be done later if indicated. */ + p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); + p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); + + p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); + + p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); + p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); + p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); + + if ( !( p->flags & BDF_DWIDTH_ ) ) + { + /* Missing DWIDTH field. Emit an auto correction message and set */ + /* the device width to the glyph width. */ + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno )); + glyph->dwidth = glyph->bbx.width; + } + + /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ + /* value if necessary. */ + if ( p->opts->correct_metrics ) + { + /* Determine the point size of the glyph. */ + unsigned short sw = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + + + if ( sw != glyph->swidth ) + { + glyph->swidth = sw; + + p->flags |= BDF_SWIDTH_ADJ_; + } + } + + p->flags |= BDF_BBX_; + goto Exit; + } + + /* And finally, gather up the bitmap. */ + if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 ) + { + unsigned long bitmap_size; + + + if ( !( p->flags & BDF_BBX_ ) ) + { + /* Missing BBX field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" )); + error = FT_THROW( Missing_Bbx_Field ); + goto Exit; + } + + /* Allocate enough space for the bitmap. */ + glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; + + bitmap_size = glyph->bpr * glyph->bbx.height; + if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) + { + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno )); + error = FT_THROW( Bbx_Too_Big ); + goto Exit; + } + else + glyph->bytes = (unsigned short)bitmap_size; + + if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) ) + goto Exit; + + p->row = 0; + p->flags |= BDF_BITMAP_; + + goto Exit; + } + + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + Missing_Encoding: + /* Missing ENCODING field. */ + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" )); + error = FT_THROW( Missing_Encoding_Field ); + + Exit: + if ( error && ( p->flags & BDF_GLYPH_ ) ) + FT_FREE( p->glyph_name ); + + return error; + } + + + /* Load the font properties. */ + static FT_Error + bdf_parse_properties_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long vlen; + bdf_line_func_t_* next; + bdf_parse_t_* p; + char* name; + char* value; + char nbuf[BUFSIZE]; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + /* Check for the end of the properties. */ + if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) + { + /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ + /* encountered yet, then make sure they are added as properties and */ + /* make sure they are set from the font bounding box info. */ + /* */ + /* This is *always* done regardless of the options, because X11 */ + /* requires these two fields to compile fonts. */ + if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) + { + p->font->font_ascent = p->font->bbx.ascent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent ); + error = bdf_add_property_( p->font, "FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + + FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent )); + } + + if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) + { + p->font->font_descent = p->font->bbx.descent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent ); + error = bdf_add_property_( p->font, "FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + + FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent )); + } + + p->flags &= ~BDF_PROPS_; + *next = bdf_parse_glyphs_; + + goto Exit; + } + + /* Ignore the _XFREE86_GLYPH_RANGES properties. */ + if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) + goto Exit; + + /* Handle COMMENT fields and properties in a special way to preserve */ + /* the spacing. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + name = value = line; + value += 7; + if ( *value ) + *value++ = 0; + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) ) + { + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + name = p->list.field[0]; + + bdf_list_shift_( &p->list, 1 ); + value = bdf_list_join_( &p->list, ' ', &vlen ); + + error = bdf_add_property_( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + + Exit: + return error; + } + + + /* Load the font header. */ + static FT_Error + bdf_parse_start_( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long slen; + bdf_line_func_t_* next; + bdf_parse_t_* p; + bdf_font_t* font; + char *s; + + FT_Memory memory = NULL; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + next = (bdf_line_func_t_ *)call_data; + p = (bdf_parse_t_ *) client_data; + + if ( p->font ) + memory = p->font->memory; + + /* Check for a comment. This is done to handle those fonts that have */ + /* comments before the STARTFONT line for some reason. */ + if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments && p->font ) + { + linelen -= 7; + + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = bdf_add_comment_( p->font, s, linelen ); + } + goto Exit; + } + + if ( !( p->flags & BDF_START_ ) ) + { + memory = p->memory; + + if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 ) + { + /* we don't emit an error message since this code gets */ + /* explicitly caught one level higher */ + error = FT_THROW( Missing_Startfont_Field ); + goto Exit; + } + + p->flags = BDF_START_; + font = p->font = NULL; + + if ( FT_NEW( font ) ) + goto Exit; + p->font = font; + + font->memory = p->memory; + + { /* setup */ + size_t i; + bdf_property_t* prop; + + + error = ft_hash_str_init( &(font->proptbl), memory ); + if ( error ) + goto Exit; + for ( i = 0, prop = (bdf_property_t*)bdf_properties_; + i < num_bdf_properties_; i++, prop++ ) + { + error = ft_hash_str_insert( prop->name, i, + &(font->proptbl), memory ); + if ( error ) + goto Exit; + } + } + + if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) ) + goto Exit; + error = ft_hash_str_init( (FT_Hash)p->font->internal, memory ); + if ( error ) + goto Exit; + p->font->spacing = p->opts->font_spacing; + p->font->default_char = ~0UL; + + goto Exit; + } + + /* Check for the start of the properties. */ + if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 ) + { + if ( !( p->flags & BDF_FONT_BBX_ ) ) + { + /* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = FT_THROW( Missing_Fontboundingbox_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + /* at this point, `p->font' can't be NULL */ + p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] ); + /* We need at least 4 bytes per property. */ + if ( p->cnt > p->size / 4 ) + { + p->font->props_size = 0; + + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) + { + p->font->props_size = 0; + goto Exit; + } + + p->flags |= BDF_PROPS_; + *next = bdf_parse_properties_; + + goto Exit; + } + + /* Check for the FONTBOUNDINGBOX field. */ + if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) + { + if ( !( p->flags & BDF_SIZE_ ) ) + { + /* Missing the SIZE field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" )); + error = FT_THROW( Missing_Size_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->font->bbx.width = bdf_atous_( p->list.field[1] ); + p->font->bbx.height = bdf_atous_( p->list.field[2] ); + + p->font->bbx.x_offset = bdf_atos_( p->list.field[3] ); + p->font->bbx.y_offset = bdf_atos_( p->list.field[4] ); + + p->font->bbx.ascent = (short)( p->font->bbx.height + + p->font->bbx.y_offset ); + + p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); + + p->flags |= BDF_FONT_BBX_; + + goto Exit; + } + + /* The next thing to check for is the FONT field. */ + if ( _bdf_strncmp( line, "FONT", 4 ) == 0 ) + { + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + bdf_list_shift_( &p->list, 1 ); + + s = bdf_list_join_( &p->list, ' ', &slen ); + + if ( !s ) + { + FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ + FT_FREE( p->font->name ); + + if ( FT_DUP( p->font->name, s, slen + 1 ) ) + goto Exit; + + /* If the font name is an XLFD name, set the spacing to the one in */ + /* the font name. If there is no spacing fall back on the default. */ + error = bdf_set_default_spacing_( p->font, p->opts, lineno ); + if ( error ) + goto Exit; + + p->flags |= BDF_FONT_NAME_; + + goto Exit; + } + + /* Check for the SIZE field. */ + if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 ) + { + if ( !( p->flags & BDF_FONT_NAME_ ) ) + { + /* Missing the FONT field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" )); + error = FT_THROW( Missing_Font_Field ); + goto Exit; + } + + error = bdf_list_split_( &p->list, " +", line, linelen ); + if ( error ) + goto Exit; + + p->font->point_size = bdf_atoul_( p->list.field[1] ); + p->font->resolution_x = bdf_atoul_( p->list.field[2] ); + p->font->resolution_y = bdf_atoul_( p->list.field[3] ); + + /* Check for the bits per pixel field. */ + if ( p->list.used == 5 ) + { + unsigned short bpp; + + + bpp = bdf_atous_( p->list.field[4] ); + + /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */ + if ( bpp > 4 ) + p->font->bpp = 8; + else if ( bpp > 2 ) + p->font->bpp = 4; + else if ( bpp > 1 ) + p->font->bpp = 2; + else + p->font->bpp = 1; + + if ( p->font->bpp != bpp ) + FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp )); + } + else + p->font->bpp = 1; + + p->flags |= BDF_SIZE_; + + goto Exit; + } + + /* Check for the CHARS field -- font properties are optional */ + if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 ) + { + char nbuf[BUFSIZE]; + + + if ( !( p->flags & BDF_FONT_BBX_ ) ) + { + /* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = FT_THROW( Missing_Fontboundingbox_Field ); + goto Exit; + } + + /* Add the two standard X11 properties which are required */ + /* for compiling fonts. */ + p->font->font_ascent = p->font->bbx.ascent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent ); + error = bdf_add_property_( p->font, "FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent )); + + p->font->font_descent = p->font->bbx.descent; + ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent ); + error = bdf_add_property_( p->font, "FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent )); + + *next = bdf_parse_glyphs_; + + /* A special return value. */ + error = -1; + goto Exit; + } + + FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno )); + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + /************************************************************************** + * + * API. + * + */ + + + FT_LOCAL_DEF( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory memory, + bdf_options_t* opts, + bdf_font_t* *font ) + { + unsigned long lineno = 0; /* make compiler happy */ + bdf_parse_t_ *p = NULL; + + FT_Error error = FT_Err_Ok; + + + if ( FT_NEW( p ) ) + goto Exit; + + p->opts = (bdf_options_t*)( opts ? opts : &bdf_opts_ ); + p->minlb = 32767; + p->size = stream->size; + p->memory = memory; /* only during font creation */ + + bdf_list_init_( &p->list, memory ); + + error = bdf_readstream_( stream, bdf_parse_start_, + (void *)p, &lineno ); + if ( error ) + goto Fail; + + if ( p->font ) + { + /* If the font is not proportional, set the font's monowidth */ + /* field to the width of the font bounding box. */ + + if ( p->font->spacing != BDF_PROPORTIONAL ) + p->font->monowidth = p->font->bbx.width; + + /* If the number of glyphs loaded is not that of the original count, */ + /* indicate the difference. */ + if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, + p->font->glyphs_used + p->font->unencoded_used )); + } + + /* Once the font has been loaded, adjust the overall font metrics if */ + /* necessary. */ + if ( p->opts->correct_metrics != 0 && + ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) + { + if ( p->maxrb - p->minlb != p->font->bbx.width ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG3, + p->font->bbx.width, p->maxrb - p->minlb )); + p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); + } + + if ( p->font->bbx.x_offset != p->minlb ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG4, + p->font->bbx.x_offset, p->minlb )); + p->font->bbx.x_offset = p->minlb; + } + + if ( p->font->bbx.ascent != p->maxas ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG5, + p->font->bbx.ascent, p->maxas )); + p->font->bbx.ascent = p->maxas; + } + + if ( p->font->bbx.descent != p->maxds ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG6, + p->font->bbx.descent, p->maxds )); + p->font->bbx.descent = p->maxds; + p->font->bbx.y_offset = (short)( -p->maxds ); + } + + if ( p->maxas + p->maxds != p->font->bbx.height ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG7, + p->font->bbx.height, p->maxas + p->maxds )); + p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); + } + + if ( p->flags & BDF_SWIDTH_ADJ_ ) + FT_TRACE2(( "bdf_load_font: " ACMSG8 )); + } + } + + if ( p->flags & BDF_START_ ) + { + /* The ENDFONT field was never reached or did not exist. */ + if ( !( p->flags & BDF_GLYPHS_ ) ) + { + /* Error happened while parsing header. */ + FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); + error = FT_THROW( Corrupted_Font_Header ); + goto Fail; + } + else + { + /* Error happened when parsing glyphs. */ + FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); + error = FT_THROW( Corrupted_Font_Glyphs ); + goto Fail; + } + } + + if ( !p->font && !error ) + error = FT_THROW( Invalid_File_Format ); + + *font = p->font; + + Exit: + if ( p ) + { + bdf_list_done_( &p->list ); + + FT_FREE( p->glyph_name ); + FT_FREE( p ); + } + + return error; + + Fail: + bdf_free_font( p->font ); + + FT_FREE( p->font ); + + goto Exit; + } + + + FT_LOCAL_DEF( void ) + bdf_free_font( bdf_font_t* font ) + { + bdf_property_t* prop; + unsigned long i; + bdf_glyph_t* glyphs; + FT_Memory memory; + + + if ( font == NULL ) + return; + + memory = font->memory; + + FT_FREE( font->name ); + + /* Free up the internal hash table of property names. */ + if ( font->internal ) + { + ft_hash_str_free( (FT_Hash)font->internal, memory ); + FT_FREE( font->internal ); + } + + /* Free up the comment info. */ + FT_FREE( font->comments ); + + /* Free up the properties. */ + for ( i = 0; i < font->props_size; i++ ) + { + if ( font->props[i].format == BDF_ATOM ) + FT_FREE( font->props[i].value.atom ); + } + + FT_FREE( font->props ); + + /* Free up the character info. */ + for ( i = 0, glyphs = font->glyphs; + i < font->glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; + i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + + FT_FREE( font->glyphs ); + FT_FREE( font->unencoded ); + + /* bdf_cleanup */ + ft_hash_str_free( &(font->proptbl), memory ); + + /* Free up the user defined properties. */ + for ( prop = font->user_props, i = 0; + i < font->nuser_props; i++, prop++ ) + FT_FREE( prop->name ); + + FT_FREE( font->user_props ); + + /* FREE( font ); */ /* XXX Fixme */ + } + + + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ) + { + size_t* propid; + + + if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 ) + return 0; + + propid = ft_hash_str_lookup( name, (FT_Hash)font->internal ); + + return propid ? ( font->props + *propid ) : 0; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/bzip2/ftbzip2.c b/Dependencies/freetype/freetype/src/bzip2/ftbzip2.c new file mode 100644 index 00000000..a0249eb8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/bzip2/ftbzip2.c @@ -0,0 +1,535 @@ +/**************************************************************************** + * + * ftbzip2.c + * + * FreeType support for .bz2 compressed files. + * + * This optional component relies on libbz2. It should mainly be used to + * parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2010-2024 by + * Joel Klinghed. + * + * based on `src/gzip/ftgzip.c' + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Bzip2_Err_ +#define FT_ERR_BASE FT_Mod_Err_Bzip2 + +#include + + +#ifdef FT_CONFIG_OPTION_USE_BZIP2 + +#define BZ_NO_STDIO /* Do not need FILE */ +#include + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + typedef void* (*alloc_func)( void*, int, int ); + typedef void (*free_func) ( void*, void* ); + + + static void* + ft_bzip2_alloc( void* memory_, /* FT_Memory */ + int items, + int size ) + { + FT_Memory memory = (FT_Memory)memory_; + + FT_ULong sz = (FT_ULong)size * (FT_ULong)items; + FT_Error error; + FT_Pointer p = NULL; + + + FT_MEM_QALLOC( p, sz ); + return p; + } + + + static void + ft_bzip2_free( void* memory_, /* FT_Memory */ + void* address ) + { + FT_Memory memory = (FT_Memory)memory_; + + + FT_MEM_FREE( address ); + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_BZIP2_BUFFER_SIZE 4096 + + typedef struct FT_BZip2FileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + bz_stream bzstream; /* bzlib input stream */ + + FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + FT_Bool reset; /* reset before next read */ + + } FT_BZip2FileRec, *FT_BZip2File; + + + /* check and skip .bz2 header - we don't support `transparent' compression */ + static FT_Error + ft_bzip2_check_header( FT_Stream stream ) + { + FT_Error error = FT_Err_Ok; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the version, and head[3] the blocksize */ + if ( head[0] != 0x42 || + head[1] != 0x5A || + head[2] != 0x68 ) /* only support bzip2 (huffman) */ + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + Exit: + return error; + } + + + static FT_Error + ft_bzip2_file_init( FT_BZip2File zip, + FT_Stream stream, + FT_Stream source ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + /* check .bz2 header */ + { + stream = source; + + error = ft_bzip2_check_header( stream ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + } + + /* initialize bzlib */ + bzstream->bzalloc = ft_bzip2_alloc; + bzstream->bzfree = ft_bzip2_free; + bzstream->opaque = zip->memory; + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->buffer; + + if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK || + !bzstream->next_in ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static void + ft_bzip2_file_done( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + /* clear the rest */ + bzstream->bzalloc = NULL; + bzstream->bzfree = NULL; + bzstream->opaque = NULL; + bzstream->next_in = NULL; + bzstream->next_out = NULL; + bzstream->avail_in = 0; + bzstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_bzip2_file_reset( FT_BZip2File zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->input; + bzstream->avail_out = 0; + bzstream->next_out = (char*)zip->buffer; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + BZ2_bzDecompressInit( bzstream, 0, 0 ); + } + + return error; + } + + + static FT_Error + ft_bzip2_file_fill_input( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_BZIP2_BUFFER_SIZE ); + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + } + else + { + size = stream->size - stream->pos; + if ( size > FT_BZIP2_BUFFER_SIZE ) + size = FT_BZIP2_BUFFER_SIZE; + + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + bzstream->next_in = (char*)zip->input; + bzstream->avail_in = size; + + return FT_Err_Ok; + } + + + static FT_Error + ft_bzip2_file_fill_output( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + bzstream->next_out = (char*)zip->cursor; + bzstream->avail_out = FT_BZIP2_BUFFER_SIZE; + + while ( bzstream->avail_out > 0 ) + { + int err; + + + if ( bzstream->avail_in == 0 ) + { + error = ft_bzip2_file_fill_input( zip ); + if ( error ) + break; + } + + err = BZ2_bzDecompress( bzstream ); + + if ( err != BZ_OK ) + { + zip->reset = 1; + + if ( err == BZ_STREAM_END ) + { + zip->limit = (FT_Byte*)bzstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */ + static FT_Error + ft_bzip2_file_skip_output( FT_BZip2File zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + for (;;) + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_bzip2_file_io( FT_BZip2File zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if seeking backwards or bzip reported an error. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos || zip->reset ) + { + error = ft_bzip2_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_bzip2_stream_close( FT_Stream stream ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize bzip file descriptor */ + ft_bzip2_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static unsigned long + ft_bzip2_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + + + return ft_bzip2_file_io( zip, offset, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_BZip2File zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * check the header right now; this prevents allocating unnecessary + * objects when we don't need them + */ + error = ft_bzip2_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_bzip2_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = NULL; + stream->read = ft_bzip2_stream_io; + stream->close = ft_bzip2_stream_close; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcache.c b/Dependencies/freetype/freetype/src/cache/ftcache.c new file mode 100644 index 00000000..81e0347a --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcache.c @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * ftcache.c + * + * The FreeType Caching sub-system (body only). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftcbasic.c" +#include "ftccache.c" +#include "ftccmap.c" +#include "ftcglyph.c" +#include "ftcimage.c" +#include "ftcmanag.c" +#include "ftcmru.c" +#include "ftcsbits.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcbasic.c b/Dependencies/freetype/freetype/src/cache/ftcbasic.c new file mode 100644 index 00000000..7102d3d2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcbasic.c @@ -0,0 +1,598 @@ +/**************************************************************************** + * + * ftcbasic.c + * + * The FreeType basic cache interface (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftcglyph.h" +#include "ftcimage.h" +#include "ftcsbits.h" + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /* + * Basic Families + * + */ + typedef struct FTC_BasicAttrRec_ + { + FTC_ScalerRec scaler; + FT_Int32 load_flags; + + } FTC_BasicAttrRec, *FTC_BasicAttrs; + +#define FTC_BASIC_ATTR_COMPARE( a, b ) \ + FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \ + (a)->load_flags == (b)->load_flags ) + +#define FTC_BASIC_ATTR_HASH( a ) \ + ( FTC_SCALER_HASH( &(a)->scaler ) + \ + (FT_Offset)( 31 * (a)->load_flags ) ) + + + typedef struct FTC_BasicQueryRec_ + { + FTC_GQueryRec gquery; + FTC_BasicAttrRec attrs; + + } FTC_BasicQueryRec, *FTC_BasicQuery; + + + typedef struct FTC_BasicFamilyRec_ + { + FTC_FamilyRec family; + FTC_BasicAttrRec attrs; + + } FTC_BasicFamilyRec, *FTC_BasicFamily; + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_family_compare( FTC_MruNode ftcfamily, + FT_Pointer ftcquery ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + + + return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_init( FTC_MruNode ftcfamily, + FT_Pointer ftcquery, + FT_Pointer ftccache ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; + FTC_Cache cache = (FTC_Cache)ftccache; + + + FTC_Family_Init( FTC_FAMILY( family ), cache ); + family->attrs = query->attrs; + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ftc_basic_family_get_count( FTC_Family ftcfamily, + FTC_Manager manager ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Face face; + FT_UInt result = 0; + + + error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, + &face ); + + if ( error || !face ) + return result; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs ) + { + FT_TRACE1(( "ftc_basic_family_get_count:" + " the number of glyphs in this face is %ld,\n", + face->num_glyphs )); + FT_TRACE1(( " " + " which is too much and thus truncated\n" )); + } +#endif + + result = (FT_UInt)face->num_glyphs; + + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_bitmap( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FT_Size size; + + + error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); + if ( !error ) + { + FT_Face face = size->face; + + + error = FT_Load_Glyph( face, + gindex, + family->attrs.load_flags | FT_LOAD_RENDER ); + if ( !error ) + *aface = face; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_basic_family_load_glyph( FTC_Family ftcfamily, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ) + { + FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; + FT_Error error; + FTC_Scaler scaler = &family->attrs.scaler; + FT_Face face; + FT_Size size; + + + /* we will now load the glyph image */ + error = FTC_Manager_LookupSize( cache->manager, + scaler, + &size ); + if ( !error ) + { + face = size->face; + + error = FT_Load_Glyph( face, gindex, family->attrs.load_flags ); + if ( !error ) + { + if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || + face->glyph->format == FT_GLYPH_FORMAT_OUTLINE || + face->glyph->format == FT_GLYPH_FORMAT_SVG ) + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if ( !error ) + { + *aglyph = glyph; + goto Exit; + } + } + else + error = FT_THROW( Invalid_Argument ); + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, + FT_Pointer ftcface_id, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; + FT_Bool result; + + + if ( list_changed ) + *list_changed = FALSE; + result = FT_BOOL( family->attrs.scaler.face_id == face_id ); + if ( result ) + { + /* we must call this function to avoid this node from appearing + * in later lookups with the same face_id! + */ + FTC_GNode_UnselectFamily( gnode, cache ); + } + return result; + } + + + /* + * + * basic image cache + * + */ + + static + const FTC_IFamilyClassRec ftc_basic_image_family_class = + { + { + sizeof ( FTC_BasicFamilyRec ), + + ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ + NULL /* FTC_MruNode_DoneFunc node_done */ + }, + + ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc family_load_glyph */ + }; + + + static + const FTC_GCacheClassRec ftc_basic_image_cache_class = + { + { + ftc_inode_new, /* FTC_Node_NewFunc node_new */ + ftc_inode_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_gnode_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_inode_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ + }, + + (FTC_MruListClass)&ftc_basic_image_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_image_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ + FT_Offset hash; + + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !aglyph ) + return FT_THROW( Invalid_Argument ); + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = type->flags; + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + +#ifdef FTC_INLINE /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_gnode_compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, gindex, + FTC_GQUERY( &query ), + &node ); +#endif + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + } + + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_ImageCache_LookupScaler( FTC_ImageCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ + FT_Offset hash; + + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !aglyph || !scaler ) + return FT_THROW( Invalid_Argument ); + + *aglyph = NULL; + if ( anode ) + *anode = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', + * but public `FT_Face->face_flags' is of type `FT_Long'. + * + * On long > int systems, higher bits of load_flags cannot be handled. + */ +#if FT_ULONG_MAX > 0xFFFFFFFFUL + if ( load_flags > 0xFFFFFFFFUL ) + FT_TRACE1(( "FTC_ImageCache_LookupScaler:" + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~0xFFFFFFFFUL )); +#endif + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = (FT_Int32)load_flags; + + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_gnode_compare, + hash, gindex, + &query, + node, + error ); + if ( !error ) + { + *aglyph = FTC_INODE( node )->glyph; + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + } + + return error; + } + + + /* + * + * basic small bitmap cache + * + */ + + static + const FTC_SFamilyClassRec ftc_basic_sbit_family_class = + { + { + sizeof ( FTC_BasicFamilyRec ), + ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ + NULL /* FTC_MruNode_DoneFunc node_done */ + }, + + ftc_basic_family_get_count, + ftc_basic_family_load_bitmap + }; + + + static + const FTC_GCacheClassRec ftc_basic_sbit_cache_class = + { + { + ftc_snode_new, /* FTC_Node_NewFunc node_new */ + ftc_snode_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_snode_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_snode_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_GCacheRec ), + ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ + }, + + (FTC_MruListClass)&ftc_basic_sbit_family_class + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ) + { + return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class, + (FTC_GCache*)acache ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ + FT_Offset hash; + + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !ansbit ) + return FT_THROW( Invalid_Argument ); + + *ansbit = NULL; + if ( anode ) + *anode = NULL; + + query.attrs.scaler.face_id = type->face_id; + query.attrs.scaler.width = type->width; + query.attrs.scaler.height = type->height; + query.attrs.load_flags = type->flags; + + query.attrs.scaler.pixel = 1; + query.attrs.scaler.x_res = 0; /* make compilers happy */ + query.attrs.scaler.y_res = 0; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + +#ifdef FTC_INLINE /* inlining is about 50% faster! */ + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_snode_compare, + hash, gindex, + &query, + node, + error ); +#else + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), + hash, + gindex, + FTC_GQUERY( &query ), + &node ); +#endif + if ( error ) + goto Exit; + + *ansbit = FTC_SNODE( node )->sbits + + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_SBitCache_LookupScaler( FTC_SBitCache cache, + FTC_Scaler scaler, + FT_ULong load_flags, + FT_UInt gindex, + FTC_SBit *ansbit, + FTC_Node *anode ) + { + FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ + FT_Offset hash; + + + /* other argument checks delayed to `FTC_Cache_Lookup' */ + if ( !ansbit || !scaler ) + return FT_THROW( Invalid_Argument ); + + *ansbit = NULL; + if ( anode ) + *anode = NULL; + + /* + * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', + * but public `FT_Face->face_flags' is of type `FT_Long'. + * + * On long > int systems, higher bits of load_flags cannot be handled. + */ +#if FT_ULONG_MAX > 0xFFFFFFFFUL + if ( load_flags > 0xFFFFFFFFUL ) + FT_TRACE1(( "FTC_ImageCache_LookupScaler:" + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~0xFFFFFFFFUL )); +#endif + + query.attrs.scaler = scaler[0]; + query.attrs.load_flags = (FT_Int32)load_flags; + + /* beware, the hash must be the same for all glyph ranges! */ + hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + + gindex / FTC_SBIT_ITEMS_PER_NODE; + + FTC_GCACHE_LOOKUP_CMP( cache, + ftc_basic_family_compare, + ftc_snode_compare, + hash, gindex, + &query, + node, + error ); + if ( error ) + goto Exit; + + *ansbit = FTC_SNODE( node )->sbits + + ( gindex - FTC_GNODE( node )->gindex ); + + if ( anode ) + { + *anode = node; + node->ref_count++; + } + + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftccache.c b/Dependencies/freetype/freetype/src/cache/ftccache.c new file mode 100644 index 00000000..8a3d887f --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftccache.c @@ -0,0 +1,584 @@ +/**************************************************************************** + * + * ftccache.c + * + * The FreeType internal cache interface (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "ftcmanag.h" +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + +#define FTC_HASH_MAX_LOAD 2 +#define FTC_HASH_MIN_LOAD 1 +#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) + + /* this one _must_ be a power of 2! */ +#define FTC_HASH_INITIAL_SIZE 8 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* add a new node to the head of the manager's circular MRU list */ + static void + ftc_node_mru_link( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Prepend( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes++; + } + + + /* remove a node from the manager's MRU list */ + static void + ftc_node_mru_unlink( FTC_Node node, + FTC_Manager manager ) + { + void *nl = &manager->nodes_list; + + + FTC_MruNode_Remove( (FTC_MruNode*)nl, + (FTC_MruNode)node ); + manager->num_nodes--; + } + + +#ifndef FTC_INLINE + + /* move a node to the head of the manager's MRU list */ + static void + ftc_node_mru_up( FTC_Node node, + FTC_Manager manager ) + { + FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, + (FTC_MruNode)node ); + } + + + /* get a top bucket for specified hash from cache, + * body for FTC_NODE_TOP_FOR_HASH( cache, hash ) + */ + FT_LOCAL_DEF( FTC_Node* ) + ftc_get_top_node_for_hash( FTC_Cache cache, + FT_Offset hash ) + { + FT_Offset idx; + + + idx = hash & cache->mask; + if ( idx >= cache->p ) + idx = hash & ( cache->mask >> 1 ); + + return cache->buckets + idx; + } + +#endif /* !FTC_INLINE */ + + + /* Note that this function cannot fail. If we cannot re-size the + * buckets array appropriately, we simply degrade the hash table's + * performance! + */ + static void + ftc_cache_resize( FTC_Cache cache ) + { + for (;;) + { + FTC_Node node, *pnode; + FT_UFast p = cache->p; + FT_UFast size = cache->mask + 1; /* available size */ + FT_UFast half = size >> 1; + + + /* do we need to expand the buckets array? */ + if ( cache->slack < 0 ) + { + FTC_Node new_list = NULL; + + + /* try to expand the buckets array _before_ splitting + * the bucket lists + */ + if ( p == size ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't expand the array, leave immediately */ + if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) ) + break; + + cache->mask = 2 * size - 1; + half = size; + } + + /* the bucket to split */ + pnode = cache->buckets + p - half; + + for (;;) + { + node = *pnode; + if ( !node ) + break; + + if ( node->hash & half ) + { + *pnode = node->link; + node->link = new_list; + new_list = node; + } + else + pnode = &node->link; + } + + cache->buckets[p] = new_list; + + cache->slack += FTC_HASH_MAX_LOAD; + cache->p = p + 1; + + FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n", + cache->index, cache->p )); + } + + /* do we need to shrink the buckets array? */ + else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD ) + { + FTC_Node old_list = cache->buckets[--p]; + + + if ( p < FTC_HASH_INITIAL_SIZE ) + break; + + if ( p == half ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + /* if we can't shrink the array, leave immediately */ + if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) ) + break; + + cache->mask = half - 1; + } + + /* the bucket to merge */ + pnode = cache->buckets + p - half; + + while ( *pnode ) + pnode = &(*pnode)->link; + + *pnode = old_list; + + cache->slack -= FTC_HASH_MAX_LOAD; + cache->p = p; + + FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n", + cache->index, cache->p )); + } + + /* otherwise, the hash table is balanced */ + else + break; + } + } + + + /* remove a node from its cache's hash table */ + static void + ftc_node_hash_unlink( FTC_Node node0, + FTC_Cache cache ) + { + FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node0->hash ); + + + for (;;) + { + FTC_Node node = *pnode; + + + if ( !node ) + { + FT_TRACE0(( "ftc_node_hash_unlink: unknown node\n" )); + return; + } + + if ( node == node0 ) + break; + + pnode = &node->link; + } + + *pnode = node0->link; + node0->link = NULL; + + cache->slack++; + ftc_cache_resize( cache ); + } + + + /* add a node to the `top' of its cache's hash table */ + static void + ftc_node_hash_link( FTC_Node node, + FTC_Cache cache ) + { + FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node->hash ); + + + node->link = *pnode; + *pnode = node; + + cache->slack--; + ftc_cache_resize( cache ); + } + + + /* remove a node from the cache manager */ + FT_LOCAL_DEF( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ) + { + FTC_Cache cache; + + +#ifdef FT_DEBUG_ERROR + /* find node's cache */ + if ( node->cache_index >= manager->num_caches ) + { + FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + cache = manager->caches[node->cache_index]; + +#ifdef FT_DEBUG_ERROR + if ( !cache ) + { + FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" )); + return; + } +#endif + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* remove node from cache's hash table */ + ftc_node_hash_unlink( node, cache ); + + /* now finalize it */ + cache->clazz.node_free( node, cache ); + +#if 0 + /* check, just in case of general corruption :-) */ + if ( manager->num_nodes == 0 ) + FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%u)\n", + manager->num_nodes )); +#endif + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ABSTRACT CACHE CLASS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + ftc_cache_init( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + + + cache->p = FTC_HASH_INITIAL_SIZE; + cache->mask = FTC_HASH_INITIAL_SIZE - 1; + cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; + + FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE ); + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) + { + return ftc_cache_init( cache ); + } + + + FT_LOCAL_DEF( void ) + ftc_cache_done( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + + + if ( cache->buckets ) + { + FTC_Manager manager = cache->manager; + FT_UFast count = cache->p; + FT_UFast i; + + + for ( i = 0; i < count; i++ ) + { + FTC_Node node = cache->buckets[i], next; + + + while ( node ) + { + next = node->link; + node->link = NULL; + + /* remove node from mru list */ + ftc_node_mru_unlink( node, manager ); + + /* now finalize it */ + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + + cache->clazz.node_free( node, cache ); + node = next; + } + } + } + + FT_FREE( cache->buckets ); + + cache->p = 0; + cache->mask = 0; + cache->slack = 0; + } + + + FT_LOCAL_DEF( void ) + FTC_Cache_Done( FTC_Cache cache ) + { + ftc_cache_done( cache ); + } + + + static void + ftc_cache_add( FTC_Cache cache, + FT_Offset hash, + FTC_Node node ) + { + node->hash = hash; + node->cache_index = (FT_UShort)cache->index; + node->ref_count = 0; + + ftc_node_hash_link( node, cache ); + ftc_node_mru_link( node, cache->manager ); + + { + FTC_Manager manager = cache->manager; + + + manager->cur_weight += cache->clazz.node_weight( node, cache ); + + if ( manager->cur_weight >= manager->max_weight ) + { + node->ref_count++; + FTC_Manager_Compress( manager ); + node->ref_count--; + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ) + { + FT_Error error; + FTC_Node node; + + + /* + * We use the FTC_CACHE_TRYLOOP macros to support out-of-memory + * errors (OOM) correctly, i.e., by flushing the cache progressively + * in order to make more room. + */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = cache->clazz.node_new( &node, query, cache ); + } + FTC_CACHE_TRYLOOP_END( NULL ) + + if ( error ) + node = NULL; + else + { + /* don't assume that the cache has the same number of buckets, since + * our allocation request might have triggered global cache flushing + */ + ftc_cache_add( cache, hash, node ); + } + + *anode = node; + return error; + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ) + { + FTC_Node* bucket; + FTC_Node* pnode; + FTC_Node node; + FT_Error error = FT_Err_Ok; + FT_Bool list_changed = FALSE; + + FTC_Node_CompareFunc compare = cache->clazz.node_compare; + + + if ( !cache || !anode ) + return FT_THROW( Invalid_Argument ); + + /* Go to the `top' node of the list sharing same masked hash */ + bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash ); + + /* Lookup a node with exactly same hash and queried properties. */ + /* NOTE: _nodcomp() may change the linked list to reduce memory. */ + for (;;) + { + node = *pnode; + if ( !node ) + goto NewNode; + + if ( node->hash == hash && + compare( node, query, cache, &list_changed ) ) + break; + + pnode = &node->link; + } + + if ( list_changed ) + { + /* Update bucket by modified linked list */ + bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash ); + + /* Update pnode by modified linked list */ + while ( *pnode != node ) + { + if ( !*pnode ) + { + FT_ERROR(( "FTC_Cache_Lookup: oops!!! node missing\n" )); + goto NewNode; + } + else + pnode = &(*pnode)->link; + } + } + + /* Reorder the list to move the found node to the `top' */ + if ( node != *bucket ) + { + *pnode = node->link; + node->link = *bucket; + *bucket = node; + } + + /* move to head of MRU list */ + { + FTC_Manager manager = cache->manager; + + + if ( node != manager->nodes_list ) + ftc_node_mru_up( node, manager ); + } + *anode = node; + + return error; + + NewNode: + return FTC_Cache_NewNode( cache, hash, query, anode ); + } + +#endif /* !FTC_INLINE */ + + + FT_LOCAL_DEF( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ) + { + FTC_Manager manager = cache->manager; + FT_UFast count = cache->p; + FT_UFast i; + + + for ( i = 0; i < count; i++ ) + { + FTC_Node* pnode = cache->buckets + i; + + + for (;;) + { + FTC_Node node = *pnode; + + + if ( !node ) + break; + + if ( cache->clazz.node_remove_faceid( node, face_id, cache, NULL ) ) + { + *pnode = node->link; + + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + ftc_node_mru_unlink( node, manager ); + + cache->clazz.node_free( node, cache ); + + cache->slack++; + } + else + pnode = &node->link; + } + } + + ftc_cache_resize( cache ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftccache.h b/Dependencies/freetype/freetype/src/cache/ftccache.h new file mode 100644 index 00000000..85d321c1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftccache.h @@ -0,0 +1,359 @@ +/**************************************************************************** + * + * ftccache.h + * + * FreeType internal cache interface (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCCACHE_H_ +#define FTCCACHE_H_ + +#include +#include "ftcmru.h" + +FT_BEGIN_HEADER + +#define FTC_FACE_ID_HASH( i ) \ + ( ( (FT_Offset)(i) >> 3 ) ^ ( (FT_Offset)(i) << 7 ) ) + + /* handle to cache object */ + typedef struct FTC_CacheRec_* FTC_Cache; + + /* handle to cache class */ + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * Each cache controls one or more cache nodes. Each node is part of + * the global_lru list of the manager. Its `data' field however is used + * as a reference count for now. + * + * A node can be anything, depending on the type of information held by + * the cache. It can be an individual glyph image, a set of bitmaps + * glyphs for a given size, some metrics, etc. + * + */ + + /* structure size should be 20 bytes on 32-bits machines */ + typedef struct FTC_NodeRec_ + { + FTC_MruNodeRec mru; /* circular mru list pointer */ + FTC_Node link; /* used for hashing */ + FT_Offset hash; /* used for hashing too */ + FT_UShort cache_index; /* index of cache the node belongs to */ + FT_Short ref_count; /* reference count for this node */ + + } FTC_NodeRec; + + +#define FTC_NODE( x ) ( (FTC_Node)(x) ) +#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) + +#define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next ) +#define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev ) + + /* address the hash table entries */ +#ifdef FTC_INLINE +#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ + ( ( cache )->buckets + \ + ( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \ + ? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \ + : ( ( hash ) & ( cache )->mask ) ) ) +#else + FT_LOCAL( FTC_Node* ) + ftc_get_top_node_for_hash( FTC_Cache cache, + FT_Offset hash ); +#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ + ftc_get_top_node_for_hash( ( cache ), ( hash ) ) +#endif + + FT_LOCAL( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* initialize a new cache node */ + typedef FT_Error + (*FTC_Node_NewFunc)( FTC_Node *pnode, + FT_Pointer query, + FTC_Cache cache ); + + typedef FT_Offset + (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); + + /* compare a node to a given key pair */ + typedef FT_Bool + (*FTC_Node_CompareFunc)( FTC_Node node, + FT_Pointer key, + FTC_Cache cache, + FT_Bool* list_changed ); + + + typedef void + (*FTC_Node_FreeFunc)( FTC_Node node, + FTC_Cache cache ); + + typedef FT_Error + (*FTC_Cache_InitFunc)( FTC_Cache cache ); + + typedef void + (*FTC_Cache_DoneFunc)( FTC_Cache cache ); + + + typedef struct FTC_CacheClassRec_ + { + FTC_Node_NewFunc node_new; + FTC_Node_WeightFunc node_weight; + FTC_Node_CompareFunc node_compare; + FTC_Node_CompareFunc node_remove_faceid; + FTC_Node_FreeFunc node_free; + + FT_Offset cache_size; + FTC_Cache_InitFunc cache_init; + FTC_Cache_DoneFunc cache_done; + + } FTC_CacheClassRec; + + + /* each cache really implements a hash table to manage its nodes */ + /* the number of the table entries (buckets) can change dynamically */ + /* each bucket contains a linked lists of nodes for a given hash */ + typedef struct FTC_CacheRec_ + { + FT_UFast p; /* hash table counter */ + FT_UFast mask; /* hash table index range */ + FT_Long slack; + FTC_Node* buckets; + + FTC_CacheClassRec clazz; /* local copy, for speed */ + + FTC_Manager manager; + FT_Memory memory; + FT_UInt index; /* in manager's table */ + + FTC_CacheClass org_class; /* original class pointer */ + + } FTC_CacheRec; + + +#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) +#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) + + + /* default cache initialize */ + FT_LOCAL( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); + + /* default cache finalizer */ + FT_LOCAL( void ) + FTC_Cache_Done( FTC_Cache cache ); + + /* Call this function to look up the cache. If no corresponding + * node is found, a new one is automatically created. This function + * is capable of flushing the cache adequately to make room for the + * new cache object. + */ + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_Cache_Lookup( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ); +#endif + + FT_LOCAL( FT_Error ) + FTC_Cache_NewNode( FTC_Cache cache, + FT_Offset hash, + FT_Pointer query, + FTC_Node *anode ); + + /* Remove all nodes that relate to a given face_id. This is useful + * when un-installing fonts. Note that if a cache node relates to + * the face_id but is locked (i.e., has `ref_count > 0'), the node + * will _not_ be destroyed, but its internal face_id reference will + * be modified. + * + * The final result will be that the node will never come back + * in further lookup requests, and will be flushed on demand from + * the cache normally when its reference count reaches 0. + */ + FT_LOCAL( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ); + + +#ifdef FTC_INLINE + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_Node *_bucket, *_pnode, _node; \ + FTC_Cache _cache = FTC_CACHE( cache ); \ + FT_Offset _hash = (FT_Offset)(hash); \ + FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ + FT_Bool _list_changed = FALSE; \ + \ + \ + error = FT_Err_Ok; \ + node = NULL; \ + \ + /* Go to the `top' node of the list sharing same masked hash */ \ + _bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \ + \ + /* Look up a node with identical hash and queried properties. */ \ + /* NOTE: _nodcomp() may change the linked list to reduce memory. */ \ + for (;;) \ + { \ + _node = *_pnode; \ + if ( !_node ) \ + goto NewNode_; \ + \ + if ( _node->hash == _hash && \ + _nodcomp( _node, query, _cache, &_list_changed ) ) \ + break; \ + \ + _pnode = &_node->link; \ + } \ + \ + if ( _list_changed ) \ + { \ + /* Update _bucket by possibly modified linked list */ \ + _bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \ + \ + /* Update _pnode by possibly modified linked list */ \ + while ( *_pnode != _node ) \ + { \ + if ( !*_pnode ) \ + { \ + FT_ERROR(( "FTC_CACHE_LOOKUP_CMP: oops!!! node missing\n" )); \ + goto NewNode_; \ + } \ + else \ + _pnode = &(*_pnode)->link; \ + } \ + } \ + \ + /* Reorder the list to move the found node to the `top' */ \ + if ( _node != *_bucket ) \ + { \ + *_pnode = _node->link; \ + _node->link = *_bucket; \ + *_bucket = _node; \ + } \ + \ + /* Update MRU list */ \ + { \ + FTC_Manager _manager = _cache->manager; \ + void* _nl = &_manager->nodes_list; \ + \ + \ + if ( _node != _manager->nodes_list ) \ + FTC_MruNode_Up( (FTC_MruNode*)_nl, \ + (FTC_MruNode)_node ); \ + } \ + goto Ok_; \ + \ + NewNode_: \ + error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ + \ + Ok_: \ + node = _node; \ + FT_END_STMNT + +#else /* !FTC_INLINE */ + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, \ + (FTC_Node*)&(node) ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + + /* + * This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry + * loop to flush the cache repeatedly in case of memory overflows. + * + * It is used when creating a new cache node, or within a lookup + * that needs to allocate data (e.g. the sbit cache lookup). + * + * Example: + * + * { + * FTC_CACHE_TRYLOOP( cache ) + * error = load_data( ... ); + * FTC_CACHE_TRYLOOP_END() + * } + * + */ +#define FTC_CACHE_TRYLOOP( cache ) \ + { \ + FTC_Manager _try_manager = FTC_CACHE( cache )->manager; \ + FT_UInt _try_count = 4; \ + \ + \ + for (;;) \ + { \ + FT_UInt _try_done; + + +#define FTC_CACHE_TRYLOOP_END( list_changed ) \ + if ( !error || FT_ERR_NEQ( error, Out_Of_Memory ) ) \ + break; \ + \ + _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \ + if ( _try_done > 0 && list_changed != NULL ) \ + *(FT_Bool*)( list_changed ) = TRUE; \ + \ + if ( _try_done == 0 ) \ + break; \ + \ + if ( _try_done == _try_count ) \ + { \ + _try_count *= 2; \ + if ( _try_count < _try_done || \ + _try_count > _try_manager->num_nodes ) \ + _try_count = _try_manager->num_nodes; \ + } \ + } \ + } + + /* */ + +FT_END_HEADER + + +#endif /* FTCCACHE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftccback.h b/Dependencies/freetype/freetype/src/cache/ftccback.h new file mode 100644 index 00000000..a1d76baa --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftccback.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * + * ftccback.h + * + * Callback functions of the caching sub-system (specification only). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTCCBACK_H_ +#define FTCCBACK_H_ + +#include +#include "ftccache.h" + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + ftc_inode_free( FTC_Node inode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_inode_new( FTC_Node *pinode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_Offset ) + ftc_inode_weight( FTC_Node inode, + FTC_Cache cache ); + + + FT_LOCAL( void ) + ftc_snode_free( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + ftc_snode_new( FTC_Node *psnode, + FT_Pointer gquery, + FTC_Cache cache ); + + FT_LOCAL( FT_Offset ) + ftc_snode_weight( FTC_Node snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Bool ) + ftc_snode_compare( FTC_Node snode, + FT_Pointer gquery, + FTC_Cache cache, + FT_Bool* list_changed ); + + + FT_LOCAL( FT_Bool ) + ftc_gnode_compare( FTC_Node gnode, + FT_Pointer gquery, + FTC_Cache cache, + FT_Bool* list_changed ); + + + FT_LOCAL( FT_Error ) + ftc_gcache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_gcache_done( FTC_Cache cache ); + + + FT_LOCAL( FT_Error ) + ftc_cache_init( FTC_Cache cache ); + + FT_LOCAL( void ) + ftc_cache_done( FTC_Cache cache ); + +FT_END_HEADER + +#endif /* FTCCBACK_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftccmap.c b/Dependencies/freetype/freetype/src/cache/ftccmap.c new file mode 100644 index 00000000..b5c61e81 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftccmap.c @@ -0,0 +1,323 @@ +/**************************************************************************** + * + * ftccmap.c + * + * FreeType CharMap cache (body) + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "ftcmanag.h" +#include +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /************************************************************************** + * + * Each FTC_CMapNode contains a simple array to map a range of character + * codes to equivalent glyph indices. + * + * For now, the implementation is very basic: Each node maps a range of + * 128 consecutive character codes to their corresponding glyph indices. + * + * We could do more complex things, but I don't think it is really very + * useful. + * + */ + + + /* number of glyph indices / character code per node */ +#define FTC_CMAP_INDICES_MAX 128 + + /* compute a query/node hash */ +#define FTC_CMAP_HASH( faceid, index, charcode ) \ + ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \ + ( (charcode) / FTC_CMAP_INDICES_MAX ) ) + + /* the charmap query */ + typedef struct FTC_CMapQueryRec_ + { + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 char_code; + + } FTC_CMapQueryRec, *FTC_CMapQuery; + +#define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x)) + + /* the cmap cache node */ + typedef struct FTC_CMapNodeRec_ + { + FTC_NodeRec node; + FTC_FaceID face_id; + FT_UInt cmap_index; + FT_UInt32 first; /* first character in node */ + FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ + + } FTC_CMapNodeRec, *FTC_CMapNode; + +#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) + + /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ + /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ +#define FTC_CMAP_UNKNOWN (FT_UInt16)~0 + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHARMAP NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( void ) + ftc_cmap_node_free( FTC_Node ftcnode, + FTC_Cache cache ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FT_Memory memory = cache->memory; + + + FT_FREE( node ); + } + + + /* initialize a new cmap node */ + FT_CALLBACK_DEF( FT_Error ) + ftc_cmap_node_new( FTC_Node *ftcanode, + FT_Pointer ftcquery, + FTC_Cache cache ) + { + FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_Error error; + FT_Memory memory = cache->memory; + FTC_CMapNode node = NULL; + FT_UInt nn; + + + if ( !FT_QNEW( node ) ) + { + node->face_id = query->face_id; + node->cmap_index = query->cmap_index; + node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * + FTC_CMAP_INDICES_MAX; + + for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) + node->indices[nn] = FTC_CMAP_UNKNOWN; + } + + *anode = node; + return error; + } + + + /* compute the weight of a given cmap node */ + FT_CALLBACK_DEF( FT_Offset ) + ftc_cmap_node_weight( FTC_Node cnode, + FTC_Cache cache ) + { + FT_UNUSED( cnode ); + FT_UNUSED( cache ); + + return sizeof ( *cnode ); + } + + + /* compare a cmap node to a given query */ + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_compare( FTC_Node ftcnode, + FT_Pointer ftcquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + if ( node->face_id == query->face_id && + node->cmap_index == query->cmap_index ) + { + FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); + + + return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); + } + + return 0; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_cmap_node_remove_faceid( FTC_Node ftcnode, + FT_Pointer ftcface_id, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_CMapNode node = (FTC_CMapNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + return FT_BOOL( node->face_id == face_id ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH IMAGE CACHE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static + const FTC_CacheClassRec ftc_cmap_cache_class = + { + ftc_cmap_node_new, /* FTC_Node_NewFunc node_new */ + ftc_cmap_node_weight, /* FTC_Node_WeightFunc node_weight */ + ftc_cmap_node_compare, /* FTC_Node_CompareFunc node_compare */ + ftc_cmap_node_remove_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ + ftc_cmap_node_free, /* FTC_Node_FreeFunc node_free */ + + sizeof ( FTC_CacheRec ), + ftc_cache_init, /* FTC_Cache_InitFunc cache_init */ + ftc_cache_done, /* FTC_Cache_DoneFunc cache_done */ + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ) + { + return FTC_Manager_RegisterCache( manager, + &ftc_cmap_cache_class, + FTC_CACHE_P( acache ) ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, + FTC_FaceID face_id, + FT_Int cmap_index, + FT_UInt32 char_code ) + { + FTC_Cache cache = FTC_CACHE( cmap_cache ); + FTC_CMapQueryRec query; + FTC_Node node; + FT_Error error; + FT_UInt gindex = 0; + FT_Offset hash; + FT_Int no_cmap_change = 0; + + + if ( cmap_index < 0 ) + { + /* Treat a negative cmap index as a special value, meaning that you */ + /* don't want to change the FT_Face's character map through this */ + /* call. This can be useful if the face requester callback already */ + /* sets the face's charmap to the appropriate value. */ + + no_cmap_change = 1; + cmap_index = 0; + } + + if ( !cache ) + { + FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" )); + return 0; + } + + query.face_id = face_id; + query.cmap_index = (FT_UInt)cmap_index; + query.char_code = char_code; + + hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code ); + +#ifdef FTC_INLINE + FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, + node, error ); +#else + error = FTC_Cache_Lookup( cache, hash, &query, &node ); +#endif + if ( error ) + goto Exit; + + FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first < + FTC_CMAP_INDICES_MAX ); + + /* something rotten can happen with rogue clients */ + if ( char_code - FTC_CMAP_NODE( node )->first >= FTC_CMAP_INDICES_MAX ) + return 0; /* XXX: should return appropriate error */ + + gindex = FTC_CMAP_NODE( node )->indices[char_code - + FTC_CMAP_NODE( node )->first]; + if ( gindex == FTC_CMAP_UNKNOWN ) + { + FT_Face face; + + + gindex = 0; + + error = FTC_Manager_LookupFace( cache->manager, + FTC_CMAP_NODE( node )->face_id, + &face ); + if ( error ) + goto Exit; + + if ( cmap_index < face->num_charmaps ) + { + FT_CharMap old = face->charmap; + FT_CharMap cmap = face->charmaps[cmap_index]; + + + if ( !no_cmap_change ) + face->charmap = cmap; + + gindex = FT_Get_Char_Index( face, char_code ); + + if ( !no_cmap_change ) + face->charmap = old; + } + + FTC_CMAP_NODE( node )->indices[char_code - + FTC_CMAP_NODE( node )->first] + = (FT_UShort)gindex; + } + + Exit: + return gindex; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcerror.h b/Dependencies/freetype/freetype/src/cache/ftcerror.h new file mode 100644 index 00000000..daabcc61 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcerror.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ftcerror.h + * + * Caching sub-system error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the caching sub-system error enumeration + * constants. + * + */ + +#ifndef FTCERROR_H_ +#define FTCERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX FTC_Err_ +#define FT_ERR_BASE FT_Mod_Err_Cache + +#include + +#endif /* FTCERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcglyph.c b/Dependencies/freetype/freetype/src/cache/ftcglyph.c new file mode 100644 index 00000000..5e785637 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcglyph.c @@ -0,0 +1,204 @@ +/**************************************************************************** + * + * ftcglyph.c + * + * FreeType Glyph Image (FT_Glyph) cache (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include "ftcglyph.h" +#include + +#include "ftccback.h" +#include "ftcerror.h" + + + /* create a new chunk node, setting its cache index and ref count */ + FT_LOCAL_DEF( void ) + FTC_GNode_Init( FTC_GNode gnode, + FT_UInt gindex, + FTC_Family family ) + { + gnode->family = family; + gnode->gindex = gindex; + family->num_nodes++; + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ) + { + FTC_Family family = gnode->family; + + + gnode->family = NULL; + if ( family && --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, cache ); + } + + + FT_LOCAL_DEF( void ) + FTC_GNode_Done( FTC_GNode gnode, + FTC_Cache cache ) + { + /* finalize the node */ + gnode->gindex = 0; + + FTC_GNode_UnselectFamily( gnode, cache ); + } + + + FT_LOCAL_DEF( FT_Bool ) + ftc_gnode_compare( FTC_Node ftcgnode, + FT_Pointer ftcgquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_GNode gnode = (FTC_GNode)ftcgnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FT_UNUSED( cache ); + + + if ( list_changed ) + *list_changed = FALSE; + return FT_BOOL( gnode->family == gquery->family && + gnode->gindex == gquery->gindex ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CHUNK SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ) + { + FTC_GCacheClass clazz = FTC_CACHE_GCACHE_CLASS( cache ); + + + family->clazz = clazz->family_class; + family->num_nodes = 0; + family->cache = cache; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_gcache_init( FTC_Cache cache ) + { + FTC_GCache gcache = (FTC_GCache)cache; + FT_Error error; + + + error = FTC_Cache_Init( cache ); + if ( !error ) + { + FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class; + + FTC_MruList_Init( &gcache->families, + clazz->family_class, + 0, /* no maximum here! */ + cache, + cache->memory ); + } + + return error; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Init( FTC_GCache gcache ) + { + return ftc_gcache_init( FTC_CACHE( gcache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ftc_gcache_done( FTC_Cache cache ) + { + FTC_GCache gcache = (FTC_GCache)cache; + + + FTC_Cache_Done( cache ); + FTC_MruList_Done( &gcache->families ); + } + + +#if 0 + + FT_LOCAL_DEF( void ) + FTC_GCache_Done( FTC_GCache gcache ) + { + ftc_gcache_done( FTC_CACHE( gcache ) ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ) + { + return FTC_Manager_RegisterCache( manager, (FTC_CacheClass)clazz, + (FTC_Cache*)acache ); + } + + +#ifndef FTC_INLINE + + FT_LOCAL_DEF( FT_Error ) + FTC_GCache_Lookup( FTC_GCache gcache, + FT_Offset hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ) + { + FT_Error error; + + + query->gindex = gindex; + + FTC_MRULIST_LOOKUP( &gcache->families, query, query->family, error ); + if ( !error ) + { + FTC_Family family = query->family; + + + /* prevent the family from being destroyed too early when an */ + /* out-of-memory condition occurs during glyph node initialization. */ + family->num_nodes++; + + error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode ); + + if ( --family->num_nodes == 0 ) + FTC_FAMILY_FREE( family, FTC_CACHE( gcache ) ); + } + return error; + } + +#endif /* !FTC_INLINE */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcglyph.h b/Dependencies/freetype/freetype/src/cache/ftcglyph.h new file mode 100644 index 00000000..b1a96da8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcglyph.h @@ -0,0 +1,314 @@ +/**************************************************************************** + * + * ftcglyph.h + * + * FreeType abstract glyph cache (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * + * FTC_GCache is an _abstract_ cache object optimized to store glyph + * data. It works as follows: + * + * - It manages FTC_GNode objects. Each one of them can hold one or more + * glyph `items'. Item types are not specified in the FTC_GCache but + * in classes that extend it. + * + * - Glyph attributes, like face ID, character size, render mode, etc., + * can be grouped into abstract `glyph families'. This avoids storing + * the attributes within the FTC_GCache, since it is likely that many + * FTC_GNodes will belong to the same family in typical uses. + * + * - Each FTC_GNode is thus an FTC_Node with two additional fields: + * + * * gindex: A glyph index, or the first index in a glyph range. + * * family: A pointer to a glyph `family'. + * + * - Family types are not fully specific in the FTC_Family type, but + * by classes that extend it. + * + * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. + * They share an FTC_Family sub-class called FTC_BasicFamily which is + * used to store the following data: face ID, pixel/point sizes, load + * flags. For more details see the file `src/cache/ftcbasic.c'. + * + * Client applications can extend FTC_GNode with their own FTC_GNode + * and FTC_Family sub-classes to implement more complex caches (e.g., + * handling automatic synthesis, like obliquing & emboldening, colored + * glyphs, etc.). + * + * See also the FTC_ICache & FTC_SCache classes in `ftcimage.h' and + * `ftcsbits.h', which both extend FTC_GCache with additional + * optimizations. + * + * A typical FTC_GCache implementation must provide at least the + * following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: + * my_node_new (must call FTC_GNode_Init) + * my_node_free (must call FTC_GNode_Done) + * my_node_compare (must call ftc_gnode_compare) + * my_node_remove_faceid (must call ftc_gnode_unselect in case + * of match) + * + * - FTC_Family sub-class, e.g. MyFamily, with relevant methods: + * my_family_compare + * my_family_init + * my_family_done + * + * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query + * data. + * + * - Constant structures for a FTC_GNodeClass. + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New. + * + * - MyCacheLookup with a call to FTC_GCache_Lookup. This function will + * automatically: + * + * - Search for the corresponding family in the cache, or create + * a new one if necessary. Put it in FTC_GQUERY(myquery).family + * + * - Call FTC_Cache_Lookup. + * + * If it returns NULL, you should create a new node, then call + * ftc_cache_add as usual. + */ + + + /************************************************************************** + * + * Important: The functions defined in this file are only used to + * implement an abstract glyph cache class. You need to + * provide additional logic to implement a complete cache. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef FTCGLYPH_H_ +#define FTCGLYPH_H_ + + +#include "ftcmanag.h" + + +FT_BEGIN_HEADER + + + /* + * We can group glyphs into `families'. Each family correspond to a + * given face ID, character size, transform, etc. + * + * Families are implemented as MRU list nodes. They are + * reference-counted. + */ + + typedef struct FTC_FamilyRec_ + { + FTC_MruNodeRec mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_Cache cache; + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; + +#define FTC_FAMILY( x ) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) ) + + + typedef struct FTC_GNodeRec_ + { + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; + + } FTC_GNodeRec, *FTC_GNode; + +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) + + + typedef struct FTC_GQueryRec_ + { + FT_UInt gindex; + FTC_Family family; + + } FTC_GQueryRec, *FTC_GQuery; + +#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) + + + /************************************************************************** + * + * These functions are exported so that they can be called from + * user-provided cache classes; otherwise, they are really part of the + * cache sub-system internals. + */ + + /* must be called by derived FTC_Node_InitFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Init( FTC_GNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_Family family ); + + /* call this function to clear a node's family -- this is necessary */ + /* to implement the `node_remove_faceid' cache method correctly */ + FT_LOCAL( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ); + + /* must be called by derived FTC_Node_DoneFunc routines */ + FT_LOCAL( void ) + FTC_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + FT_LOCAL( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ); + + typedef struct FTC_GCacheRec_ + { + FTC_CacheRec cache; + FTC_MruListRec families; + + } FTC_GCacheRec, *FTC_GCache; + +#define FTC_GCACHE( x ) ((FTC_GCache)(x)) + + +#if 0 + /* can be used as @FTC_Cache_InitFunc */ + FT_LOCAL( FT_Error ) + FTC_GCache_Init( FTC_GCache cache ); +#endif + + +#if 0 + /* can be used as @FTC_Cache_DoneFunc */ + FT_LOCAL( void ) + FTC_GCache_Done( FTC_GCache cache ); +#endif + + + /* the glyph cache class adds fields for the family implementation */ + typedef struct FTC_GCacheClassRec_ + { + FTC_CacheClassRec clazz; + FTC_MruListClass family_class; + + } FTC_GCacheClassRec; + + typedef const FTC_GCacheClassRec* FTC_GCacheClass; + +#define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x)) + +#define FTC_CACHE_GCACHE_CLASS( x ) \ + FTC_GCACHE_CLASS( FTC_CACHE( x )->org_class ) +#define FTC_CACHE_FAMILY_CLASS( x ) \ + ( (FTC_MruListClass)FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + /* convenience function; use it instead of FTC_Manager_Register_Cache */ + FT_LOCAL( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ); + +#ifndef FTC_INLINE + FT_LOCAL( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_Offset hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ); +#endif + + + /* */ + + +#define FTC_FAMILY_FREE( family, cache ) \ + FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \ + (FTC_MruNode)(family) ) + + +#ifdef FTC_INLINE + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_GCache _gcache = FTC_GCACHE( cache ); \ + FTC_GQuery _gquery = (FTC_GQuery)( query ); \ + FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ + FTC_MruNode _mrunode; \ + \ + \ + _gquery->gindex = (gindex); \ + \ + FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ + _mrunode, error ); \ + _gquery->family = FTC_FAMILY( _mrunode ); \ + if ( !error ) \ + { \ + FTC_Family _gqfamily = _gquery->family; \ + \ + \ + _gqfamily->num_nodes++; \ + \ + FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ + \ + if ( --_gqfamily->num_nodes == 0 ) \ + FTC_FAMILY_FREE( _gqfamily, _gcache ); \ + } \ + FT_END_STMNT + /* */ + +#else /* !FTC_INLINE */ + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + \ + error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, \ + FTC_GQUERY( query ), &node ); \ + \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + +FT_END_HEADER + + +#endif /* FTCGLYPH_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcimage.c b/Dependencies/freetype/freetype/src/cache/ftcimage.c new file mode 100644 index 00000000..14630640 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcimage.c @@ -0,0 +1,158 @@ +/**************************************************************************** + * + * ftcimage.c + * + * FreeType Image cache (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcimage.h" +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + + + /* finalize a given glyph image node */ + FT_LOCAL_DEF( void ) + ftc_inode_free( FTC_Node ftcinode, + FTC_Cache cache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_Memory memory = cache->memory; + + + FT_Done_Glyph( inode->glyph ); + + FTC_GNode_Done( FTC_GNODE( inode ), cache ); + FT_FREE( inode ); + } + + + FT_LOCAL_DEF( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ) + { + ftc_inode_free( FTC_NODE( inode ), cache ); + } + + + /* initialize a new glyph image node */ + FT_LOCAL_DEF( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_INode inode = NULL; + + + if ( !FT_QNEW( inode ) ) + { + FTC_GNode gnode = FTC_GNODE( inode ); + FTC_Family family = gquery->family; + FT_UInt gindex = gquery->gindex; + FTC_IFamilyClass clazz = FTC_CACHE_IFAMILY_CLASS( cache ); + + + /* initialize its inner fields */ + FTC_GNode_Init( gnode, gindex, family ); + inode->glyph = NULL; + + /* we will now load the glyph image */ + error = clazz->family_load_glyph( family, gindex, cache, + &inode->glyph ); + if ( error ) + { + FTC_INode_Free( inode, cache ); + inode = NULL; + } + } + + *pinode = inode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_inode_new( FTC_Node *ftcpinode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_INode *pinode = (FTC_INode*)ftcpinode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_INode_New( pinode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_Offset ) + ftc_inode_weight( FTC_Node ftcinode, + FTC_Cache ftccache ) + { + FTC_INode inode = (FTC_INode)ftcinode; + FT_Offset size = 0; + FT_Glyph glyph = inode->glyph; + + FT_UNUSED( ftccache ); + + + switch ( glyph->format ) + { + case FT_GLYPH_FORMAT_BITMAP: + { + FT_BitmapGlyph bitg = (FT_BitmapGlyph)glyph; + + + size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) + + sizeof ( *bitg ); + } + break; + + case FT_GLYPH_FORMAT_OUTLINE: + { + FT_OutlineGlyph outg = (FT_OutlineGlyph)glyph; + + + size = (FT_Offset)outg->outline.n_points * + ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + + (FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) + + sizeof ( *outg ); + } + break; + + default: + ; + } + + size += sizeof ( *inode ); + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Offset ) + FTC_INode_Weight( FTC_INode inode ) + { + return ftc_inode_weight( FTC_NODE( inode ), NULL ); + } + +#endif /* 0 */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcimage.h b/Dependencies/freetype/freetype/src/cache/ftcimage.h new file mode 100644 index 00000000..a0c4a972 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcimage.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * + * ftcimage.h + * + * FreeType Generic Image cache (specification) + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* + * FTC_ICache is an _abstract_ cache used to store a single FT_Glyph + * image per cache node. + * + * FTC_ICache extends FTC_GCache. For an implementation example, + * see FTC_ImageCache in `src/cache/ftbasic.c'. + */ + + + /************************************************************************** + * + * Each image cache really manages FT_Glyph objects. + * + */ + + +#ifndef FTCIMAGE_H_ +#define FTCIMAGE_H_ + + +#include +#include "ftcglyph.h" + +FT_BEGIN_HEADER + + + /* the FT_Glyph image node type - we store only 1 glyph per node */ + typedef struct FTC_INodeRec_ + { + FTC_GNodeRec gnode; + FT_Glyph glyph; + + } FTC_INodeRec, *FTC_INode; + +#define FTC_INODE( x ) ( (FTC_INode)( x ) ) +#define FTC_INODE_GINDEX( x ) FTC_GNODE( x )->gindex +#define FTC_INODE_FAMILY( x ) FTC_GNODE( x )->family + + typedef FT_Error + (*FTC_IFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ); + + typedef struct FTC_IFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_IFamily_LoadGlyphFunc family_load_glyph; + + } FTC_IFamilyClassRec; + + typedef const FTC_IFamilyClassRec* FTC_IFamilyClass; + +#define FTC_IFAMILY_CLASS( x ) ((FTC_IFamilyClass)(x)) + +#define FTC_CACHE_IFAMILY_CLASS( x ) \ + FTC_IFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + /* can be used as a @FTC_Node_FreeFunc */ + FT_LOCAL( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ); + + /* Can be used as @FTC_Node_NewFunc. `gquery.index' and `gquery.family' + * must be set correctly. This function will call the `family_load_glyph' + * method to load the FT_Glyph into the cache node. + */ + FT_LOCAL( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + /* can be used as @FTC_Node_WeightFunc */ + FT_LOCAL( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ); +#endif + + + /* */ + +FT_END_HEADER + +#endif /* FTCIMAGE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcmanag.c b/Dependencies/freetype/freetype/src/cache/ftcmanag.c new file mode 100644 index 00000000..c0a48a53 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcmanag.c @@ -0,0 +1,677 @@ +/**************************************************************************** + * + * ftcmanag.c + * + * FreeType Cache Manager (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcmanag.h" +#include +#include +#include + +#include "ftcerror.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + static FT_Error + ftc_scaler_lookup_size( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Face face; + FT_Size size = NULL; + FT_Error error; + + + error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); + if ( error ) + goto Exit; + + error = FT_New_Size( face, &size ); + if ( error ) + goto Exit; + + FT_Activate_Size( size ); + + if ( scaler->pixel ) + error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); + else + error = FT_Set_Char_Size( face, + (FT_F26Dot6)scaler->width, + (FT_F26Dot6)scaler->height, + scaler->x_res, + scaler->y_res ); + if ( error ) + { + FT_Done_Size( size ); + size = NULL; + } + + Exit: + *asize = size; + return error; + } + + + typedef struct FTC_SizeNodeRec_ + { + FTC_MruNodeRec node; + FT_Size size; + FTC_ScalerRec scaler; + + } FTC_SizeNodeRec, *FTC_SizeNode; + +#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) ) + + + FT_CALLBACK_DEF( void ) + ftc_size_node_done( FTC_MruNode ftcnode, + FT_Pointer data ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FT_UNUSED( data ); + + + FT_Done_Size( node->size ); + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_size_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcscaler ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Scaler scaler0 = &node->scaler; + + + if ( FTC_SCALER_COMPARE( scaler0, scaler ) ) + { + FT_Activate_Size( node->size ); + return 1; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcscaler, + FT_Pointer ftcmanager ) + { + FT_Error error; + FT_Size size; + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_Scaler scaler = (FTC_Scaler)ftcscaler; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + error = ftc_scaler_lookup_size( manager, scaler, &size ); + if ( !error ) + { + node->size = size; + node->scaler = scaler[0]; + } + + return error; + } + + + static + const FTC_MruListClassRec ftc_size_list_class = + { + sizeof ( FTC_SizeNodeRec ), + + ftc_size_node_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_size_node_init, /* FTC_MruNode_InitFunc node_init */ + ftc_size_node_done /* FTC_MruNode_DoneFunc node_done */ + }; + + + /* helper function used by ftc_face_node_done */ + static FT_Bool + ftc_size_node_compare_faceid( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_SizeNode node = (FTC_SizeNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->scaler.face_id == face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) + { + FT_Error error; + FTC_MruNode mrunode; + + + if ( !asize || !scaler ) + return FT_THROW( Invalid_Argument ); + + *asize = NULL; + + if ( !manager ) + return FT_THROW( Invalid_Cache_Handle ); + +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare, + mrunode, error ); + +#else + error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode ); +#endif + + if ( !error ) + *asize = FTC_SIZE_NODE( mrunode )->size; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE MRU IMPLEMENTATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct FTC_FaceNodeRec_ + { + FTC_MruNodeRec node; + FTC_FaceID face_id; + FT_Face face; + + } FTC_FaceNodeRec, *FTC_FaceNode; + +#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) ) + + + FT_CALLBACK_DEF( FT_Error ) + ftc_face_node_init( FTC_MruNode ftcnode, + FT_Pointer ftcface_id, + FT_Pointer ftcmanager ) + { + FT_Error error; + FT_Face face; + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + error = manager->request_face( face_id, + manager->library, + manager->request_data, + &face ); + if ( !error ) + { + /* destroy initial size object; it will be re-created later */ + if ( face->size ) + FT_Done_Size( face->size ); + + node->face = face; + node->face_id = face_id; + } + + return error; + } + + + FT_CALLBACK_DEF( void ) + ftc_face_node_done( FTC_MruNode ftcnode, + FT_Pointer ftcmanager ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_Manager manager = (FTC_Manager)ftcmanager; + + + /* we must begin by removing all scalers for the target face */ + /* from the manager's list */ + FTC_MruList_RemoveSelection( &manager->sizes, + ftc_size_node_compare_faceid, + node->face_id ); + + /* all right, we can discard the face now */ + FT_Done_Face( node->face ); + node->face = NULL; + node->face_id = NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + ftc_face_node_compare( FTC_MruNode ftcnode, + FT_Pointer ftcface_id ) + { + FTC_FaceNode node = (FTC_FaceNode)ftcnode; + FTC_FaceID face_id = (FTC_FaceID)ftcface_id; + + + return FT_BOOL( node->face_id == face_id ); + } + + + static + const FTC_MruListClassRec ftc_face_list_class = + { + sizeof ( FTC_FaceNodeRec), + + ftc_face_node_compare, /* FTC_MruNode_CompareFunc node_compare */ + ftc_face_node_init, /* FTC_MruNode_InitFunc node_init */ + ftc_face_node_done /* FTC_MruNode_DoneFunc node_done */ + }; + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + FT_Error error; + FTC_MruNode mrunode; + + + if ( !aface ) + return FT_THROW( Invalid_Argument ); + + *aface = NULL; + + if ( !manager ) + return FT_THROW( Invalid_Cache_Handle ); + + /* we break encapsulation for the sake of speed */ +#ifdef FTC_INLINE + + FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare, + mrunode, error ); + +#else + error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode ); +#endif + + if ( !error ) + *aface = FTC_FACE_NODE( mrunode )->face; + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE MANAGER ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( FT_Error ) + FTC_Manager_New( FT_Library library, + FT_UInt max_faces, + FT_UInt max_sizes, + FT_ULong max_bytes, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ) + { + FT_Error error; + FT_Memory memory; + FTC_Manager manager = NULL; + + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); + + if ( !amanager || !requester ) + return FT_THROW( Invalid_Argument ); + + memory = library->memory; + + if ( FT_QNEW( manager ) ) + goto Exit; + + if ( max_faces == 0 ) + max_faces = FTC_MAX_FACES_DEFAULT; + + if ( max_sizes == 0 ) + max_sizes = FTC_MAX_SIZES_DEFAULT; + + if ( max_bytes == 0 ) + max_bytes = FTC_MAX_BYTES_DEFAULT; + + manager->library = library; + manager->memory = memory; + manager->max_weight = max_bytes; + manager->cur_weight = 0; + + manager->request_face = requester; + manager->request_data = req_data; + + FTC_MruList_Init( &manager->faces, + &ftc_face_list_class, + max_faces, + manager, + memory ); + + FTC_MruList_Init( &manager->sizes, + &ftc_size_list_class, + max_sizes, + manager, + memory ); + + manager->nodes_list = NULL; + manager->num_nodes = 0; + manager->num_caches = 0; + + *amanager = manager; + + Exit: + return error; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Done( FTC_Manager manager ) + { + FT_Memory memory; + FT_UInt idx; + + + if ( !manager || !manager->library ) + return; + + memory = manager->memory; + + /* now discard all caches */ + for ( idx = manager->num_caches; idx-- > 0; ) + { + FTC_Cache cache = manager->caches[idx]; + + + if ( cache ) + { + cache->clazz.cache_done( cache ); + FT_FREE( cache ); + } + } + + /* discard faces and sizes */ + FTC_MruList_Done( &manager->sizes ); + FTC_MruList_Done( &manager->faces ); + + FT_FREE( manager ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_Reset( FTC_Manager manager ) + { + if ( !manager ) + return; + + FTC_MruList_Reset( &manager->sizes ); + FTC_MruList_Reset( &manager->faces ); + + FTC_Manager_FlushN( manager, manager->num_nodes ); + } + + +#ifdef FT_DEBUG_ERROR + + static void + FTC_Manager_Check( FTC_Manager manager ) + { + FTC_Node node, first; + + + first = manager->nodes_list; + + /* check node weights */ + if ( first ) + { + FT_Offset weight = 0; + + + node = first; + + do + { + FTC_Cache cache = manager->caches[node->cache_index]; + + + if ( node->cache_index >= manager->num_caches ) + FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %hu\n", + node->cache_index )); + else + weight += cache->clazz.node_weight( node, cache ); + + node = FTC_NODE_NEXT( node ); + + } while ( node != first ); + + if ( weight != manager->cur_weight ) + FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", + manager->cur_weight, weight )); + } + + /* check circular list */ + if ( first ) + { + FT_UFast count = 0; + + + node = first; + do + { + count++; + node = FTC_NODE_NEXT( node ); + + } while ( node != first ); + + if ( count != manager->num_nodes ) + FT_TRACE0(( "FTC_Manager_Check:" + " invalid cache node count %u instead of %u\n", + manager->num_nodes, count )); + } + } + +#endif /* FT_DEBUG_ERROR */ + + + /* `Compress' the manager's data, i.e., get rid of old cache nodes */ + /* that are not referenced anymore in order to limit the total */ + /* memory used by the cache. */ + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( void ) + FTC_Manager_Compress( FTC_Manager manager ) + { + FTC_Node node, prev, first; + + + if ( !manager ) + return; + + first = manager->nodes_list; + +#ifdef FT_DEBUG_ERROR + FTC_Manager_Check( manager ); + + FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %u\n", + manager->cur_weight, manager->max_weight, + manager->num_nodes )); +#endif + + if ( manager->cur_weight < manager->max_weight || !first ) + return; + + /* go to last node -- it's a circular list */ + prev = FTC_NODE_PREV( first ); + do + { + node = prev; + prev = FTC_NODE_PREV( node ); + + if ( node->ref_count <= 0 ) + ftc_node_destroy( node, manager ); + + } while ( node != first && manager->cur_weight > manager->max_weight ); + } + + + /* documentation is in ftcmanag.h */ + + FT_LOCAL_DEF( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + FTC_Cache cache = NULL; + + + if ( manager && clazz && acache ) + { + FT_Memory memory = manager->memory; + + + if ( manager->num_caches >= FTC_MAX_CACHES ) + { + error = FT_THROW( Too_Many_Caches ); + FT_ERROR(( "FTC_Manager_RegisterCache:" + " too many registered caches\n" )); + goto Exit; + } + + if ( !FT_QALLOC( cache, clazz->cache_size ) ) + { + cache->manager = manager; + cache->memory = memory; + cache->clazz = clazz[0]; + cache->org_class = clazz; + + /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ + /* IF IT IS NOT SET CORRECTLY */ + cache->index = manager->num_caches; + + error = clazz->cache_init( cache ); + if ( error ) + { + clazz->cache_done( cache ); + FT_FREE( cache ); + goto Exit; + } + + manager->caches[manager->num_caches++] = cache; + } + } + + Exit: + if ( acache ) + *acache = cache; + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ) + { + FTC_Node first = manager->nodes_list; + FTC_Node prev, node; + FT_UInt result = 0; + + + /* try to remove `count' nodes from the list */ + if ( !first || !count ) + return result; + + /* go to last node -- it's a circular list */ + prev = FTC_NODE_PREV( first ); + do + { + node = prev; + prev = FTC_NODE_PREV( node ); + + /* don't touch locked nodes */ + if ( node->ref_count <= 0 ) + { + ftc_node_destroy( node, manager ); + result++; + } + } while ( node != first && result < count ); + + return result; + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ) + { + FT_UInt nn; + + + if ( !manager ) + return; + + /* this will remove all FTC_SizeNode that correspond to + * the face_id as well + */ + FTC_MruList_RemoveSelection( &manager->faces, + ftc_face_node_compare, + face_id ); + + for ( nn = 0; nn < manager->num_caches; nn++ ) + FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); + } + + + /* documentation is in ftcache.h */ + + FT_EXPORT_DEF( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ) + { + if ( node && + manager && + node->cache_index < manager->num_caches ) + node->ref_count--; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcmanag.h b/Dependencies/freetype/freetype/src/cache/ftcmanag.h new file mode 100644 index 00000000..bd158f5f --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcmanag.h @@ -0,0 +1,175 @@ +/**************************************************************************** + * + * ftcmanag.h + * + * FreeType Cache Manager (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * A cache manager is in charge of the following: + * + * - Maintain a mapping between generic FTC_FaceIDs and live FT_Face + * objects. The mapping itself is performed through a user-provided + * callback. However, the manager maintains a small cache of FT_Face + * and FT_Size objects in order to speed up things considerably. + * + * - Manage one or more cache objects. Each cache is in charge of + * holding a varying number of `cache nodes'. Each cache node + * represents a minimal amount of individually accessible cached + * data. For example, a cache node can be an FT_Glyph image + * containing a vector outline, or some glyph metrics, or anything + * else. + * + * Each cache node has a certain size in bytes that is added to the + * total amount of `cache memory' within the manager. + * + * All cache nodes are located in a global LRU list, where the oldest + * node is at the tail of the list. + * + * Each node belongs to a single cache, and includes a reference + * count to avoid destroying it (due to caching). + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef FTCMANAG_H_ +#define FTCMANAG_H_ + + +#include +#include "ftcmru.h" +#include "ftccache.h" + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Section: + * cache_subsystem + * + */ + + +#define FTC_MAX_FACES_DEFAULT 2 +#define FTC_MAX_SIZES_DEFAULT 4 +#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */ + + /* maximum number of caches registered in a single manager */ +#define FTC_MAX_CACHES 16 + + + typedef struct FTC_ManagerRec_ + { + FT_Library library; + FT_Memory memory; + + FTC_Node nodes_list; + FT_Offset max_weight; + FT_Offset cur_weight; + FT_UInt num_nodes; + + FTC_Cache caches[FTC_MAX_CACHES]; + FT_UInt num_caches; + + FTC_MruListRec faces; + FTC_MruListRec sizes; + + FT_Pointer request_data; + FTC_Face_Requester request_face; + + } FTC_ManagerRec; + + + /************************************************************************** + * + * @Function: + * FTC_Manager_Compress + * + * @Description: + * This function is used to check the state of the cache manager if + * its `num_bytes' field is greater than its `max_bytes' field. It + * will flush as many old cache nodes as possible (ignoring cache + * nodes with a non-zero reference count). + * + * @InOut: + * manager :: + * A handle to the cache manager. + * + * @Note: + * Client applications should not call this function directly. It is + * normally invoked by specific cache implementations. + * + * The reason this function is exported is to allow client-specific + * cache classes. + */ + FT_LOCAL( void ) + FTC_Manager_Compress( FTC_Manager manager ); + + + /* try to flush `count' old nodes from the cache; return the number + * of really flushed nodes + */ + FT_LOCAL( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ); + + + /* this must be used internally for the moment */ + FT_LOCAL( FT_Error ) + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ); + + /* */ + +#define FTC_SCALER_COMPARE( a, b ) \ + ( (a)->face_id == (b)->face_id && \ + (a)->width == (b)->width && \ + (a)->height == (b)->height && \ + ((a)->pixel != 0) == ((b)->pixel != 0) && \ + ( (a)->pixel || \ + ( (a)->x_res == (b)->x_res && \ + (a)->y_res == (b)->y_res ) ) ) + +#define FTC_SCALER_HASH( q ) \ + ( FTC_FACE_ID_HASH( (q)->face_id ) + \ + (q)->width + (q)->height*7 + \ + ( (q)->pixel ? 0 : ( (q)->x_res*33 ^ (q)->y_res*61 ) ) ) + + /* */ + +FT_END_HEADER + +#endif /* FTCMANAG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcmru.c b/Dependencies/freetype/freetype/src/cache/ftcmru.c new file mode 100644 index 00000000..f908eb25 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcmru.c @@ -0,0 +1,341 @@ +/**************************************************************************** + * + * ftcmru.c + * + * FreeType MRU support (body). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcmru.h" +#include +#include + +#include "ftcerror.h" + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + if ( first ) + { + FTC_MruNode last = first->prev; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + { + fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" ); + exit( 2 ); + } + cnode = cnode->next; + + } while ( cnode != first ); + } +#endif + + first->prev = node; + last->next = node; + node->next = first; + node->prev = last; + } + else + { + node->next = node; + node->prev = node; + } + *plist = node; + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + + + FT_ASSERT( first ); + + if ( first != node ) + { + FTC_MruNode prev, next, last; + + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Up: invalid action\n" ); + exit( 2 ); + Ok: + } +#endif + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + last = first->prev; + + last->next = node; + first->prev = node; + + node->next = first; + node->prev = last; + + *plist = node; + } + } + + + FT_LOCAL_DEF( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ) + { + FTC_MruNode first = *plist; + FTC_MruNode prev, next; + + + FT_ASSERT( first ); + +#ifdef FT_DEBUG_ERROR + { + FTC_MruNode cnode = first; + + + do + { + if ( cnode == node ) + goto Ok; + cnode = cnode->next; + + } while ( cnode != first ); + + fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" ); + exit( 2 ); + Ok: + } +#endif + + prev = node->prev; + next = node->next; + + prev->next = next; + next->prev = prev; + + if ( node == next ) + { + FT_ASSERT( first == node ); + FT_ASSERT( prev == node ); + + *plist = NULL; + } + else if ( node == first ) + *plist = next; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ) + { + list->num_nodes = 0; + list->max_nodes = max_nodes; + list->nodes = NULL; + list->clazz = *clazz; + list->data = data; + list->memory = memory; + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Reset( FTC_MruList list ) + { + while ( list->nodes ) + FTC_MruList_Remove( list, list->nodes ); + + FT_ASSERT( list->num_nodes == 0 ); + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_Done( FTC_MruList list ) + { + FTC_MruList_Reset( list ); + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ) + { + FTC_MruNode_CompareFunc compare = list->clazz.node_compare; + FTC_MruNode first, node; + + + first = list->nodes; + node = NULL; + + if ( first ) + { + node = first; + do + { + if ( compare( node, key ) ) + { + if ( node != first ) + FTC_MruNode_Up( &list->nodes, node ); + + return node; + } + + node = node->next; + + } while ( node != first); + } + + return NULL; + } +#endif + + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FT_Error error; + FTC_MruNode node = NULL; + FTC_MruNode prev = NULL; + FT_Memory memory = list->memory; + + + /* zero new node in case of node_init failure */ + if ( FT_ALLOC( node, list->clazz.node_size ) ) + goto Exit; + + error = list->clazz.node_init( node, key, list->data ); + if ( error ) + { + prev = node; + node = NULL; + + goto Clean; + } + else if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) + prev = list->nodes->prev; + + FTC_MruNode_Prepend( &list->nodes, node ); + list->num_nodes++; + + if ( !prev ) + goto Exit; + + FTC_MruNode_Remove( &list->nodes, prev ); + list->num_nodes--; + + Clean: + if ( list->clazz.node_done ) + list->clazz.node_done( prev, list->data ); + + FT_FREE( prev ); + + Exit: + *anode = node; + return error; + } + + +#ifndef FTC_INLINE + FT_LOCAL_DEF( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FTC_MruNode node; + + + node = FTC_MruList_Find( list, key ); + if ( !node ) + return FTC_MruList_New( list, key, anode ); + + *anode = node; + return 0; + } +#endif /* FTC_INLINE */ + + FT_LOCAL_DEF( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ) + { + FT_Memory memory = list->memory; + + + FTC_MruNode_Remove( &list->nodes, node ); + list->num_nodes--; + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + } + + + FT_LOCAL_DEF( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ) + { + FTC_MruNode first = list->nodes; + FTC_MruNode prev, node; + + + if ( !first || !selection ) + return; + + prev = first->prev; + do + { + node = prev; + prev = node->prev; + + if ( selection( node, key ) ) + FTC_MruList_Remove( list, node ); + + } while ( node != first ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcmru.h b/Dependencies/freetype/freetype/src/cache/ftcmru.h new file mode 100644 index 00000000..68faab98 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcmru.h @@ -0,0 +1,242 @@ +/**************************************************************************** + * + * ftcmru.h + * + * Simple MRU list-cache (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * An MRU is a list that cannot hold more than a certain number of + * elements (`max_elements'). All elements in the list are sorted in + * least-recently-used order, i.e., the `oldest' element is at the tail + * of the list. + * + * When doing a lookup (either through `Lookup()' or `Lookup_Node()'), + * the list is searched for an element with the corresponding key. If + * it is found, the element is moved to the head of the list and is + * returned. + * + * If no corresponding element is found, the lookup routine will try to + * obtain a new element with the relevant key. If the list is already + * full, the oldest element from the list is discarded and replaced by a + * new one; a new element is added to the list otherwise. + * + * Note that it is possible to pre-allocate the element list nodes. + * This is handy if `max_elements' is sufficiently small, as it saves + * allocations/releases during the lookup process. + * + */ + + +#ifndef FTCMRU_H_ +#define FTCMRU_H_ + + +#include +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + +#define xxFT_DEBUG_ERROR +#define FTC_INLINE + +FT_BEGIN_HEADER + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + FTC_MruNode prev; + + } FTC_MruNodeRec; + + + FT_LOCAL( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ); + + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + + typedef FT_Bool + (*FTC_MruNode_CompareFunc)( FTC_MruNode node, + FT_Pointer key ); + + typedef FT_Error + (*FTC_MruNode_InitFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef void + (*FTC_MruNode_DoneFunc)( FTC_MruNode node, + FT_Pointer data ); + + + typedef struct FTC_MruListClassRec_ + { + FT_Offset node_size; + + FTC_MruNode_CompareFunc node_compare; + FTC_MruNode_InitFunc node_init; + FTC_MruNode_DoneFunc node_done; + + } FTC_MruListClassRec; + + + typedef struct FTC_MruListRec_ + { + FT_UInt num_nodes; + FT_UInt max_nodes; + FTC_MruNode nodes; + FT_Pointer data; + FTC_MruListClassRec clazz; + FT_Memory memory; + + } FTC_MruListRec; + + + FT_LOCAL( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ); + + FT_LOCAL( void ) + FTC_MruList_Reset( FTC_MruList list ); + + + FT_LOCAL( void ) + FTC_MruList_Done( FTC_MruList list ); + + + FT_LOCAL( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ); + + FT_LOCAL( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ); + + FT_LOCAL( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc selection, + FT_Pointer key ); + + +#ifdef FTC_INLINE + +#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \ + FT_BEGIN_STMNT \ + FTC_MruNode* _pfirst = &(list)->nodes; \ + FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \ + FTC_MruNode _first, _node; \ + \ + \ + error = FT_Err_Ok; \ + _first = *(_pfirst); \ + _node = NULL; \ + \ + if ( _first ) \ + { \ + _node = _first; \ + do \ + { \ + if ( _compare( _node, (key) ) ) \ + { \ + if ( _node != _first ) \ + FTC_MruNode_Up( _pfirst, _node ); \ + \ + node = _node; \ + goto MruOk_; \ + } \ + _node = _node->next; \ + \ + } while ( _node != _first); \ + } \ + \ + error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \ + MruOk_: \ + ; \ + FT_END_STMNT + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error ) + +#else /* !FTC_INLINE */ + + FT_LOCAL( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ); + + FT_LOCAL( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *pnode ); + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) + +#endif /* !FTC_INLINE */ + + +#define FTC_MRULIST_LOOP( list, node ) \ + FT_BEGIN_STMNT \ + FTC_MruNode _first = (list)->nodes; \ + \ + \ + if ( _first ) \ + { \ + FTC_MruNode _node = _first; \ + \ + \ + do \ + { \ + *(FTC_MruNode*)&(node) = _node; + + +#define FTC_MRULIST_LOOP_END() \ + _node = _node->next; \ + \ + } while ( _node != _first ); \ + } \ + FT_END_STMNT + + /* */ + +FT_END_HEADER + + +#endif /* FTCMRU_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcsbits.c b/Dependencies/freetype/freetype/src/cache/ftcsbits.c new file mode 100644 index 00000000..19f3ef04 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcsbits.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * ftcsbits.c + * + * FreeType sbits manager (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "ftcsbits.h" +#include +#include +#include + +#include "ftccback.h" +#include "ftcerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT cache + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SBIT CACHE NODES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + ftc_sbit_copy_bitmap( FTC_SBit sbit, + FT_Bitmap* bitmap, + FT_Memory memory ) + { + FT_Error error; + FT_Int pitch = bitmap->pitch; + FT_ULong size; + + + if ( pitch < 0 ) + pitch = -pitch; + + size = (FT_ULong)pitch * bitmap->rows; + + FT_MEM_DUP( sbit->buffer, bitmap->buffer, size ); + + return error; + } + + + FT_LOCAL_DEF( void ) + ftc_snode_free( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_SBit sbit = snode->sbits; + FT_UInt count = snode->count; + FT_Memory memory = cache->memory; + + + for ( ; count > 0; sbit++, count-- ) + FT_FREE( sbit->buffer ); + + FTC_GNode_Done( FTC_GNODE( snode ), cache ); + + FT_FREE( snode ); + } + + + FT_LOCAL_DEF( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ) + { + ftc_snode_free( FTC_NODE( snode ), cache ); + } + + + /* + * This function tries to load a small bitmap within a given FTC_SNode. + * Note that it returns a non-zero error code _only_ in the case of + * out-of-memory condition. For all other errors (e.g., corresponding + * to a bad font file), this function will mark the sbit as `unavailable' + * and return a value of 0. + * + * You should also read the comment within the @ftc_snode_compare + * function below to see how out-of-memory is handled during a lookup. + */ + static FT_Error + ftc_snode_load( FTC_SNode snode, + FTC_Manager manager, + FT_UInt gindex, + FT_ULong *asize ) + { + FT_Error error; + FTC_GNode gnode = FTC_GNODE( snode ); + FTC_Family family = gnode->family; + FT_Face face; + FTC_SBit sbit; + FTC_SFamilyClass clazz; + + + if ( gindex - gnode->gindex >= snode->count ) + { + FT_ERROR(( "ftc_snode_load: invalid glyph index" )); + return FT_THROW( Invalid_Argument ); + } + + sbit = snode->sbits + ( gindex - gnode->gindex ); + clazz = (FTC_SFamilyClass)family->clazz; + + error = clazz->family_load_glyph( family, gindex, manager, &face ); + if ( error ) + goto BadGlyph; + + { + FT_Int temp; + FT_GlyphSlot slot = face->glyph; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */ + + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + FT_TRACE0(( "ftc_snode_load:" + " glyph loaded didn't return a bitmap\n" )); + goto BadGlyph; + } + + /* Check whether our values fit into 8/16-bit containers! */ + /* If this is not the case, our bitmap is too large */ + /* and we will leave it as `missing' with sbit.buffer = 0 */ + +#define CHECK_CHAR( d ) ( temp = (FT_Char)d, (FT_Int) temp == (FT_Int) d ) +#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d ) +#define CHECK_SHRT( d ) ( temp = (FT_Short)d, (FT_Int)temp == (FT_Int) d ) + + /* horizontal advance in pixels */ + xadvance = ( slot->advance.x + 32 ) >> 6; + yadvance = ( slot->advance.y + 32 ) >> 6; + + if ( !CHECK_BYTE( bitmap->rows ) || + !CHECK_BYTE( bitmap->width ) || + !CHECK_SHRT( bitmap->pitch ) || + !CHECK_CHAR( slot->bitmap_left ) || + !CHECK_CHAR( slot->bitmap_top ) || + !CHECK_CHAR( xadvance ) || + !CHECK_CHAR( yadvance ) ) + { + FT_TRACE2(( "ftc_snode_load:" + " glyph too large for small bitmap cache\n")); + goto BadGlyph; + } + + sbit->width = (FT_Byte)bitmap->width; + sbit->height = (FT_Byte)bitmap->rows; + sbit->pitch = (FT_Short)bitmap->pitch; + sbit->left = (FT_Char)slot->bitmap_left; + sbit->top = (FT_Char)slot->bitmap_top; + sbit->xadvance = (FT_Char)xadvance; + sbit->yadvance = (FT_Char)yadvance; + sbit->format = (FT_Byte)bitmap->pixel_mode; + sbit->max_grays = (FT_Byte)( bitmap->num_grays - 1 ); + + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + /* take the bitmap ownership */ + sbit->buffer = bitmap->buffer; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* copy the bitmap into a new buffer -- ignore error */ + error = ftc_sbit_copy_bitmap( sbit, bitmap, manager->memory ); + } + + /* now, compute size */ + if ( asize ) + *asize = (FT_ULong)FT_ABS( sbit->pitch ) * sbit->height; + + } /* glyph loading successful */ + + /* ignore the errors that might have occurred -- */ + /* we mark unloaded glyphs with `sbit.buffer == 0' */ + /* and `width == 255', `height == 0' */ + /* */ + if ( error && FT_ERR_NEQ( error, Out_Of_Memory ) ) + { + BadGlyph: + sbit->width = 255; + sbit->height = 0; + sbit->buffer = NULL; + error = FT_Err_Ok; + if ( asize ) + *asize = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + FT_Error error; + FTC_SNode snode = NULL; + FT_UInt gindex = gquery->gindex; + FTC_Family family = gquery->family; + + FTC_SFamilyClass clazz = FTC_CACHE_SFAMILY_CLASS( cache ); + FT_UInt total; + FT_UInt node_count; + + + total = clazz->family_get_count( family, cache->manager ); + if ( total == 0 || gindex >= total ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( snode ) ) + { + FT_UInt count, start; + + + start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE ); + count = total - start; + if ( count > FTC_SBIT_ITEMS_PER_NODE ) + count = FTC_SBIT_ITEMS_PER_NODE; + + FTC_GNode_Init( FTC_GNODE( snode ), start, family ); + + snode->count = count; + for ( node_count = 0; node_count < count; node_count++ ) + { + snode->sbits[node_count].width = 255; + snode->sbits[node_count].height = 0; + snode->sbits[node_count].buffer = NULL; + } + + error = ftc_snode_load( snode, + cache->manager, + gindex, + NULL ); + if ( error ) + { + FTC_SNode_Free( snode, cache ); + snode = NULL; + } + } + + Exit: + *psnode = snode; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + ftc_snode_new( FTC_Node *ftcpsnode, + FT_Pointer ftcgquery, + FTC_Cache cache ) + { + FTC_SNode *psnode = (FTC_SNode*)ftcpsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + + + return FTC_SNode_New( psnode, gquery, cache ); + } + + + FT_LOCAL_DEF( FT_Offset ) + ftc_snode_weight( FTC_Node ftcsnode, + FTC_Cache cache ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FT_UInt count = snode->count; + FTC_SBit sbit = snode->sbits; + FT_Int pitch; + FT_Offset size; + + FT_UNUSED( cache ); + + + FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE ); + + /* the node itself */ + size = sizeof ( *snode ); + + for ( ; count > 0; count--, sbit++ ) + { + if ( sbit->buffer ) + { + pitch = sbit->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + /* add the size of a given glyph image */ + size += (FT_Offset)pitch * sbit->height; + } + } + + return size; + } + + +#if 0 + + FT_LOCAL_DEF( FT_Offset ) + FTC_SNode_Weight( FTC_SNode snode ) + { + return ftc_snode_weight( FTC_NODE( snode ), NULL ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Bool ) + ftc_snode_compare( FTC_Node ftcsnode, + FT_Pointer ftcgquery, + FTC_Cache cache, + FT_Bool* list_changed ) + { + FTC_SNode snode = (FTC_SNode)ftcsnode; + FTC_GQuery gquery = (FTC_GQuery)ftcgquery; + FTC_GNode gnode = FTC_GNODE( snode ); + FT_UInt gindex = gquery->gindex; + FT_Bool result; + + + if ( list_changed ) + *list_changed = FALSE; + result = FT_BOOL( gnode->family == gquery->family && + gindex - gnode->gindex < snode->count ); + if ( result ) + { + /* check if we need to load the glyph bitmap now */ + FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex ); + + + /* + * The following code illustrates what to do when you want to + * perform operations that may fail within a lookup function. + * + * Here, we want to load a small bitmap on-demand; we thus + * need to call the `ftc_snode_load' function which may return + * a non-zero error code only when we are out of memory (OOM). + * + * The correct thing to do is to use @FTC_CACHE_TRYLOOP and + * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop + * that is capable of flushing the cache incrementally when + * an OOM errors occur. + * + * However, we need to `lock' the node before this operation to + * prevent it from being flushed within the loop. + * + * When we exit the loop, we unlock the node, then check the `error' + * variable. If it is non-zero, this means that the cache was + * completely flushed and that no usable memory was found to load + * the bitmap. + * + * We then prefer to return a value of 0 (i.e., NO MATCH). This + * ensures that the caller will try to allocate a new node. + * This operation consequently _fail_ and the lookup function + * returns the appropriate OOM error code. + * + * Note that `buffer == NULL && width == 255' is a hack used to + * tag `unavailable' bitmaps in the array. We should never try + * to load these. + * + */ + + if ( !sbit->buffer && sbit->width == 255 ) + { + FT_ULong size; + FT_Error error; + + + ftcsnode->ref_count++; /* lock node to prevent flushing */ + /* in retry loop */ + + FTC_CACHE_TRYLOOP( cache ) + { + error = ftc_snode_load( snode, cache->manager, gindex, &size ); + } + FTC_CACHE_TRYLOOP_END( list_changed ) + + ftcsnode->ref_count--; /* unlock the node */ + + if ( error ) + result = 0; + else + cache->manager->cur_weight += size; + } + } + + return result; + } + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cache/ftcsbits.h b/Dependencies/freetype/freetype/src/cache/ftcsbits.h new file mode 100644 index 00000000..d7c4a364 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cache/ftcsbits.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * ftcsbits.h + * + * A small-bitmap cache (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTCSBITS_H_ +#define FTCSBITS_H_ + + +#include +#include "ftcglyph.h" + + +FT_BEGIN_HEADER + +#define FTC_SBIT_ITEMS_PER_NODE 16 + + typedef struct FTC_SNodeRec_ + { + FTC_GNodeRec gnode; + FT_UInt count; + FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE]; + + } FTC_SNodeRec, *FTC_SNode; + + +#define FTC_SNODE( x ) ( (FTC_SNode)( x ) ) +#define FTC_SNODE_GINDEX( x ) FTC_GNODE( x )->gindex +#define FTC_SNODE_FAMILY( x ) FTC_GNODE( x )->family + + typedef FT_UInt + (*FTC_SFamily_GetCountFunc)( FTC_Family family, + FTC_Manager manager ); + + typedef FT_Error + (*FTC_SFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ); + + typedef struct FTC_SFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_SFamily_GetCountFunc family_get_count; + FTC_SFamily_LoadGlyphFunc family_load_glyph; + + } FTC_SFamilyClassRec; + + typedef const FTC_SFamilyClassRec* FTC_SFamilyClass; + +#define FTC_SFAMILY_CLASS( x ) ( (FTC_SFamilyClass)(x) ) + +#define FTC_CACHE_SFAMILY_CLASS( x ) \ + FTC_SFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) + + + FT_LOCAL( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ); + + FT_LOCAL( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ); + +#if 0 + FT_LOCAL( FT_ULong ) + FTC_SNode_Weight( FTC_SNode inode ); +#endif + + /* */ + +FT_END_HEADER + +#endif /* FTCSBITS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cff.c b/Dependencies/freetype/freetype/src/cff/cff.c new file mode 100644 index 00000000..e3e00969 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cff.c @@ -0,0 +1,28 @@ +/**************************************************************************** + * + * cff.c + * + * FreeType OpenType driver component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "cffcmap.c" +#include "cffdrivr.c" +#include "cffgload.c" +#include "cffparse.c" +#include "cffload.c" +#include "cffobjs.c" + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffcmap.c b/Dependencies/freetype/freetype/src/cff/cffcmap.c new file mode 100644 index 00000000..ea5f8ed2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffcmap.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * + * cffcmap.c + * + * CFF character mapping table (cmap) support (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "cffcmap.h" +#include "cffload.h" + +#include "cfferrs.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_encoding_init( FT_CMap cmap, + FT_Pointer pointer ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Encoding encoding = &cff->encoding; + + FT_UNUSED( pointer ); + + + cffcmap->gids = encoding->codes; + + return 0; + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_encoding_done( FT_CMap cmap ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + + + cffcmap->gids = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_index( FT_CMap cmap, + FT_UInt32 char_code ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; + + + if ( char_code < 256 ) + result = cffcmap->gids[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + while ( char_code < 255 ) + { + result = cffcmap->gids[++char_code]; + if ( result ) + { + *pchar_code = char_code; + break; + } + } + + return result; + } + + + FT_DEFINE_CMAP_CLASS( + cff_cmap_encoding_class_rec, + + sizeof ( CFF_CMapStdRec ), + + (FT_CMap_InitFunc) cff_cmap_encoding_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_encoding_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char* ) + cff_sid_to_glyph_name( void* face_, /* TT_Face */ + FT_UInt idx ) + { + TT_Face face = (TT_Face)face_; + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_UInt sid = charset->sids[idx]; + + + return cff_index_get_sid_string( cff, sid ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + CFF_Font cff = (CFF_Font)face->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + FT_UNUSED( pointer ); + + + /* can't build Unicode map for CID-keyed font */ + /* because we don't know glyph names. */ + if ( !charset->sids ) + return FT_THROW( No_Unicode_Glyph_Name ); + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + cff->num_glyphs, + &cff_sid_to_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_DEFINE_CMAP_CLASS( + cff_cmap_unicode_class_rec, + + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) cff_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffcmap.h b/Dependencies/freetype/freetype/src/cff/cffcmap.h new file mode 100644 index 00000000..1dd8700c --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffcmap.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * + * cffcmap.h + * + * CFF character mapping table (cmap) support (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFCMAP_H_ +#define CFFCMAP_H_ + +#include + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct CFF_CMapStdRec_* CFF_CMapStd; + + typedef struct CFF_CMapStdRec_ + { + FT_CMapRec cmap; + FT_UShort* gids; /* up to 256 elements */ + + } CFF_CMapStdRec; + + + FT_DECLARE_CMAP_CLASS( cff_cmap_encoding_class_rec ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_DECLARE_CMAP_CLASS( cff_cmap_unicode_class_rec ) + + +FT_END_HEADER + +#endif /* CFFCMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffdrivr.c b/Dependencies/freetype/freetype/src/cff/cffdrivr.c new file mode 100644 index 00000000..f6ebdb38 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffdrivr.c @@ -0,0 +1,1263 @@ +/**************************************************************************** + * + * cffdrivr.c + * + * OpenType font driver implementation (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cffdrivr.h" +#include "cffgload.h" +#include "cffload.h" +#include "cffcmap.h" +#include "cffparse.h" +#include "cffobjs.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "cfferrs.h" + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffdriver + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * cff_get_kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings, are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_kerning( FT_Face face, /* CFF_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + CFF_Face cffface = (CFF_Face)face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * cff_glyph_load + * + * @Description: + * A driver method used to load a glyph within a given glyph slot. + * + * @Input: + * slot :: + * A handle to the target slot object where the glyph + * will be loaded. + * + * size :: + * A handle to the source face size at which the glyph + * must be scaled, loaded, etc. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_??? constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_CALLBACK_DEF( FT_Error ) + cff_glyph_load( FT_GlyphSlot slot, /* CFF_GlyphSlot */ + FT_Size size, /* CFF_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_GlyphSlot cffslot = (CFF_GlyphSlot)slot; + CFF_Size cffsize = (CFF_Size)size; + + + if ( !cffslot ) + return FT_THROW( Invalid_Slot_Handle ); + + FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index )); + + /* check whether we want a scaled outline or bitmap */ + if ( !cffsize ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + /* reset the size object if necessary */ + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + + if ( size ) + { + /* these two objects must have the same parent */ + if ( size->face != slot->face ) + return FT_THROW( Invalid_Face_Handle ); + } + + /* now load the glyph outline if necessary */ + error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ) + { + FT_UInt nn; + FT_Error error = FT_Err_Ok; + FT_GlyphSlot slot = face->glyph; + + + if ( FT_IS_SFNT( face ) ) + { + /* OpenType 1.7 mandates that the data from `hmtx' table be used; */ + /* it is no longer necessary that those values are identical to */ + /* the values in the `CFF' table */ + + CFF_Face cffface = (CFF_Face)face; + FT_Short dummy; + + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* check whether we have data from the `vmtx' table at all; */ + /* otherwise we extract the info from the CFF glyphstrings */ + /* (instead of synthesizing a global value using the `OS/2' */ + /* table) */ + if ( !cffface->vertical_info ) + goto Missing_Table; + + for ( nn = 0; nn < count; nn++ ) + { + FT_UShort ah; + + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + 1, + start + nn, + &dummy, + &ah ); + + FT_TRACE5(( " idx %d: advance height %d font unit%s\n", + start + nn, + ah, + ah == 1 ? "" : "s" )); + advances[nn] = ah; + } + } + else + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* check whether we have data from the `hmtx' table at all */ + if ( !cffface->horizontal.number_Of_HMetrics ) + goto Missing_Table; + + for ( nn = 0; nn < count; nn++ ) + { + FT_UShort aw; + + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + 0, + start + nn, + &dummy, + &aw ); + + FT_TRACE5(( " idx %d: advance width %d font unit%s\n", + start + nn, + aw, + aw == 1 ? "" : "s" )); + advances[nn] = aw; + } + } + + return error; + } + + Missing_Table: + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + + for ( nn = 0; nn < count; nn++ ) + { + error = cff_glyph_load( slot, face->size, start + nn, flags ); + if ( error ) + break; + + advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? slot->linearVertAdvance + : slot->linearHoriAdvance; + } + + return error; + } + + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_get_glyph_name( FT_Face face, /* CFF_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font font = (CFF_Font)cffface->extra.data; + FT_String* gname; + FT_UShort sid; + FT_Error error; + + + /* CFF2 table does not have glyph names; */ + /* we need to use `post' table method */ + if ( font->version_major == 2 ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_GlyphDict service = + (FT_Service_GlyphDict)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_GLYPH_DICT, + 0 ); + + + if ( service && service->get_name ) + return service->get_name( face, glyph_index, buffer, buffer_max ); + else + { + FT_ERROR(( "cff_get_glyph_name:" + " cannot get glyph name from a CFF2 font\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + } + + if ( !font->psnames ) + { + FT_ERROR(( "cff_get_glyph_name:" + " cannot get glyph name from CFF & CEF fonts\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + /* first, locate the sid in the charset table */ + sid = font->charset.sids[glyph_index]; + + /* now, look up the name itself */ + gname = cff_index_get_sid_string( font, sid ); + + if ( gname ) + FT_STRCPYN( buffer, gname, buffer_max ); + + error = FT_Err_Ok; + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + cff_get_name_index( FT_Face face, /* CFF_Face */ + const FT_String* glyph_name ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + CFF_Charset charset = &cff->charset; + FT_Service_PsCMaps psnames; + FT_String* name; + FT_UShort sid; + FT_UInt i; + + + /* CFF2 table does not have glyph names; */ + /* we need to use `post' table method */ + if ( cff->version_major == 2 ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_GlyphDict service = + (FT_Service_GlyphDict)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_GLYPH_DICT, + 0 ); + + + if ( service && service->name_index ) + return service->name_index( face, glyph_name ); + else + { + FT_ERROR(( "cff_get_name_index:" + " cannot get glyph index from a CFF2 font\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + return 0; + } + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + return 0; + + for ( i = 0; i < cff->num_glyphs; i++ ) + { + sid = charset->sids[i]; + + if ( sid > 390 ) + name = cff_index_get_string( cff, sid - 391 ); + else + name = (FT_String *)psnames->adobe_std_strings( sid ); + + if ( !name ) + continue; + + if ( !ft_strcmp( glyph_name, name ) ) + return i; + } + + return 0; + } + + + FT_DEFINE_SERVICE_GLYPHDICTREC( + cff_service_glyph_dict, + + cff_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + cff_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + ) + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Int ) + cff_ps_has_glyph_names( FT_Face face ) + { + return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_info( FT_Face face, /* CFF_Face */ + PS_FontInfoRec* afont_info ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; + + + if ( cffface->is_cff2 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( cff && !cff->font_info ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_FontInfoRec* font_info = NULL; + + + if ( FT_QNEW( font_info ) ) + goto Fail; + + font_info->version = cff_index_get_sid_string( cff, + dict->version ); + font_info->notice = cff_index_get_sid_string( cff, + dict->notice ); + font_info->full_name = cff_index_get_sid_string( cff, + dict->full_name ); + font_info->family_name = cff_index_get_sid_string( cff, + dict->family_name ); + font_info->weight = cff_index_get_sid_string( cff, + dict->weight ); + font_info->italic_angle = dict->italic_angle; + font_info->is_fixed_pitch = dict->is_fixed_pitch; + font_info->underline_position = (FT_Short)dict->underline_position; + font_info->underline_thickness = (FT_UShort)dict->underline_thickness; + + cff->font_info = font_info; + } + + if ( cff ) + *afont_info = *cff->font_info; + + Fail: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_extra( FT_Face face, /* CFF_Face */ + PS_FontExtraRec* afont_extra ) + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; + + + if ( cff && !cff->font_extra ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_FontExtraRec* font_extra = NULL; + FT_String* embedded_postscript; + + + if ( FT_QNEW( font_extra ) ) + goto Fail; + + font_extra->fs_type = 0U; + + embedded_postscript = cff_index_get_sid_string( + cff, + dict->embedded_postscript ); + if ( embedded_postscript ) + { + FT_String* start_fstype; + FT_String* start_def; + + + /* Identify the XYZ integer in `/FSType XYZ def' substring. */ + if ( ( start_fstype = ft_strstr( embedded_postscript, + "/FSType" ) ) != NULL && + ( start_def = ft_strstr( start_fstype + + sizeof ( "/FSType" ) - 1, + "def" ) ) != NULL ) + { + FT_String* s; + + + for ( s = start_fstype + sizeof ( "/FSType" ) - 1; + s != start_def; + s++ ) + { + if ( *s >= '0' && *s <= '9' ) + { + if ( font_extra->fs_type >= ( FT_USHORT_MAX - 9 ) / 10 ) + { + /* Overflow - ignore the FSType value. */ + font_extra->fs_type = 0U; + break; + } + + font_extra->fs_type *= 10; + font_extra->fs_type += (FT_UShort)( *s - '0' ); + } + else if ( *s != ' ' && *s != '\n' && *s != '\r' ) + { + /* Non-whitespace character between `/FSType' and next `def' */ + /* - ignore the FSType value. */ + font_extra->fs_type = 0U; + break; + } + } + } + } + + cff->font_extra = font_extra; + } + + if ( cff ) + *afont_extra = *cff->font_extra; + + Fail: + return error; + } + + + FT_DEFINE_SERVICE_PSINFOREC( + cff_service_ps_info, + + cff_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cff_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + cff_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + /* unsupported with CFF fonts */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ + /* not implemented */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ + ) + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + cff_get_ps_name( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + + + /* following the OpenType specification 1.7, we return the name stored */ + /* in the `name' table for a CFF wrapped into an SFNT container */ + + if ( FT_IS_SFNT( face ) && sfnt ) + { + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); + FT_Service_PsFontName service = + (FT_Service_PsFontName)ft_module_get_service( + sfnt_module, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, + 0 ); + + + if ( service && service->get_ps_font_name ) + return service->get_ps_font_name( face ); + } + + return cff ? (const char*)cff->font_name : NULL; + } + + + FT_DEFINE_SERVICE_PSFONTNAMEREC( + cff_service_ps_name, + + cff_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ + ) + + + /* + * TT CMAP INFO + * + * If the charmap is a synthetic Unicode encoding cmap or + * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO + * service defined in SFNT module. + * + * Otherwise call the service function in the sfnt module. + * + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + FT_Error error = FT_Err_Ok; + + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Library library = FT_FACE_LIBRARY( face ); + + + if ( cmap->clazz != &cff_cmap_encoding_class_rec && + cmap->clazz != &cff_cmap_unicode_class_rec ) + { + FT_Module sfnt = FT_Get_Module( library, "sfnt" ); + FT_Service_TTCMaps service = + (FT_Service_TTCMaps)ft_module_get_service( sfnt, + FT_SERVICE_ID_TT_CMAP, + 0 ); + + + if ( service && service->get_cmap_info ) + error = service->get_cmap_info( charmap, cmap_info ); + } + else + error = FT_THROW( Invalid_CharMap_Format ); + + return error; + } + + + FT_DEFINE_SERVICE_TTCMAPSREC( + cff_service_get_cmap_info, + + cff_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ + ) + + + /* + * CID INFO SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + cff_get_ros( FT_Face face, /* FT_Face */ + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry == 0xFFFFU ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( registry ) + { + if ( !cff->registry ) + cff->registry = cff_index_get_sid_string( cff, + dict->cid_registry ); + *registry = cff->registry; + } + + if ( ordering ) + { + if ( !cff->ordering ) + cff->ordering = cff_index_get_sid_string( cff, + dict->cid_ordering ); + *ordering = cff->ordering; + } + + /* + * XXX: According to Adobe TechNote #5176, the supplement in CFF + * can be a real number. We truncate it to fit public API + * since freetype-2.3.6. + */ + if ( supplement ) + { + if ( dict->cid_supplement < FT_INT_MIN || + dict->cid_supplement > FT_INT_MAX ) + FT_TRACE1(( "cff_get_ros: too large supplement %ld is truncated\n", + dict->cid_supplement )); + *supplement = (FT_Int)dict->cid_supplement; + } + } + + Fail: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_is_cid( FT_Face face, /* CFF_Face */ + FT_Bool *is_cid ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + *is_cid = 0; + + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry != 0xFFFFU ) + *is_cid = 1; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_cid_from_glyph_index( FT_Face face, /* CFF_Face */ + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + + if ( cff ) + { + FT_UInt c; + CFF_FontRecDict dict = &cff->top_font.font_dict; + + + if ( dict->cid_registry == 0xFFFFU ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + if ( glyph_index >= cff->num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + + c = cff->charset.sids[glyph_index]; + + if ( cid ) + *cid = c; + } + + Fail: + return error; + } + + + FT_DEFINE_SERVICE_CIDREC( + cff_service_cid_info, + + cff_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cff_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cff_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ + ) + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + cff_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* + * MULTIPLE MASTER SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_blend( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_mm_blend( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_blend( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_blend( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_weightvector( FT_Face face, /* CFF_Face */ + FT_UInt len, + FT_Fixed* weightvector ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_mm_weightvector( face, len, weightvector ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_weightvector( FT_Face face, /* CFF_Face */ + FT_UInt* len, + FT_Fixed* weightvector ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_weightvector( face, len, weightvector ); + } + + + FT_CALLBACK_DEF( void ) + cff_construct_ps_name( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->construct_ps_name( face ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_var( FT_Face face, /* CFF_Face */ + FT_MM_Var* *master ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_mm_var( face, master ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_var_design( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_var_design( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_var_design( FT_Face face, /* CFF_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_var_design( face, num_coords, coords ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_set_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt instance_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->set_named_instance( face, instance_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_default_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt *instance_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_default_named_instance( face, instance_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_item_variation_store( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_item_var_store( face, offset, itemStore ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_delta_set_index_mapping( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_delta_set_idx_map( face, offset, map, + itemStore, table_len ); + } + + + FT_CALLBACK_DEF( FT_Int ) + cff_get_item_delta( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_item_delta( face, itemStore, outerIndex, innerIndex ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_item_variation_store( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_item_var_store( face, itemStore ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_delta_set_index_map( FT_Face face, /* CFF_Face */ + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_delta_set_idx_map( face, deltaSetIdxMap ); + } + + + + FT_DEFINE_SERVICE_MULTIMASTERSREC( + cff_service_multi_masters, + + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + cff_set_mm_blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + cff_get_mm_blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + cff_get_mm_var, /* FT_Get_MM_Var_Func get_mm_var */ + cff_set_var_design, /* FT_Set_Var_Design_Func set_var_design */ + cff_get_var_design, /* FT_Get_Var_Design_Func get_var_design */ + cff_set_named_instance, + /* FT_Set_Named_Instance_Func set_named_instance */ + cff_get_default_named_instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + cff_set_mm_weightvector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + cff_get_mm_weightvector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + cff_construct_ps_name, + /* FT_Construct_PS_Name_Func construct_ps_name */ + cff_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + cff_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + cff_get_item_delta, + /* FT_Var_Get_Item_Delta_Func get_item_delta */ + cff_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + cff_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + cff_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + cff_done_blend /* FT_Done_Blend_Func done_blend */ + ) + + + /* + * METRICS VARIATIONS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_hadvance_adjust( FT_Face face, /* CFF_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; + + + return var->hadvance_adjust( face, gindex, avalue ); + } + + + FT_CALLBACK_DEF( void ) + cff_metrics_adjust( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; + + + var->metrics_adjust( face ); + } + + + FT_DEFINE_SERVICE_METRICSVARIATIONSREC( + cff_service_metrics_variations, + + cff_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ + + NULL, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ + + cff_metrics_adjust, /* FT_Metrics_Adjust_Func metrics_adjust */ + NULL /* FT_Size_Reset_Func size_reset */ + ) +#endif + + + /* + * CFFLOAD SERVICE + * + */ + + FT_DEFINE_SERVICE_CFFLOADREC( + cff_service_cff_load, + + cff_get_standard_encoding, /* FT_Get_Standard_Encoding_Func get_standard_encoding */ + cff_load_private_dict, /* FT_Load_Private_Dict_Func load_private_dict */ + cff_fd_select_get, /* FT_FD_Select_Get_Func fd_select_get */ + cff_blend_check_vector, /* FT_Blend_Check_Vector_Func blend_check_vector */ + cff_blend_build_vector /* FT_Blend_Build_Vector_Func blend_build_vector */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#if defined TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC10( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_MULTI_MASTERS, &cff_service_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &cff_service_metrics_variations, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) +#else + FT_DEFINE_SERVICEDESCREC8( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cff_get_interface( FT_Module driver, /* CFF_Driver */ + const char* module_interface ) + { + FT_Library library; + FT_Module sfnt; + FT_Module_Interface result; + + + result = ft_service_list_lookup( cff_services, module_interface ); + if ( result ) + return result; + + /* `driver' is not yet evaluated */ + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; + + /* we pass our request to the `sfnt' module */ + sfnt = FT_Get_Module( library, "sfnt" ); + + return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define CFF_SIZE_SELECT cff_size_select +#else +#define CFF_SIZE_SELECT 0 +#endif + + FT_DEFINE_DRIVER( + cff_driver_class, + + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER | + FT_MODULE_DRIVER_HINTS_LIGHTLY, + + sizeof ( PS_DriverRec ), + "cff", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + cff_driver_init, /* FT_Module_Constructor module_init */ + cff_driver_done, /* FT_Module_Destructor module_done */ + cff_get_interface, /* FT_Module_Requester get_interface */ + + sizeof ( TT_FaceRec ), + sizeof ( CFF_SizeRec ), + sizeof ( CFF_GlyphSlotRec ), + + cff_face_init, /* FT_Face_InitFunc init_face */ + cff_face_done, /* FT_Face_DoneFunc done_face */ + cff_size_init, /* FT_Size_InitFunc init_size */ + cff_size_done, /* FT_Size_DoneFunc done_size */ + cff_slot_init, /* FT_Slot_InitFunc init_slot */ + cff_slot_done, /* FT_Slot_DoneFunc done_slot */ + + cff_glyph_load, /* FT_Slot_LoadFunc load_glyph */ + + cff_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + cff_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ + + cff_size_request, /* FT_Size_RequestFunc request_size */ + CFF_SIZE_SELECT /* FT_Size_SelectFunc select_size */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffdrivr.h b/Dependencies/freetype/freetype/src/cff/cffdrivr.h new file mode 100644 index 00000000..fd5bc37e --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffdrivr.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * cffdrivr.h + * + * High-level OpenType driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFDRIVER_H_ +#define CFFDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_DRIVER( cff_driver_class ) + +FT_END_HEADER + +#endif /* CFFDRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cfferrs.h b/Dependencies/freetype/freetype/src/cff/cfferrs.h new file mode 100644 index 00000000..128adc3b --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cfferrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * cfferrs.h + * + * CFF error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the CFF error enumeration constants. + * + */ + +#ifndef CFFERRS_H_ +#define CFFERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CFF_Err_ +#define FT_ERR_BASE FT_Mod_Err_CFF + + +#include + +#endif /* CFFERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffgload.c b/Dependencies/freetype/freetype/src/cff/cffgload.c new file mode 100644 index 00000000..cbb071ab --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffgload.c @@ -0,0 +1,762 @@ +/**************************************************************************** + * + * cffgload.c + * + * OpenType Glyph Loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "cffload.h" +#include "cffgload.h" + +#include "cfferrs.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffgload + + + FT_LOCAL_DEF( FT_Error ) + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + FT_Error error = + face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &data ); + + + *pointer = (FT_Byte*)data.pointer; + *length = data.length; + + return error; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + return cff_index_access_element( &cff->charstrings_index, glyph_index, + pointer, length ); + } + } + + + FT_LOCAL_DEF( void ) + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ) + { +#ifndef FT_CONFIG_OPTION_INCREMENTAL + FT_UNUSED( length ); +#endif + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( face->root.internal->incremental_interface ) + { + FT_Data data; + + + data.pointer = *pointer; + data.length = (FT_UInt)length; + + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, &data ); + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + cff_index_forget_element( &cff->charstrings_index, pointer ); + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#if 0 /* unused until we support pure CFF fonts */ + + + FT_LOCAL_DEF( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ) + { + FT_Error error = FT_Err_Ok; + CFF_Decoder decoder; + FT_Int glyph_index; + CFF_Font cff = (CFF_Font)face->other; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; + + + *max_advance = 0; + + /* Initialize load decoder */ + decoder_funcs->init( &decoder, face, 0, 0, 0, 0, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width. */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + FT_Byte* charstring; + FT_ULong charstring_len; + + + /* now get load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( !error ) + { + error = decoder_funcs->prepare( &decoder, size, glyph_index ); + if ( !error ) + error = decoder_funcs->parse_charstrings_old( &decoder, + charstring, + charstring_len, + 0 ); + + cff_free_glyph_data( face, &charstring, &charstring_len ); + } + + /* ignore the error if one has occurred -- skip to next glyph */ + error = FT_Err_Ok; + } + + *max_advance = decoder.builder.advance.x; + + return FT_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_Decoder decoder; + PS_Decoder psdecoder; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting, scaled, force_scaling; + CFF_Font cff = (CFF_Font)face->extra.data; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; + + FT_Matrix font_matrix; + FT_Vector font_offset; + + + force_scaling = FALSE; + + /* in a CID-keyed font, consider `glyph_index' as a CID and map */ + /* it immediately to the real glyph_index -- if it isn't a */ + /* subsetted font, glyph_indices and CIDs are identical, though */ + if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && + cff->charset.cids ) + { + /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */ + if ( glyph_index != 0 ) + { + glyph_index = cff_charset_cid_to_gindex( &cff->charset, + glyph_index ); + if ( glyph_index == 0 ) + return FT_THROW( Invalid_Argument ); + } + } + else if ( glyph_index >= cff->num_glyphs ) + return FT_THROW( Invalid_Argument ); + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + if ( size ) + { + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap if any */ + /* */ + /* XXX: The convention should be emphasized in */ + /* the documents because it can be confusing. */ + if ( size ) + { + CFF_Face cff_face = (CFF_Face)size->root.face; + SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; + FT_Stream stream = cff_face->root.stream; + + + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( size->root.face ) ) + { + TT_SBit_MetricsRec metrics; + + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_UInt)load_flags, + stream, + &glyph->root.bitmap, + &metrics ); + + if ( !error ) + { + FT_Bool has_vertical_info; + FT_UShort advance; + FT_Short dummy; + + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + glyph->root.metrics.width = (FT_Pos)metrics.width * 64; + glyph->root.metrics.height = (FT_Pos)metrics.height * 64; + + glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64; + glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64; + glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64; + + glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64; + glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64; + glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64; + + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->root.bitmap_left = metrics.vertBearingX; + glyph->root.bitmap_top = metrics.vertBearingY; + } + else + { + glyph->root.bitmap_left = metrics.horiBearingX; + glyph->root.bitmap_top = metrics.horiBearingY; + } + + /* compute linear advance widths */ + + (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0, + glyph_index, + &dummy, + &advance ); + glyph->root.linearHoriAdvance = advance; + + has_vertical_info = FT_BOOL( + face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ); + + /* get the vertical metrics from the vmtx table if we have one */ + if ( has_vertical_info ) + { + (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1, + glyph_index, + &dummy, + &advance ); + glyph->root.linearVertAdvance = advance; + } + else + { + /* make up vertical ones */ + if ( face->os2.version != 0xFFFFU ) + glyph->root.linearVertAdvance = (FT_Pos) + ( face->os2.sTypoAscender - face->os2.sTypoDescender ); + else + glyph->root.linearVertAdvance = (FT_Pos) + ( face->horizontal.Ascender - face->horizontal.Descender ); + } + + return error; + } + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* return immediately if we only want the embedded bitmaps */ + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return FT_THROW( Invalid_Argument ); + +#ifdef FT_CONFIG_OPTION_SVG + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + /* + * We load the SVG document and try to grab the advances from the + * table. For the bearings we rely on the presetting hook to do that. + */ + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + if ( size && (size->root.metrics.x_ppem < 1 || + size->root.metrics.y_ppem < 1 ) ) + { + error = FT_THROW( Invalid_Size_Handle ); + return error; + } + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short dummy; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->root.format = FT_GLYPH_FORMAT_SVG; + + /* + * If horizontal or vertical advances are not present in the table, + * this is a problem with the font since the standard requires them. + * However, we are graceful and calculate the values by ourselves + * for the vertical case. + */ + sfnt->get_metrics( face, + FALSE, + glyph_index, + &dummy, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &dummy, + &advanceY ); + + glyph->root.linearHoriAdvance = advanceX; + glyph->root.linearVertAdvance = advanceY; + + glyph->root.metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->root.metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + /* if we have a CID subfont, use its matrix (which has already */ + /* been multiplied with the root matrix) */ + + /* this scaling is only relevant if the PS hinter isn't active */ + if ( cff->num_subfonts ) + { + FT_Long top_upm, sub_upm; + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, + glyph_index ); + + + if ( fd_index >= cff->num_subfonts ) + fd_index = (FT_Byte)( cff->num_subfonts - 1 ); + + top_upm = (FT_Long)cff->top_font.font_dict.units_per_em; + sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em; + + font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; + font_offset = cff->subfonts[fd_index]->font_dict.font_offset; + + if ( top_upm != sub_upm ) + { + glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm ); + glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm ); + + force_scaling = TRUE; + } + } + else + { + font_matrix = cff->top_font.font_dict.font_matrix; + font_offset = cff->top_font.font_dict.font_offset; + } + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + /* top-level code ensures that FT_LOAD_NO_HINTING is set */ + /* if FT_LOAD_NO_SCALE is active */ + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ + + { +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); +#endif + + FT_Byte* charstring; + FT_ULong charstring_len; + + + decoder_funcs->init( &decoder, face, size, glyph, hinting, + FT_LOAD_TARGET_MODE( load_flags ), + cff_get_glyph_data, + cff_free_glyph_data ); + + /* this is for pure CFFs */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY ) + decoder.width_only = TRUE; + + decoder.builder.no_recurse = + FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + /* this function also checks for a valid subfont index */ + error = decoder_funcs->prepare( &decoder, size, glyph_index ); + if ( error ) + goto Glyph_Build_Finished; + + /* now load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( error ) + goto Glyph_Build_Finished; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + /* choose which CFF renderer to use */ + if ( driver->hinting_engine == FT_HINTING_FREETYPE ) + error = decoder_funcs->parse_charstrings_old( &decoder, + charstring, + charstring_len, + 0 ); + else +#endif + { + psaux->ps_decoder_init( &psdecoder, &decoder, FALSE ); + + error = decoder_funcs->parse_charstrings( &psdecoder, + charstring, + charstring_len ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + hinting = FALSE; + force_scaling = TRUE; + glyph->hint = hinting; + + error = decoder_funcs->parse_charstrings( &psdecoder, + charstring, + charstring_len ); + } + } + + cff_free_glyph_data( face, &charstring, charstring_len ); + + if ( error ) + goto Glyph_Build_Finished; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Control data and length may not be available for incremental */ + /* fonts. */ + if ( face->root.internal->incremental_interface ) + { + glyph->root.control_data = NULL; + glyph->root.control_len = 0; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* We set control_data and control_len if charstrings is loaded. */ + /* See how charstring loads at cff_index_access_element() in */ + /* cffload.c. */ + { + CFF_Index csindex = &cff->charstrings_index; + + + if ( csindex->offsets ) + { + glyph->root.control_data = csindex->bytes + + csindex->offsets[glyph_index] - 1; + glyph->root.control_len = (FT_Long)charstring_len; + } + } + + Glyph_Build_Finished: + /* save new glyph tables, if no error */ + if ( !error ) + decoder.builder.funcs.done( &decoder.builder ); + /* XXX: anything to do for broken glyph entry? */ + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && + face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = decoder.builder.left_bearing.x; + metrics.bearing_y = 0; + metrics.advance = decoder.builder.advance.x; + metrics.advance_v = decoder.builder.advance.y; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + + decoder.builder.left_bearing.x = metrics.bearing_x; + decoder.builder.advance.x = metrics.advance; + decoder.builder.advance.y = metrics.advance_v; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + if ( !error ) + { + /* Now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax. */ + + /* For composite glyphs, return only left side bearing and */ + /* advance width. */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = glyph->root.internal; + + + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.glyph_width; + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + FT_Bool has_vertical_info; + + + if ( face->horizontal.number_Of_HMetrics ) + { + FT_Short horiBearingX = 0; + FT_UShort horiAdvance = 0; + + + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, + glyph_index, + &horiBearingX, + &horiAdvance ); + metrics->horiAdvance = horiAdvance; + metrics->horiBearingX = horiBearingX; + glyph->root.linearHoriAdvance = horiAdvance; + } + else + { + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.glyph_width; + glyph->root.linearHoriAdvance = decoder.glyph_width; + } + + glyph->root.internal->glyph_transformed = 0; + + has_vertical_info = FT_BOOL( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ); + + /* get the vertical metrics from the vmtx table if we have one */ + if ( has_vertical_info ) + { + FT_Short vertBearingY = 0; + FT_UShort vertAdvance = 0; + + + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, + glyph_index, + &vertBearingY, + &vertAdvance ); + metrics->vertBearingY = vertBearingY; + metrics->vertAdvance = vertAdvance; + } + else + { + /* make up vertical ones */ + if ( face->os2.version != 0xFFFFU ) + metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + } + + glyph->root.linearVertAdvance = metrics->vertAdvance; + + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + glyph->root.outline.flags = 0; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &glyph->root.outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &glyph->root.outline; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( has_vertical_info ) + { + metrics->vertBearingX = metrics->horiBearingX - + metrics->horiAdvance / 2; + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, + glyph->y_scale ); + } + else + { + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + } + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffgload.h b/Dependencies/freetype/freetype/src/cff/cffgload.h new file mode 100644 index 00000000..346d4b11 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffgload.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * cffgload.h + * + * OpenType Glyph Loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFGLOAD_H_ +#define CFFGLOAD_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ); + FT_LOCAL( void ) + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ); + + +#if 0 /* unused until we support pure CFF fonts */ + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + + FT_LOCAL( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* CFFGLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffload.c b/Dependencies/freetype/freetype/src/cff/cffload.c new file mode 100644 index 00000000..979fd45f --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffload.c @@ -0,0 +1,2570 @@ +/**************************************************************************** + * + * cffload.c + * + * OpenType and CFF data/program tables loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "cffload.h" +#include "cffparse.h" + +#include "cfferrs.h" + + +#define FT_FIXED_ONE ( (FT_Fixed)0x10000 ) + + +#if 1 + + static const FT_UShort cff_isoadobe_charset[229] = + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228 + }; + + static const FT_UShort cff_expert_charset[166] = + { + 0, 1, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 + }; + + static const FT_UShort cff_expertsubset_charset[87] = + { + 0, 1, 231, 232, 235, 236, 237, 238, + 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, + 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 + }; + + static const FT_UShort cff_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, + 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, + 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, + 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, + 146, 147, 148, 149, 0, 0, 0, 0 + }; + + static const FT_UShort cff_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 0, 0, + 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, + 110, 267, 268, 269, 0, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, + 309, 310, 311, 0, 312, 0, 0, 312, + 0, 0, 314, 315, 0, 0, 316, 317, + 318, 0, 0, 0, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 0, 0, + 326, 150, 164, 169, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378 + }; + +#endif /* 1 */ + + + FT_LOCAL_DEF( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ) + { + return (FT_UShort)( charcode < 256 ? cff_standard_encoding[charcode] + : 0 ); + } + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffload + + + /* read an offset from the index's stream current position */ + static FT_ULong + cff_index_read_offset( CFF_Index idx, + FT_Error *errorp ) + { + FT_Error error; + FT_Stream stream = idx->stream; + FT_Byte tmp[4]; + FT_ULong result = 0; + + + if ( !FT_STREAM_READ( tmp, idx->off_size ) ) + { + FT_Int nn; + + + for ( nn = 0; nn < idx->off_size; nn++ ) + result = ( result << 8 ) | tmp[nn]; + } + + *errorp = error; + return result; + } + + + static FT_Error + cff_index_init( CFF_Index idx, + FT_Stream stream, + FT_Bool load, + FT_Bool cff2 ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt count; + + + FT_ZERO( idx ); + + idx->stream = stream; + idx->start = FT_STREAM_POS(); + + if ( cff2 ) + { + if ( FT_READ_ULONG( count ) ) + goto Exit; + idx->hdr_size = 5; + } + else + { + if ( FT_READ_USHORT( count ) ) + goto Exit; + idx->hdr_size = 3; + } + + if ( count > 0 ) + { + FT_Byte offsize; + FT_ULong size; + + + /* there is at least one element; read the offset size, */ + /* then access the offset table to compute the index's total size */ + if ( FT_READ_BYTE( offsize ) ) + goto Exit; + + if ( offsize < 1 || offsize > 4 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + idx->count = count; + idx->off_size = offsize; + size = (FT_ULong)( count + 1 ) * offsize; + + idx->data_offset = idx->start + idx->hdr_size + size; + + if ( FT_STREAM_SKIP( size - offsize ) ) + goto Exit; + + size = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( size == 0 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + idx->data_size = --size; + + if ( load ) + { + /* load the data */ + if ( FT_FRAME_EXTRACT( size, idx->bytes ) ) + goto Exit; + } + else + { + /* skip the data */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + static void + cff_index_done( CFF_Index idx ) + { + if ( idx->stream ) + { + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->bytes ) + FT_FRAME_RELEASE( idx->bytes ); + + FT_FREE( idx->offsets ); + FT_ZERO( idx ); + } + } + + + static FT_Error + cff_index_load_offsets( CFF_Index idx ) + { + FT_Error error = FT_Err_Ok; + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + + + if ( idx->count > 0 && !idx->offsets ) + { + FT_Byte offsize = idx->off_size; + FT_ULong data_size; + FT_Byte* p; + FT_Byte* p_end; + FT_ULong* poff; + + + data_size = (FT_ULong)( idx->count + 1 ) * offsize; + + if ( FT_QNEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + idx->hdr_size ) || + FT_FRAME_ENTER( data_size ) ) + goto Exit; + + poff = idx->offsets; + p = (FT_Byte*)stream->cursor; + p_end = p + data_size; + + switch ( offsize ) + { + case 1: + for ( ; p < p_end; p++, poff++ ) + poff[0] = p[0]; + break; + + case 2: + for ( ; p < p_end; p += 2, poff++ ) + poff[0] = FT_PEEK_USHORT( p ); + break; + + case 3: + for ( ; p < p_end; p += 3, poff++ ) + poff[0] = FT_PEEK_UOFF3( p ); + break; + + default: + for ( ; p < p_end; p += 4, poff++ ) + poff[0] = FT_PEEK_ULONG( p ); + } + + FT_FRAME_EXIT(); + } + + Exit: + if ( error ) + FT_FREE( idx->offsets ); + + return error; + } + + + /* Allocate a table containing pointers to an index's elements. */ + /* The `pool' argument makes this function convert the index */ + /* entries to C-style strings (that is, null-terminated). */ + static FT_Error + cff_index_get_pointers( CFF_Index idx, + FT_Byte*** table, + FT_Byte** pool, + FT_ULong* pool_size ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = idx->stream->memory; + + FT_Byte** tbl = NULL; + FT_Byte* new_bytes = NULL; + FT_ULong new_size; + + + *table = NULL; + + if ( !idx->offsets ) + { + error = cff_index_load_offsets( idx ); + if ( error ) + goto Exit; + } + + new_size = idx->data_size + idx->count; + + if ( idx->count > 0 && + !FT_QNEW_ARRAY( tbl, idx->count + 1 ) && + ( !pool || !FT_ALLOC( new_bytes, new_size ) ) ) + { + FT_ULong n, cur_offset; + FT_ULong extra = 0; + FT_Byte* org_bytes = idx->bytes; + + + /* at this point, `idx->offsets' can't be NULL */ + cur_offset = idx->offsets[0] - 1; + + /* sanity check */ + if ( cur_offset != 0 ) + { + FT_TRACE0(( "cff_index_get_pointers:" + " invalid first offset value %ld set to zero\n", + cur_offset )); + cur_offset = 0; + } + + if ( !pool ) + tbl[0] = org_bytes + cur_offset; + else + tbl[0] = new_bytes + cur_offset; + + for ( n = 1; n <= idx->count; n++ ) + { + FT_ULong next_offset = idx->offsets[n] - 1; + + + /* two sanity checks for invalid offset tables */ + if ( next_offset < cur_offset ) + next_offset = cur_offset; + else if ( next_offset > idx->data_size ) + next_offset = idx->data_size; + + if ( !pool ) + tbl[n] = org_bytes + next_offset; + else + { + tbl[n] = new_bytes + next_offset + extra; + + if ( next_offset != cur_offset ) + { + FT_MEM_COPY( tbl[n - 1], + org_bytes + cur_offset, + tbl[n] - tbl[n - 1] ); + tbl[n][0] = '\0'; + tbl[n] += 1; + extra++; + } + } + + cur_offset = next_offset; + } + *table = tbl; + + if ( pool ) + *pool = new_bytes; + if ( pool_size ) + *pool_size = new_size; + } + + Exit: + if ( error && new_bytes ) + FT_FREE( new_bytes ); + if ( error && tbl ) + FT_FREE( tbl ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ) + { + FT_Error error = FT_Err_Ok; + + + if ( idx && idx->count > element ) + { + /* compute start and end offsets */ + FT_Stream stream = idx->stream; + FT_ULong off1, off2 = 0; + + + /* load offsets from file or the offset table */ + if ( !idx->offsets ) + { + FT_ULong pos = element * idx->off_size; + + + if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) ) + goto Exit; + + off1 = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + + if ( off1 != 0 ) + { + do + { + element++; + off2 = cff_index_read_offset( idx, &error ); + + } while ( off2 == 0 && element < idx->count ); + } + } + else /* use offsets table */ + { + off1 = idx->offsets[element]; + if ( off1 ) + { + do + { + element++; + off2 = idx->offsets[element]; + + } while ( off2 == 0 && element < idx->count ); + } + } + + /* XXX: should check off2 does not exceed the end of this entry; */ + /* at present, only truncate off2 at the end of this stream */ + if ( off2 > stream->size + 1 || + idx->data_offset > stream->size - off2 + 1 ) + { + FT_ERROR(( "cff_index_access_element:" + " offset to next entry (%ld)" + " exceeds the end of stream (%ld)\n", + off2, stream->size - idx->data_offset + 1 )); + off2 = stream->size - idx->data_offset + 1; + } + + /* access element */ + if ( off1 && off2 > off1 ) + { + *pbyte_len = off2 - off1; + + if ( idx->bytes ) + { + /* this index was completely loaded in memory, that's easy */ + *pbytes = idx->bytes + off1 - 1; + } + else + { + /* this index is still on disk/file, access it through a frame */ + if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) || + FT_FRAME_EXTRACT( off2 - off1, *pbytes ) ) + goto Exit; + } + } + else + { + /* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = FT_THROW( Invalid_Argument ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ) + { + if ( idx->bytes == 0 ) + { + FT_Stream stream = idx->stream; + + + FT_FRAME_RELEASE( *pbytes ); + } + } + + + /* get an entry from Name INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_name( CFF_Font font, + FT_UInt element ) + { + CFF_Index idx = &font->name_index; + FT_Memory memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = NULL; + + + if ( !idx->stream ) /* CFF2 does not include a name index */ + goto Exit; + + memory = idx->stream->memory; + + error = cff_index_access_element( idx, element, &bytes, &byte_len ); + if ( error ) + goto Exit; + + if ( !FT_QALLOC( name, byte_len + 1 ) ) + { + FT_MEM_COPY( name, bytes, byte_len ); + name[byte_len] = 0; + } + cff_index_forget_element( idx, &bytes ); + + Exit: + return name; + } + + + /* get an entry from String INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_string( CFF_Font font, + FT_UInt element ) + { + return ( element < font->num_strings ) + ? (FT_String*)font->strings[element] + : NULL; + } + + + FT_LOCAL_DEF( FT_String* ) + cff_index_get_sid_string( CFF_Font font, + FT_UInt sid ) + { + /* value 0xFFFFU indicates a missing dictionary entry */ + if ( sid == 0xFFFFU ) + return NULL; + + /* if it is not a standard string, return it */ + if ( sid > 390 ) + return cff_index_get_string( font, sid - 391 ); + + /* CID-keyed CFF fonts don't have glyph names */ + if ( !font->psnames ) + return NULL; + + /* this is a standard string */ + return (FT_String *)font->psnames->adobe_std_strings( sid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** FD Select table support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + + static void + CFF_Done_FD_Select( CFF_FDSelect fdselect, + FT_Stream stream ) + { + if ( fdselect->data ) + FT_FRAME_RELEASE( fdselect->data ); + + fdselect->data_size = 0; + fdselect->format = 0; + fdselect->range_count = 0; + } + + + static FT_Error + CFF_Load_FD_Select( CFF_FDSelect fdselect, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong offset ) + { + FT_Error error; + FT_Byte format; + FT_UInt num_ranges; + + + /* read format */ + if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) ) + goto Exit; + + fdselect->format = format; + fdselect->cache_count = 0; /* clear cache */ + + switch ( format ) + { + case 0: /* format 0, that's simple */ + fdselect->data_size = num_glyphs; + goto Load_Data; + + case 3: /* format 3, a tad more complex */ + if ( FT_READ_USHORT( num_ranges ) ) + goto Exit; + + if ( !num_ranges ) + { + FT_TRACE0(( "CFF_Load_FD_Select: empty FDSelect array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + fdselect->data_size = num_ranges * 3 + 2; + + Load_Data: + if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) ) + goto Exit; + break; + + default: /* hmm... that's wrong */ + error = FT_THROW( Invalid_File_Format ); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ) + { + FT_Byte fd = 0; + + + /* if there is no FDSelect, return zero */ + /* Note: CFF2 with just one Font Dict has no FDSelect */ + if ( !fdselect->data ) + goto Exit; + + switch ( fdselect->format ) + { + case 0: + fd = fdselect->data[glyph_index]; + break; + + case 3: + /* first, compare to the cache */ + if ( glyph_index - fdselect->cache_first < fdselect->cache_count ) + { + fd = fdselect->cache_fd; + break; + } + + /* then, look up the ranges array */ + { + FT_Byte* p = fdselect->data; + FT_Byte* p_limit = p + fdselect->data_size; + FT_Byte fd2; + FT_UInt first, limit; + + + first = FT_NEXT_USHORT( p ); + do + { + if ( glyph_index < first ) + break; + + fd2 = *p++; + limit = FT_NEXT_USHORT( p ); + + if ( glyph_index < limit ) + { + fd = fd2; + + /* update cache */ + fdselect->cache_first = first; + fdselect->cache_count = limit - first; + fdselect->cache_fd = fd2; + break; + } + first = limit; + + } while ( p < p_limit ); + } + break; + + default: + ; + } + + Exit: + return fd; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*** ***/ + /*** CFF font support ***/ + /*** ***/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + cff_charset_compute_cids( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_UInt i; + FT_UShort max_cid = 0; + + + if ( charset->max_cid > 0 ) + goto Exit; + + for ( i = 0; i < num_glyphs; i++ ) + { + if ( charset->sids[i] > max_cid ) + max_cid = charset->sids[i]; + } + + if ( FT_NEW_ARRAY( charset->cids, (FT_ULong)max_cid + 1 ) ) + goto Exit; + + /* When multiple GIDs map to the same CID, we choose the lowest */ + /* GID. This is not described in any spec, but it matches the */ + /* behaviour of recent Acroread versions. The loop stops when */ + /* the unsigned index wraps around after reaching zero. */ + for ( i = num_glyphs - 1; i < num_glyphs; i-- ) + charset->cids[charset->sids[i]] = (FT_UShort)i; + + charset->max_cid = max_cid; + charset->num_glyphs = num_glyphs; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ) + { + FT_UInt result = 0; + + + if ( cid <= charset->max_cid ) + result = charset->cids[cid]; + + return result; + } + + + static void + cff_charset_free_cids( CFF_Charset charset, + FT_Memory memory ) + { + FT_FREE( charset->cids ); + charset->max_cid = 0; + } + + + static void + cff_charset_done( CFF_Charset charset, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + cff_charset_free_cids( charset, memory ); + + FT_FREE( charset->sids ); + charset->format = 0; + charset->offset = 0; + } + + + static FT_Error + cff_charset_load( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset, + FT_Bool invert ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + FT_UShort glyph_sid; + + + /* If the offset is greater than 2, we have to parse the charset */ + /* table. */ + if ( offset > 2 ) + { + FT_UInt j; + + + charset->offset = base_offset + offset; + + /* Get the format of the table. */ + if ( FT_STREAM_SEEK( charset->offset ) || + FT_READ_BYTE( charset->format ) ) + goto Exit; + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* assign the .notdef glyph */ + charset->sids[0] = 0; + + switch ( charset->format ) + { + case 0: + if ( num_glyphs > 0 ) + { + if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) + goto Exit; + + for ( j = 1; j < num_glyphs; j++ ) + charset->sids[j] = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + } + break; + + case 1: + case 2: + { + FT_UInt nleft; + FT_UInt i; + + + j = 1; + + while ( j < num_glyphs ) + { + /* Read the first glyph sid of the range. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Read the number of glyphs in the range. */ + if ( charset->format == 2 ) + { + if ( FT_READ_USHORT( nleft ) ) + goto Exit; + } + else + { + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + } + + /* try to rescue some of the SIDs if `nleft' is too large */ + if ( glyph_sid > 0xFFFFL - nleft ) + { + FT_ERROR(( "cff_charset_load: invalid SID range trimmed" + " nleft=%d -> %ld\n", nleft, 0xFFFFL - glyph_sid )); + nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); + } + + /* Fill in the range of sids -- `nleft + 1' glyphs. */ + for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) + charset->sids[j] = glyph_sid; + } + } + break; + + default: + FT_ERROR(( "cff_charset_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + else + { + /* Parse default tables corresponding to offset == 0, 1, or 2. */ + /* CFF specification intimates the following: */ + /* */ + /* In order to use a predefined charset, the following must be */ + /* true: The charset constructed for the glyphs in the font's */ + /* charstrings dictionary must match the predefined charset in */ + /* the first num_glyphs. */ + + charset->offset = offset; /* record charset type */ + + switch ( (FT_UInt)offset ) + { + case 0: + if ( num_glyphs > 229 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe ISO-Latin)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); + + break; + + case 1: + if ( num_glyphs > 166 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); + + break; + + case 2: + if ( num_glyphs > 87 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert Subset)\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Allocate memory for sids. */ + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; + + /* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); + + break; + + default: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* we have to invert the `sids' array for subsetted CID-keyed fonts */ + if ( invert ) + error = cff_charset_compute_cids( charset, num_glyphs, memory ); + + Exit: + /* Clean up if there was an error. */ + if ( error ) + { + FT_FREE( charset->sids ); + FT_FREE( charset->cids ); + charset->format = 0; + charset->offset = 0; + } + + return error; + } + + + static void + cff_vstore_done( CFF_VStoreRec* vstore, + FT_Memory memory ) + { + FT_UInt i; + + + /* free regionList and axisLists */ + if ( vstore->varRegionList ) + { + for ( i = 0; i < vstore->regionCount; i++ ) + FT_FREE( vstore->varRegionList[i].axisList ); + } + FT_FREE( vstore->varRegionList ); + + /* free varData and indices */ + if ( vstore->varData ) + { + for ( i = 0; i < vstore->dataCount; i++ ) + FT_FREE( vstore->varData[i].regionIndices ); + } + FT_FREE( vstore->varData ); + } + + + /* convert 2.14 to Fixed */ + #define FT_fdot14ToFixed( x ) ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) + + + static FT_Error + cff_vstore_load( CFF_VStoreRec* vstore, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_ERR( Invalid_File_Format ); + + FT_ULong* dataOffsetArray = NULL; + FT_UInt i, j; + + + /* no offset means no vstore to parse */ + if ( offset ) + { + FT_UInt vsOffset; + FT_UInt format; + FT_UInt dataCount; + FT_UInt regionCount; + FT_ULong regionListOffset; + + + /* we need to parse the table to determine its size; */ + /* skip table length */ + if ( FT_STREAM_SEEK( base_offset + offset ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + /* actual variation store begins after the length */ + vsOffset = FT_STREAM_POS(); + + /* check the header */ + if ( FT_READ_USHORT( format ) ) + goto Exit; + if ( format != 1 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( regionListOffset ) || + FT_READ_USHORT( dataCount ) ) + goto Exit; + + /* make temporary copy of item variation data offsets; */ + /* we'll parse region list first, then come back */ + if ( FT_QNEW_ARRAY( dataOffsetArray, dataCount ) ) + goto Exit; + + for ( i = 0; i < dataCount; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse regionList and axisLists */ + if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) || + FT_READ_USHORT( vstore->axisCount ) || + FT_READ_USHORT( regionCount ) ) + goto Exit; + + vstore->regionCount = 0; + if ( FT_QNEW_ARRAY( vstore->varRegionList, regionCount ) ) + goto Exit; + + for ( i = 0; i < regionCount; i++ ) + { + CFF_VarRegion* region = &vstore->varRegionList[i]; + + + if ( FT_QNEW_ARRAY( region->axisList, vstore->axisCount ) ) + goto Exit; + + /* keep track of how many axisList to deallocate on error */ + vstore->regionCount++; + + for ( j = 0; j < vstore->axisCount; j++ ) + { + CFF_AxisCoords* axis = ®ion->axisList[j]; + + FT_Int start, peak, end; + + + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) + goto Exit; + + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; + + axis->startCoord = FT_fdot14ToFixed( start ); + axis->peakCoord = FT_fdot14ToFixed( peak ); + axis->endCoord = FT_fdot14ToFixed( end ); + } + } + + /* use dataOffsetArray now to parse varData items */ + vstore->dataCount = 0; + if ( FT_QNEW_ARRAY( vstore->varData, dataCount ) ) + goto Exit; + + for ( i = 0; i < dataCount; i++ ) + { + CFF_VarData* data = &vstore->varData[i]; + + + if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) ) + goto Exit; + + /* ignore `itemCount' and `shortDeltaCount' */ + /* because CFF2 has no delta sets */ + if ( FT_STREAM_SKIP( 4 ) ) + goto Exit; + + /* Note: just record values; consistency is checked later */ + /* by cff_blend_build_vector when it consumes `vstore' */ + + if ( FT_READ_USHORT( data->regionIdxCount ) ) + goto Exit; + + if ( FT_QNEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) + goto Exit; + + /* keep track of how many regionIndices to deallocate on error */ + vstore->dataCount++; + + for ( j = 0; j < data->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( data->regionIndices[j] ) ) + goto Exit; + } + } + } + + error = FT_Err_Ok; + + Exit: + FT_FREE( dataOffsetArray ); + if ( error ) + cff_vstore_done( vstore, memory ); + + return error; + } + + + /* Clear blend stack (after blend values are consumed). */ + /* */ + /* TODO: Should do this in cff_run_parse, but subFont */ + /* ref is not available there. */ + /* */ + /* Allocation is not changed when stack is cleared. */ + FT_LOCAL_DEF( void ) + cff_blend_clear( CFF_SubFont subFont ) + { + subFont->blend_top = subFont->blend_stack; + subFont->blend_used = 0; + } + + + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + /* */ + /* This is comparable to `cf2_doBlend' but */ + /* the cffparse stack is different and can't be written. */ + /* Blended values are written to a different buffer, */ + /* using reserved operator 255. */ + /* */ + /* Blend calculation is done in 16.16 fixed-point. */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_doBlend( CFF_SubFont subFont, + CFF_Parser parser, + FT_UInt numBlends ) + { + FT_UInt delta; + FT_UInt base; + FT_UInt i, j; + FT_UInt size; + + CFF_Blend blend = &subFont->blend; + + FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */ + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + + /* compute expected number of operands for this blend */ + FT_UInt numOperands = (FT_UInt)( numBlends * blend->lenBV ); + FT_UInt count = (FT_UInt)( parser->top - 1 - parser->stack ); + + + if ( numOperands > count ) + { + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n", + count, + count == 1 ? "" : "s" )); + + error = FT_THROW( Stack_Underflow ); + goto Exit; + } + + /* check whether we have room for `numBlends' values at `blend_top' */ + size = 5 * numBlends; /* add 5 bytes per entry */ + if ( subFont->blend_used + size > subFont->blend_alloc ) + { + FT_Byte* blend_stack_old = subFont->blend_stack; + FT_Byte* blend_top_old = subFont->blend_top; + + + /* increase or allocate `blend_stack' and reset `blend_top'; */ + /* prepare to append `numBlends' values to the buffer */ + if ( FT_QREALLOC( subFont->blend_stack, + subFont->blend_alloc, + subFont->blend_alloc + size ) ) + goto Exit; + + subFont->blend_top = subFont->blend_stack + subFont->blend_used; + subFont->blend_alloc += size; + + /* iterate over the parser stack and adjust pointers */ + /* if the reallocated buffer has a different address */ + if ( blend_stack_old && + subFont->blend_stack != blend_stack_old ) + { + FT_PtrDist offset = subFont->blend_stack - blend_stack_old; + FT_Byte** p; + + + for ( p = parser->stack; p < parser->top; p++ ) + { + if ( *p >= blend_stack_old && *p < blend_top_old ) + *p += offset; + } + } + } + subFont->blend_used += size; + + base = count - numOperands; /* index of first blend arg */ + delta = base + numBlends; /* index of first delta arg */ + + for ( i = 0; i < numBlends; i++ ) + { + const FT_Int32* weight = &blend->BV[1]; + FT_Fixed sum; + + + /* convert inputs to 16.16 fixed point */ + sum = cff_parse_fixed( parser, &parser->stack[i + base] ); + + for ( j = 1; j < blend->lenBV; j++ ) + sum += FT_MulFix( cff_parse_fixed( parser, &parser->stack[delta++] ), + *weight++ ); + + /* point parser stack to new value on blend_stack */ + parser->stack[i + base] = subFont->blend_top; + + /* Push blended result as Type 2 5-byte fixed-point number. This */ + /* will not conflict with actual DICTs because 255 is a reserved */ + /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */ + /* decode of this, which rounds to an integer. */ + *subFont->blend_top++ = 255; + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 24 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 16 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 8 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum ); + } + + /* leave only numBlends results on parser stack */ + parser->top = &parser->stack[base + numBlends]; + + Exit: + return error; + } + + + /* Compute a blend vector from variation store index and normalized */ + /* vector based on pseudo-code in OpenType Font Variations Overview. */ + /* */ + /* Note: lenNDV == 0 produces a default blend vector, (1,0,0,...). */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + FT_Memory memory = blend->font->memory; /* for FT_REALLOC */ + + FT_UInt len; + CFF_VStore vs; + CFF_VarData* varData; + FT_UInt master; + + + /* protect against malformed fonts */ + if ( !( lenNDV == 0 || NDV ) ) + { + FT_TRACE4(( " cff_blend_build_vector:" + " Malformed Normalize Design Vector data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + blend->builtBV = FALSE; + + vs = &blend->font->vstore; + + /* VStore and fvar must be consistent */ + if ( lenNDV != 0 && lenNDV != vs->axisCount ) + { + FT_TRACE4(( " cff_blend_build_vector: Axis count mismatch\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( vsindex >= vs->dataCount ) + { + FT_TRACE4(( " cff_blend_build_vector: vsindex out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* select the item variation data structure */ + varData = &vs->varData[vsindex]; + + /* prepare buffer for the blend vector */ + len = varData->regionIdxCount + 1; /* add 1 for default component */ + if ( FT_QRENEW_ARRAY( blend->BV, blend->lenBV, len ) ) + goto Exit; + + blend->lenBV = len; + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < len; master++ ) + { + FT_UInt j; + FT_UInt idx; + CFF_VarRegion* varRegion; + + + /* default factor is always one */ + if ( master == 0 ) + { + blend->BV[master] = FT_FIXED_ONE; + FT_TRACE4(( " build blend vector len %d\n", len )); + FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 )); + continue; + } + + /* VStore array does not include default master, so subtract one */ + idx = varData->regionIndices[master - 1]; + varRegion = &vs->varRegionList[idx]; + + if ( idx >= vs->regionCount ) + { + FT_TRACE4(( " cff_blend_build_vector:" + " region index out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Note: `lenNDV' could be zero. */ + /* In that case, build default blend vector (1,0,0...). */ + if ( !lenNDV ) + { + blend->BV[master] = 0; + continue; + } + + /* In the normal case, initialize each component to 1 */ + /* before inner loop. */ + blend->BV[master] = FT_FIXED_ONE; /* default */ + + /* inner loop steps through axes in this region */ + for ( j = 0; j < lenNDV; j++ ) + { + CFF_AxisCoords* axis = &varRegion->axisList[j]; + + + /* compute the scalar contribution of this axis */ + /* with peak of 0 used for invalid axes */ + if ( axis->peakCoord == NDV[j] || + axis->peakCoord == 0 ) + continue; + + /* ignore this region if coords are out of range */ + else if ( NDV[j] <= axis->startCoord || + NDV[j] >= axis->endCoord ) + { + blend->BV[master] = 0; + break; + } + + /* adjust proportionally */ + else if ( NDV[j] < axis->peakCoord ) + blend->BV[master] = FT_MulDiv( blend->BV[master], + NDV[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* NDV[j] > axis->peakCoord ) */ + blend->BV[master] = FT_MulDiv( blend->BV[master], + axis->endCoord - NDV[j], + axis->endCoord - axis->peakCoord ); + } + + FT_TRACE4(( ", %f ", + blend->BV[master] / 65536.0 )); + } + + FT_TRACE4(( "]\n" )); + + /* record the parameters used to build the blend vector */ + blend->lastVsindex = vsindex; + + if ( lenNDV != 0 ) + { + /* user has set a normalized vector */ + if ( FT_QRENEW_ARRAY( blend->lastNDV, blend->lenNDV, lenNDV ) ) + goto Exit; + + FT_MEM_COPY( blend->lastNDV, + NDV, + lenNDV * sizeof ( *NDV ) ); + } + + blend->lenNDV = lenNDV; + blend->builtBV = TRUE; + + Exit: + return error; + } + + + /* `lenNDV' is zero for default vector; */ + /* return TRUE if blend vector needs to be built. */ + FT_LOCAL_DEF( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + if ( !blend->builtBV || + blend->lastVsindex != vsindex || + blend->lenNDV != lenNDV || + ( lenNDV && + ft_memcmp( NDV, + blend->lastNDV, + lenNDV * sizeof ( *NDV ) ) != 0 ) ) + { + /* need to build blend vector */ + return TRUE; + } + + return FALSE; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + FT_LOCAL_DEF( FT_Error ) + cff_get_var_blend( FT_Face face, /* CFF_Face */ + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_var_blend( face, + num_coords, + coords, + normalizedcoords, + mm_var ); + } + + + FT_LOCAL_DEF( void ) + cff_done_blend( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + if ( mm ) + mm->done_blend( face ); + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static void + cff_encoding_done( CFF_Encoding encoding ) + { + encoding->format = 0; + encoding->offset = 0; + encoding->count = 0; + } + + + static FT_Error + cff_encoding_load( CFF_Encoding encoding, + CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + FT_UInt j; + FT_UShort glyph_sid; + FT_UInt glyph_code; + + + /* Check for charset->sids. If we do not have this, we fail. */ + if ( !charset->sids ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Note: The encoding table in a CFF font is indexed by glyph index; */ + /* the first encoded glyph index is 1. Hence, we read the character */ + /* code (`glyph_code') at index j and make the assignment: */ + /* */ + /* encoding->codes[glyph_code] = j + 1 */ + /* */ + /* We also make the assignment: */ + /* */ + /* encoding->sids[glyph_code] = charset->sids[j + 1] */ + /* */ + /* This gives us both a code to GID and a code to SID mapping. */ + + if ( offset > 1 ) + { + /* Zero out the code to gid/sid mappings. */ + FT_ARRAY_ZERO( encoding->sids, 256 ); + FT_ARRAY_ZERO( encoding->codes, 256 ); + + encoding->offset = base_offset + offset; + + /* we need to parse the table to determine its size */ + if ( FT_STREAM_SEEK( encoding->offset ) || + FT_READ_BYTE( encoding->format ) || + FT_READ_BYTE( count ) ) + goto Exit; + + switch ( encoding->format & 0x7F ) + { + case 0: + { + FT_Byte* p; + + + /* By convention, GID 0 is always ".notdef" and is never */ + /* coded in the font. Hence, the number of codes found */ + /* in the table is `count+1'. */ + /* */ + encoding->count = count + 1; + + if ( FT_FRAME_ENTER( count ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + + for ( j = 1; j <= count; j++ ) + { + glyph_code = *p++; + + /* Make sure j is not too big. */ + if ( j < num_glyphs ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)j; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[j]; + } + } + + FT_FRAME_EXIT(); + } + break; + + case 1: + { + FT_UInt nleft; + FT_UInt i = 1; + FT_UInt k; + + + encoding->count = 0; + + /* Parse the Format1 ranges. */ + for ( j = 0; j < count; j++, i += nleft ) + { + /* Read the first glyph code of the range. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the number of codes in the range. */ + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + + /* Increment nleft, so we read `nleft + 1' codes/sids. */ + nleft++; + + /* compute max number of character codes */ + if ( (FT_UInt)nleft > encoding->count ) + encoding->count = nleft; + + /* Fill in the range of codes/sids. */ + for ( k = i; k < nleft + i; k++, glyph_code++ ) + { + /* Make sure k is not too big. */ + if ( k < num_glyphs && glyph_code < 256 ) + { + /* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)k; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[k]; + } + } + } + + /* simple check; one never knows what can be found in a font */ + if ( encoding->count > 256 ) + encoding->count = 256; + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Parse supplemental encodings, if any. */ + if ( encoding->format & 0x80 ) + { + FT_UInt gindex; + + + /* count supplements */ + if ( FT_READ_BYTE( count ) ) + goto Exit; + + for ( j = 0; j < count; j++ ) + { + /* Read supplemental glyph code. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; + + /* Read the SID associated with this glyph code. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; + + /* Assign code to SID mapping. */ + encoding->sids[glyph_code] = glyph_sid; + + /* First, look up GID which has been assigned to */ + /* SID glyph_sid. */ + for ( gindex = 0; gindex < num_glyphs; gindex++ ) + { + if ( charset->sids[gindex] == glyph_sid ) + { + encoding->codes[glyph_code] = (FT_UShort)gindex; + break; + } + } + } + } + } + else + { + /* We take into account the fact a CFF font can use a predefined */ + /* encoding without containing all of the glyphs encoded by this */ + /* encoding (see the note at the end of section 12 in the CFF */ + /* specification). */ + + switch ( (FT_UInt)offset ) + { + case 0: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 ); + goto Populate; + + case 1: + /* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 ); + + Populate: + /* Construct code to GID mapping from code to SID mapping */ + /* and charset. */ + + encoding->offset = offset; /* used in cff_face_init */ + encoding->count = 0; + + error = cff_charset_compute_cids( charset, num_glyphs, + stream->memory ); + if ( error ) + goto Exit; + + for ( j = 0; j < 256; j++ ) + { + FT_UInt sid = encoding->sids[j]; + FT_UInt gid = 0; + + + if ( sid ) + gid = cff_charset_cid_to_gindex( charset, sid ); + + if ( gid != 0 ) + { + encoding->codes[j] = (FT_UShort)gid; + encoding->count = j + 1; + } + else + { + encoding->codes[j] = 0; + encoding->sids [j] = 0; + } + } + break; + + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + Exit: + + /* Clean up if there was an error. */ + return error; + } + + + /* Parse private dictionary; first call is always from `cff_face_init', */ + /* so NDV has not been set for CFF2 variation. */ + /* */ + /* `cff_slot_load' must call this function each time NDV changes. */ + FT_LOCAL_DEF( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; + CFF_ParserRec parser; + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + FT_Stream stream = font->stream; + FT_UInt stackSize; + + + /* store handle needed to access memory, vstore for blend; */ + /* we need this for clean-up even if there is no private DICT */ + subfont->blend.font = font; + subfont->blend.usedBV = FALSE; /* clear state */ + + if ( !top->private_offset || !top->private_size ) + goto Exit2; /* no private DICT, do nothing */ + + /* set defaults */ + FT_ZERO( priv ); + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + /* provide inputs for blend calculations */ + priv->subfont = subfont; + subfont->lenNDV = lenNDV; + subfont->NDV = NDV; + + /* add 1 for the operator */ + stackSize = font->cff2 ? font->top_font.font_dict.maxstack + 1 + : CFF_MAX_STACK_DEPTH + 1; + + if ( cff_parser_init( &parser, + font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE, + priv, + font->library, + stackSize, + top->num_designs, + top->num_axes ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) || + FT_FRAME_ENTER( top->private_size ) ) + goto Exit; + + FT_TRACE4(( " private dictionary:\n" )); + error = cff_parser_run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + /* ensure that `num_blue_values' is even */ + priv->num_blue_values &= ~1; + + /* sanitize `initialRandomSeed' to be a positive value, if necessary; */ + /* this is not mandated by the specification but by our implementation */ + if ( priv->initial_random_seed < 0 ) + priv->initial_random_seed = -priv->initial_random_seed; + else if ( priv->initial_random_seed == 0 ) + priv->initial_random_seed = 987654321; + + /* some sanitizing to avoid overflows later on; */ + /* the upper limits are ad-hoc values */ + if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) + { + FT_TRACE2(( "cff_load_private_dict:" + " setting unlikely BlueShift value %ld to default (7)\n", + priv->blue_shift )); + priv->blue_shift = 7; + } + + if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) + { + FT_TRACE2(( "cff_load_private_dict:" + " setting unlikely BlueFuzz value %ld to default (1)\n", + priv->blue_fuzz )); + priv->blue_fuzz = 1; + } + + Exit: + /* clean up */ + cff_blend_clear( subfont ); /* clear blend stack */ + cff_parser_done( &parser ); /* free parser stack */ + + Exit2: + /* no clean up (parser not initialized) */ + return error; + } + + + /* There are 3 ways to call this function, distinguished by code. */ + /* */ + /* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */ + /* . CFF2_CODE_TOPDICT for CFF2 Top DICT */ + /* . CFF2_CODE_FONTDICT for CFF2 Font DICT */ + + static FT_Error + cff_subfont_load( CFF_SubFont subfont, + CFF_Index idx, + FT_UInt font_index, + FT_Stream stream, + FT_ULong base_offset, + FT_UInt code, + CFF_Font font, + CFF_Face face ) + { + FT_Error error; + CFF_ParserRec parser; + FT_Byte* dict = NULL; + FT_ULong dict_len; + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Bool cff2 = FT_BOOL( code == CFF2_CODE_TOPDICT || + code == CFF2_CODE_FONTDICT ); + FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK + : CFF_MAX_STACK_DEPTH; + + + /* Note: We use default stack size for CFF2 Font DICT because */ + /* Top and Font DICTs are not allowed to have blend operators. */ + error = cff_parser_init( &parser, + code, + top, + font->library, + stackSize, + 0, + 0 ); + if ( error ) + goto Exit; + + /* set defaults */ + FT_ZERO( top ); + + top->underline_position = -( 100L << 16 ); + top->underline_thickness = 50L << 16; + top->charstring_type = 2; + top->font_matrix.xx = 0x10000L; + top->font_matrix.yy = 0x10000L; + top->cid_count = 8720; + + /* we use the implementation specific SID value 0xFFFF to indicate */ + /* missing entries */ + top->version = 0xFFFFU; + top->notice = 0xFFFFU; + top->copyright = 0xFFFFU; + top->full_name = 0xFFFFU; + top->family_name = 0xFFFFU; + top->weight = 0xFFFFU; + top->embedded_postscript = 0xFFFFU; + + top->cid_registry = 0xFFFFU; + top->cid_ordering = 0xFFFFU; + top->cid_font_name = 0xFFFFU; + + /* set default stack size */ + top->maxstack = cff2 ? CFF2_DEFAULT_STACK : 48; + + if ( idx->count ) /* count is nonzero for a real index */ + error = cff_index_access_element( idx, font_index, &dict, &dict_len ); + else + { + /* CFF2 has a fake top dict index; */ + /* simulate `cff_index_access_element' */ + + /* Note: macros implicitly use `stream' and set `error' */ + if ( FT_STREAM_SEEK( idx->data_offset ) || + FT_FRAME_EXTRACT( idx->data_size, dict ) ) + goto Exit; + + dict_len = idx->data_size; + } + + if ( !error ) + { + FT_TRACE4(( " top dictionary:\n" )); + error = cff_parser_run( &parser, dict, FT_OFFSET( dict, dict_len ) ); + } + + /* clean up regardless of error */ + if ( idx->count ) + cff_index_forget_element( idx, &dict ); + else + FT_FRAME_RELEASE( dict ); + + if ( error ) + goto Exit; + + /* if it is a CID font, we stop there */ + if ( top->cid_registry != 0xFFFFU ) + goto Exit; + + /* Parse the private dictionary, if any. */ + /* */ + /* CFF2 does not have a private dictionary in the Top DICT */ + /* but may have one in a Font DICT. We need to parse */ + /* the latter here in order to load any local subrs. */ + error = cff_load_private_dict( font, subfont, 0, 0 ); + if ( error ) + goto Exit; + + if ( !cff2 ) + { + /* + * Initialize the random number generator. + * + * - If we have a face-specific seed, use it. + * If non-zero, update it to a positive value. + * + * - Otherwise, use the seed from the CFF driver. + * If non-zero, update it to a positive value. + * + * - If the random value is zero, use the seed given by the subfont's + * `initialRandomSeed' value. + * + */ + if ( face->root.internal->random_seed == -1 ) + { + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); + + + subfont->random = (FT_UInt32)driver->random_seed; + if ( driver->random_seed ) + { + do + { + driver->random_seed = + (FT_Int32)psaux->cff_random( (FT_UInt32)driver->random_seed ); + + } while ( driver->random_seed < 0 ); + } + } + else + { + subfont->random = (FT_UInt32)face->root.internal->random_seed; + if ( face->root.internal->random_seed ) + { + do + { + face->root.internal->random_seed = + (FT_Int32)psaux->cff_random( + (FT_UInt32)face->root.internal->random_seed ); + + } while ( face->root.internal->random_seed < 0 ); + } + } + + if ( !subfont->random ) + subfont->random = (FT_UInt32)priv->initial_random_seed; + } + + /* read the local subrs, if any */ + if ( priv->local_subrs_offset ) + { + if ( FT_STREAM_SEEK( base_offset + top->private_offset + + priv->local_subrs_offset ) ) + goto Exit; + + error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 ); + if ( error ) + goto Exit; + + error = cff_index_get_pointers( &subfont->local_subrs_index, + &subfont->local_subrs, NULL, NULL ); + if ( error ) + goto Exit; + } + + Exit: + cff_parser_done( &parser ); /* free parser stack */ + + return error; + } + + + static void + cff_subfont_done( FT_Memory memory, + CFF_SubFont subfont ) + { + if ( subfont ) + { + cff_index_done( &subfont->local_subrs_index ); + FT_FREE( subfont->local_subrs ); + + FT_FREE( subfont->blend.lastNDV ); + FT_FREE( subfont->blend.BV ); + FT_FREE( subfont->blend_stack ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + cff_font_load( FT_Library library, + FT_Stream stream, + FT_Int face_index, + CFF_Font font, + CFF_Face face, + FT_Bool pure_cff, + FT_Bool cff2 ) + { + static const FT_Frame_Field cff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRec + + FT_FRAME_START( 3 ), + FT_FRAME_BYTE( version_major ), + FT_FRAME_BYTE( version_minor ), + FT_FRAME_BYTE( header_size ), + FT_FRAME_END + }; + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; + CFF_FontRecDict dict; + CFF_IndexRec string_index; + FT_UInt subfont_index; + + + FT_ZERO( font ); + FT_ZERO( &string_index ); + + dict = &font->top_font.font_dict; + base_offset = FT_STREAM_POS(); + + font->library = library; + font->stream = stream; + font->memory = memory; + font->cff2 = cff2; + font->base_offset = base_offset; + + /* read CFF font header */ + if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) + goto Exit; + + if ( cff2 ) + { + if ( font->version_major != 2 || + font->header_size < 5 ) + { + FT_TRACE2(( " not a CFF2 font header\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( FT_READ_USHORT( font->top_dict_length ) ) + goto Exit; + } + else + { + FT_Byte absolute_offset; + + + if ( FT_READ_BYTE( absolute_offset ) ) + goto Exit; + + if ( font->version_major != 1 || + font->header_size < 4 || + absolute_offset > 4 ) + { + FT_TRACE2(( " not a CFF font header\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + } + + /* skip the rest of the header */ + if ( FT_STREAM_SEEK( base_offset + font->header_size ) ) + { + /* For pure CFFs we have read only four bytes so far. Contrary to */ + /* other formats like SFNT those bytes doesn't define a signature; */ + /* it is thus possible that the font isn't a CFF at all. */ + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } + goto Exit; + } + + if ( cff2 ) + { + /* For CFF2, the top dict data immediately follow the header */ + /* and the length is stored in the header `offSize' field; */ + /* there is no index for it. */ + /* */ + /* Use the `font_dict_index' to save the current position */ + /* and length of data, but leave count at zero as an indicator. */ + FT_ZERO( &font->font_dict_index ); + + font->font_dict_index.data_offset = FT_STREAM_POS(); + font->font_dict_index.data_size = font->top_dict_length; + + /* skip the top dict data for now, we will parse it later */ + if ( FT_STREAM_SKIP( font->top_dict_length ) ) + goto Exit; + + /* next, read the global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1, cff2 ) ) ) + goto Exit; + } + else + { + /* for CFF, read the name, top dict, string and global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->name_index, + stream, 0, cff2 ) ) ) + { + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } + goto Exit; + } + + /* if we have an empty font name, */ + /* it must be the only font in the CFF */ + if ( font->name_index.count > 1 && + font->name_index.data_size < font->name_index.count ) + { + /* for pure CFFs, we still haven't checked enough bytes */ + /* to be sure that it is a CFF at all */ + error = pure_cff ? FT_THROW( Unknown_File_Format ) + : FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( FT_SET_ERROR( cff_index_init( &font->font_dict_index, + stream, 0, cff2 ) ) || + FT_SET_ERROR( cff_index_init( &string_index, + stream, 1, cff2 ) ) || + FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1, cff2 ) ) || + FT_SET_ERROR( cff_index_get_pointers( &string_index, + &font->strings, + &font->string_pool, + &font->string_pool_size ) ) ) + goto Exit; + + /* there must be a Top DICT index entry for each name index entry */ + if ( font->name_index.count > font->font_dict_index.count ) + { + FT_ERROR(( "cff_font_load:" + " not enough entries in Top DICT index\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + font->num_strings = string_index.count; + + if ( pure_cff ) + { + /* well, we don't really forget the `disabled' fonts... */ + subfont_index = (FT_UInt)( face_index & 0xFFFF ); + + if ( face_index > 0 && subfont_index >= font->name_index.count ) + { + FT_ERROR(( "cff_font_load:" + " invalid subfont index for pure CFF font (%d)\n", + subfont_index )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + font->num_faces = font->name_index.count; + } + else + { + subfont_index = 0; + + if ( font->name_index.count > 1 ) + { + FT_ERROR(( "cff_font_load:" + " invalid CFF font with multiple subfonts\n" )); + FT_ERROR(( " " + " in SFNT wrapper\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* in case of a font format check, simply exit now */ + if ( face_index < 0 ) + goto Exit; + + /* now, parse the top-level font dictionary */ + FT_TRACE4(( "parsing top-level\n" )); + error = cff_subfont_load( &font->top_font, + &font->font_dict_index, + subfont_index, + stream, + base_offset, + cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT, + font, + face ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) + goto Exit; + + error = cff_index_init( &font->charstrings_index, stream, 0, cff2 ); + if ( error ) + goto Exit; + + /* now, check for a CID or CFF2 font */ + if ( dict->cid_registry != 0xFFFFU || + cff2 ) + { + CFF_IndexRec fd_index; + CFF_SubFont sub = NULL; + FT_UInt idx; + + + /* for CFF2, read the Variation Store if available; */ + /* this must follow the Top DICT parse and precede any Private DICT */ + error = cff_vstore_load( &font->vstore, + stream, + base_offset, + dict->vstore_offset ); + if ( error ) + goto Exit; + + /* this is a CID-keyed font, we must now allocate a table of */ + /* sub-fonts, then load each of them separately */ + if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) + goto Exit; + + error = cff_index_init( &fd_index, stream, 0, cff2 ); + if ( error ) + goto Exit; + + /* Font Dicts are not limited to 256 for CFF2. */ + /* TODO: support this for CFF2 */ + if ( fd_index.count > CFF_MAX_CID_FONTS ) + { + FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" )); + goto Fail_CID; + } + + /* allocate & read each font dict independently */ + font->num_subfonts = fd_index.count; + if ( FT_NEW_ARRAY( sub, fd_index.count ) ) + goto Fail_CID; + + /* set up pointer table */ + for ( idx = 0; idx < fd_index.count; idx++ ) + font->subfonts[idx] = sub + idx; + + /* now load each subfont independently */ + for ( idx = 0; idx < fd_index.count; idx++ ) + { + sub = font->subfonts[idx]; + FT_TRACE4(( "parsing subfont %u\n", idx )); + error = cff_subfont_load( sub, + &fd_index, + idx, + stream, + base_offset, + cff2 ? CFF2_CODE_FONTDICT + : CFF_CODE_TOPDICT, + font, + face ); + if ( error ) + goto Fail_CID; + } + + /* now load the FD Select array; */ + /* CFF2 omits FDSelect if there is only one FD */ + if ( !cff2 || fd_index.count > 1 ) + error = CFF_Load_FD_Select( &font->fd_select, + font->charstrings_index.count, + stream, + base_offset + dict->cid_fd_select_offset ); + + Fail_CID: + cff_index_done( &fd_index ); + + if ( error ) + goto Exit; + } + else + font->num_subfonts = 0; + + /* read the charstrings index now */ + if ( dict->charstrings_offset == 0 ) + { + FT_ERROR(( "cff_font_load: no charstrings offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + font->num_glyphs = font->charstrings_index.count; + + error = cff_index_get_pointers( &font->global_subrs_index, + &font->global_subrs, NULL, NULL ); + + if ( error ) + goto Exit; + + /* read the Charset and Encoding tables if available */ + if ( !cff2 && font->num_glyphs > 0 ) + { + FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff ); + + + error = cff_charset_load( &font->charset, font->num_glyphs, stream, + base_offset, dict->charset_offset, invert ); + if ( error ) + goto Exit; + + /* CID-keyed CFFs don't have an encoding */ + if ( dict->cid_registry == 0xFFFFU ) + { + error = cff_encoding_load( &font->encoding, + &font->charset, + font->num_glyphs, + stream, + base_offset, + dict->encoding_offset ); + if ( error ) + goto Exit; + } + } + + /* get the font name (/CIDFontName for CID-keyed fonts, */ + /* /FontName otherwise) */ + font->font_name = cff_index_get_name( font, subfont_index ); + + Exit: + cff_index_done( &string_index ); + + return error; + } + + + FT_LOCAL_DEF( void ) + cff_font_done( CFF_Font font ) + { + FT_Memory memory = font->memory; + FT_UInt idx; + + + cff_index_done( &font->global_subrs_index ); + cff_index_done( &font->font_dict_index ); + cff_index_done( &font->name_index ); + cff_index_done( &font->charstrings_index ); + + /* release font dictionaries, but only if working with */ + /* a CID keyed CFF font or a CFF2 font */ + if ( font->num_subfonts > 0 ) + { + for ( idx = 0; idx < font->num_subfonts; idx++ ) + cff_subfont_done( memory, font->subfonts[idx] ); + + /* the subfonts array has been allocated as a single block */ + FT_FREE( font->subfonts[0] ); + } + + cff_encoding_done( &font->encoding ); + cff_charset_done( &font->charset, font->stream ); + cff_vstore_done( &font->vstore, memory ); + + cff_subfont_done( memory, &font->top_font ); + + CFF_Done_FD_Select( &font->fd_select, font->stream ); + + FT_FREE( font->font_info ); + + FT_FREE( font->font_name ); + FT_FREE( font->global_subrs ); + FT_FREE( font->strings ); + FT_FREE( font->string_pool ); + + if ( font->cf2_instance.finalizer ) + { + font->cf2_instance.finalizer( font->cf2_instance.data ); + FT_FREE( font->cf2_instance.data ); + } + + FT_FREE( font->font_extra ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffload.h b/Dependencies/freetype/freetype/src/cff/cffload.h new file mode 100644 index 00000000..02209245 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffload.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * + * cffload.h + * + * OpenType & CFF data/program tables loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFLOAD_H_ +#define CFFLOAD_H_ + + +#include +#include "cffparse.h" +#include /* for CFF_Face */ + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ); + + + FT_LOCAL( FT_String* ) + cff_index_get_string( CFF_Font font, + FT_UInt element ); + + FT_LOCAL( FT_String* ) + cff_index_get_sid_string( CFF_Font font, + FT_UInt sid ); + + + FT_LOCAL( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ); + + FT_LOCAL( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ); + + FT_LOCAL( FT_String* ) + cff_index_get_name( CFF_Font font, + FT_UInt element ); + + + FT_LOCAL( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ); + + + FT_LOCAL( FT_Error ) + cff_font_load( FT_Library library, + FT_Stream stream, + FT_Int face_index, + CFF_Font font, + CFF_Face face, + FT_Bool pure_cff, + FT_Bool cff2 ); + + FT_LOCAL( void ) + cff_font_done( CFF_Font font ); + + + FT_LOCAL( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ); + + FT_LOCAL( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( void ) + cff_blend_clear( CFF_SubFont subFont ); + + FT_LOCAL( FT_Error ) + cff_blend_doBlend( CFF_SubFont subfont, + CFF_Parser parser, + FT_UInt numBlends ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cff_get_var_blend( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + FT_LOCAL( void ) + cff_done_blend( FT_Face face ); +#endif + + +FT_END_HEADER + +#endif /* CFFLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffobjs.c b/Dependencies/freetype/freetype/src/cff/cffobjs.c new file mode 100644 index 00000000..7c671373 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffobjs.c @@ -0,0 +1,1175 @@ +/**************************************************************************** + * + * cffobjs.c + * + * OpenType objects manager (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#include +#endif + +#include +#include "cffobjs.h" +#include "cffload.h" +#include "cffcmap.h" + +#include "cfferrs.h" + +#include +#include + +#define CFF_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffobjs + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + cff_size_get_globals_funcs( CFF_Size size ) + { + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->pshinter; + FT_Module module; + + + module = FT_Get_Module( font->library, "pshinter" ); + + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cff_size_done( FT_Size cffsize ) /* CFF_Size */ + { + FT_Memory memory = cffsize->face->memory; + CFF_Size size = (CFF_Size)cffsize; + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)cffsize->internal->module_data; + + + if ( internal ) + { + PSH_Globals_Funcs funcs; + + + funcs = cff_size_get_globals_funcs( size ); + if ( funcs ) + { + FT_UInt i; + + + funcs->destroy( internal->topfont ); + + for ( i = font->num_subfonts; i > 0; i-- ) + funcs->destroy( internal->subfonts[i - 1] ); + } + + FT_FREE( internal ); + } + } + + + /* CFF and Type 1 private dictionaries have slightly different */ + /* structures; we need to synthesize a Type 1 dictionary on the fly */ + + static void + cff_make_private_dict( CFF_SubFont subfont, + PS_Private priv ) + { + CFF_Private cpriv = &subfont->private_dict; + FT_UInt n, count; + + + FT_ZERO( priv ); + + count = priv->num_blue_values = cpriv->num_blue_values; + for ( n = 0; n < count; n++ ) + priv->blue_values[n] = CFF_fixedToInt( cpriv->blue_values[n] ); + + count = priv->num_other_blues = cpriv->num_other_blues; + for ( n = 0; n < count; n++ ) + priv->other_blues[n] = CFF_fixedToInt( cpriv->other_blues[n] ); + + count = priv->num_family_blues = cpriv->num_family_blues; + for ( n = 0; n < count; n++ ) + priv->family_blues[n] = CFF_fixedToInt( cpriv->family_blues[n] ); + + count = priv->num_family_other_blues = cpriv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + priv->family_other_blues[n] = + CFF_fixedToInt( cpriv->family_other_blues[n] ); + + priv->blue_scale = cpriv->blue_scale; + priv->blue_shift = (FT_Int)cpriv->blue_shift; + priv->blue_fuzz = (FT_Int)cpriv->blue_fuzz; + + priv->standard_width[0] = (FT_UShort)cpriv->standard_width; + priv->standard_height[0] = (FT_UShort)cpriv->standard_height; + + count = priv->num_snap_widths = cpriv->num_snap_widths; + for ( n = 0; n < count; n++ ) + priv->snap_widths[n] = (FT_Short)cpriv->snap_widths[n]; + + count = priv->num_snap_heights = cpriv->num_snap_heights; + for ( n = 0; n < count; n++ ) + priv->snap_heights[n] = (FT_Short)cpriv->snap_heights[n]; + + priv->force_bold = cpriv->force_bold; + priv->language_group = cpriv->language_group; + priv->lenIV = cpriv->lenIV; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_size_init( FT_Size cffsize ) /* CFF_Size */ + { + CFF_Size size = (CFF_Size)cffsize; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size ); + + FT_Memory memory = cffsize->face->memory; + CFF_Internal internal = NULL; + CFF_Face face = (CFF_Face)cffsize->face; + CFF_Font font = (CFF_Font)face->extra.data; + + PS_PrivateRec priv; + + FT_UInt i; + + if ( !funcs ) + goto Exit; + + if ( FT_NEW( internal ) ) + goto Exit; + + cff_make_private_dict( &font->top_font, &priv ); + error = funcs->create( memory, &priv, &internal->topfont ); + if ( error ) + goto Exit; + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + + + cff_make_private_dict( sub, &priv ); + error = funcs->create( memory, &priv, &internal->subfonts[i - 1] ); + if ( error ) + goto Exit; + } + + cffsize->internal->module_data = internal; + + size->strike_index = 0xFFFFFFFFUL; + + Exit: + if ( error ) + { + if ( internal ) + { + for ( i = font->num_subfonts; i > 0; i-- ) + FT_FREE( internal->subfonts[i - 1] ); + FT_FREE( internal->topfont ); + } + + FT_FREE( internal ); + } + + return error; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + + cffsize->strike_index = strike_index; + + FT_Select_Metrics( size->face, strike_index ); + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + { + CFF_Face face = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal->module_data; + + FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em; + FT_UInt i; + + + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + + + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + + return FT_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + FT_LOCAL_DEF( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ) + { + FT_Error error; + + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + CFF_Face cffface = (CFF_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + FT_ULong strike_index; + + + if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) ) + cffsize->strike_index = 0xFFFFFFFFUL; + else + return cff_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; + + funcs = cff_size_get_globals_funcs( cffsize ); + + if ( funcs ) + { + CFF_Face cffface = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)cffface->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal->module_data; + + FT_Long top_upm = (FT_Long)font->top_font.font_dict.units_per_em; + FT_UInt i; + + + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_Long sub_upm = (FT_Long)sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + + + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + cff_slot_done( FT_GlyphSlot slot ) + { + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ) + { + CFF_Face face = (CFF_Face)slot->face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->pshinter; + + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T2_Hints_Funcs funcs; + + + funcs = pshinter->get_t2_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + static FT_String* + cff_strcpy( FT_Memory memory, + const FT_String* source ) + { + FT_Error error; + FT_String* result; + + + FT_MEM_STRDUP( result, source ); + + return result; + } + + + /* Strip all subset prefixes of the form `ABCDEF+'. Usually, there */ + /* is only one, but font names like `APCOOG+JFABTD+FuturaBQ-Bold' */ + /* have been seen in the wild. */ + + static void + remove_subset_prefix( FT_String* name ) + { + FT_UInt32 i = 0, idx = 0; + + + /* six ASCII uppercase letters followed by a plus sign */ + while ( 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + name[i++] == '+' ) + { + idx = i; + } + + if ( idx ) + FT_MEM_MOVE( name, name + idx, ft_strlen( name + idx ) + 1 ); + } + + + /* Remove the style part from the family name (if present). */ + + static void + remove_style( FT_String* family_name, + const FT_String* style_name ) + { + FT_String* f = family_name + ft_strlen( family_name ); + const FT_String* s = style_name + ft_strlen( style_name ); + + + /* compare strings moving backwards */ + while ( s > style_name ) + if ( f == family_name || *--s != *--f ) + return; + + /* terminate and remove special characters */ + do + *f = '\0'; + while ( f-- > family_name && + ( *f == '-' || *f == ' ' || *f == '_' || *f == '+' ) ); + } + + + FT_LOCAL_DEF( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face cffface, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CFF_Face face = (CFF_Face)cffface; + FT_Error error; + SFNT_Service sfnt; + FT_Service_PsCMaps psnames; + PSHinter_Service pshinter; + PSAux_Service psaux; + FT_Service_CFFLoad cffload; + FT_Bool pure_cff = 1; + FT_Bool cff2 = 0; + FT_Bool sfnt_format = 0; + FT_Library library = cffface->driver->root.library; + + + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, + "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + + pshinter = (PSHinter_Service)FT_Get_Module_Interface( library, + "pshinter" ); + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, + "psaux" ); + if ( !psaux ) + { + FT_ERROR(( "cff_face_init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + face->psaux = psaux; + + FT_FACE_FIND_GLOBAL_SERVICE( face, cffload, CFF_LOAD ); + + FT_TRACE2(( "CFF driver\n" )); + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check whether we have a valid OpenType file */ + FT_TRACE2(( " " )); + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( !error ) + { + if ( face->format_tag != TTAG_OTTO ) /* `OTTO'; OpenType/CFF font */ + { + FT_TRACE2(( " not an OpenType/CFF font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* if we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return FT_Err_Ok; + + sfnt_format = 1; + + /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ + /* font; in the latter case it doesn't have a `head' table */ + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( !error ) + { + pure_cff = 0; + + /* load font directory */ + error = sfnt->load_face( stream, face, face_index, + num_params, params ); + if ( error ) + goto Exit; + } + else + { + /* load the `cmap' table explicitly */ + error = sfnt->load_cmap( face, stream ); + if ( error ) + goto Exit; + } + + /* now load the CFF part of the file; */ + /* give priority to CFF2 */ + error = face->goto_table( face, TTAG_CFF2, stream, 0 ); + if ( !error ) + { + cff2 = 1; + face->is_cff2 = cff2; + } + + if ( FT_ERR_EQ( error, Table_Missing ) ) + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + + if ( error ) + goto Exit; + } + else + { + /* rewind to start of file; we are going to load a pure-CFF font */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + error = FT_Err_Ok; + } + + /* now load and parse the CFF table in the file */ + { + CFF_Font cff = NULL; + CFF_FontRecDict dict; + FT_Memory memory = cffface->memory; + FT_Int32 flags; + FT_UInt i; + + + if ( FT_NEW( cff ) ) + goto Exit; + + face->extra.data = cff; + error = cff_font_load( library, + stream, + face_index, + cff, + face, + pure_cff, + cff2 ); + if ( error ) + goto Exit; + + /* if we are performing a simple font format check, exit immediately */ + /* (this is here for pure CFF) */ + if ( face_index < 0 ) + { + cffface->num_faces = (FT_Long)cff->num_faces; + return FT_Err_Ok; + } + + cff->pshinter = pshinter; + cff->psnames = psnames; + cff->cffload = cffload; + + cffface->face_index = face_index & 0xFFFF; + + /* Complement the root flags with some interesting information. */ + /* Note that this is only necessary for pure CFF and CEF fonts; */ + /* SFNT based fonts use the `name' table instead. */ + + cffface->num_glyphs = (FT_Long)cff->num_glyphs; + + dict = &cff->top_font.font_dict; + + /* we need the `psnames' module for CFF and CEF formats */ + /* which aren't CID-keyed */ + if ( dict->cid_registry == 0xFFFFU && !psnames ) + { + FT_ERROR(( "cff_face_init:" + " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " + " without the `psnames' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt idx; + FT_String* s; + + + FT_TRACE4(( "SIDs\n" )); + + /* dump string index, including default strings for convenience */ + for ( idx = 0; idx <= 390; idx++ ) + { + s = cff_index_get_sid_string( cff, idx ); + if ( s ) + FT_TRACE4(( " %5d %s\n", idx, s )); + } + + /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ + /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */ + /* which may contain null bytes in the middle of the data, too. */ + /* We thus access `cff->strings' directly. */ + for ( idx = 1; idx < cff->num_strings; idx++ ) + { + FT_Byte* s1 = cff->strings[idx - 1]; + FT_Byte* s2 = cff->strings[idx]; + FT_PtrDist s1len = s2 - s1 - 1; /* without the final null byte */ + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", idx + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); + } + + /* print last element */ + if ( cff->num_strings ) + { + FT_Byte* s1 = cff->strings[cff->num_strings - 1]; + FT_Byte* s2 = cff->string_pool + cff->string_pool_size; + FT_PtrDist s1len = s2 - s1 - 1; + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", cff->num_strings + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); + } + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_UInt instance_index = (FT_UInt)face_index >> 16; + + + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) ) + { + error = FT_Set_Named_Instance( cffface, instance_index ); + if ( error ) + goto Exit; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( !dict->has_font_matrix ) + dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; + + /* Normalize the font matrix so that `matrix->yy' is 1; if */ + /* it is zero, we use `matrix->yx' instead. The scaling is */ + /* done with `units_per_em' then (at this point, it already */ + /* contains the scaling factor, but without normalization */ + /* of the matrix). */ + /* */ + /* Note that the offsets must be expressed in integer font */ + /* units. */ + + { + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Fixed temp; + + + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + + if ( temp != 0x10000L ) + { + *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp ); + + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + + offset->x >>= 16; + offset->y >>= 16; + } + + for ( i = cff->num_subfonts; i > 0; i-- ) + { + CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; + CFF_FontRecDict top = &cff->top_font.font_dict; + + FT_Matrix* matrix; + FT_Vector* offset; + FT_ULong* upm; + FT_Fixed temp; + + + if ( sub->has_font_matrix ) + { + FT_Long scaling; + + + /* if we have a top-level matrix, */ + /* concatenate the subfont matrix */ + + if ( top->has_font_matrix ) + { + if ( top->units_per_em > 1 && sub->units_per_em > 1 ) + scaling = (FT_Long)FT_MIN( top->units_per_em, + sub->units_per_em ); + else + scaling = 1; + + FT_Matrix_Multiply_Scaled( &top->font_matrix, + &sub->font_matrix, + scaling ); + FT_Vector_Transform_Scaled( &sub->font_offset, + &top->font_matrix, + scaling ); + + sub->units_per_em = (FT_ULong) + FT_MulDiv( (FT_Long)sub->units_per_em, + (FT_Long)top->units_per_em, + scaling ); + } + } + else + { + sub->font_matrix = top->font_matrix; + sub->font_offset = top->font_offset; + + sub->units_per_em = top->units_per_em; + } + + matrix = &sub->font_matrix; + offset = &sub->font_offset; + upm = &sub->units_per_em; + + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + + + if ( temp != 0x10000L ) + { + *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp ); + + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + + offset->x >>= 16; + offset->y >>= 16; + } + + if ( pure_cff ) + { + char* style_name = NULL; + + + /* set up num_faces */ + cffface->num_faces = (FT_Long)cff->num_faces; + + /* compute number of glyphs */ + if ( dict->cid_registry != 0xFFFFU ) + cffface->num_glyphs = (FT_Long)( cff->charset.max_cid + 1 ); + else + cffface->num_glyphs = (FT_Long)cff->charstrings_index.count; + + /* set global bbox, as well as EM size */ + cffface->bbox.xMin = dict->font_bbox.xMin >> 16; + cffface->bbox.yMin = dict->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16; + cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16; + + cffface->units_per_EM = (FT_UShort)( dict->units_per_em ); + + cffface->ascender = (FT_Short)( cffface->bbox.yMax ); + cffface->descender = (FT_Short)( cffface->bbox.yMin ); + + cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); + if ( cffface->height < cffface->ascender - cffface->descender ) + cffface->height = (FT_Short)( cffface->ascender - + cffface->descender ); + + cffface->underline_position = + (FT_Short)( dict->underline_position >> 16 ); + cffface->underline_thickness = + (FT_Short)( dict->underline_thickness >> 16 ); + + /* retrieve font family & style name */ + if ( dict->family_name ) + { + char* family_name; + + + family_name = cff_index_get_sid_string( cff, dict->family_name ); + if ( family_name ) + cffface->family_name = cff_strcpy( memory, family_name ); + } + + if ( !cffface->family_name ) + { + cffface->family_name = cff_index_get_name( + cff, + (FT_UInt)( face_index & 0xFFFF ) ); + if ( cffface->family_name ) + remove_subset_prefix( cffface->family_name ); + } + + if ( cffface->family_name ) + { + char* full = cff_index_get_sid_string( cff, + dict->full_name ); + char* fullp = full; + char* family = cffface->family_name; + + + /* We try to extract the style name from the full name. */ + /* We need to ignore spaces and dashes during the search. */ + if ( full && family ) + { + while ( *fullp ) + { + /* skip common characters at the start of both strings */ + if ( *fullp == *family ) + { + family++; + fullp++; + continue; + } + + /* ignore spaces and dashes in full name during comparison */ + if ( *fullp == ' ' || *fullp == '-' ) + { + fullp++; + continue; + } + + /* ignore spaces and dashes in family name during comparison */ + if ( *family == ' ' || *family == '-' ) + { + family++; + continue; + } + + if ( !*family && *fullp ) + { + /* The full name begins with the same characters as the */ + /* family name, with spaces and dashes removed. In this */ + /* case, the remaining string in `fullp' will be used as */ + /* the style name. */ + style_name = cff_strcpy( memory, fullp ); + + /* remove the style part from the family name (if present) */ + if ( style_name ) + remove_style( cffface->family_name, style_name ); + } + break; + } + } + } + else + { + char *cid_font_name = + cff_index_get_sid_string( cff, + dict->cid_font_name ); + + + /* do we have a `/FontName' for a CID-keyed font? */ + if ( cid_font_name ) + cffface->family_name = cff_strcpy( memory, cid_font_name ); + } + + if ( style_name ) + cffface->style_name = style_name; + else + /* assume "Regular" style if we don't know better */ + cffface->style_name = cff_strcpy( memory, "Regular" ); + + /******************************************************************** + * + * Compute face flags. + */ + flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( sfnt_format ) + flags |= FT_FACE_FLAG_SFNT; + + /* fixed width font? */ + if ( dict->is_fixed_pitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ +#if 0 + /* kerning available? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; +#endif + + cffface->face_flags |= flags; + + /******************************************************************** + * + * Compute style flags. + */ + flags = 0; + + if ( dict->italic_angle ) + flags |= FT_STYLE_FLAG_ITALIC; + + { + char *weight = cff_index_get_sid_string( cff, + dict->weight ); + + + if ( weight ) + if ( !ft_strcmp( weight, "Bold" ) || + !ft_strcmp( weight, "Black" ) ) + flags |= FT_STYLE_FLAG_BOLD; + } + + /* double check */ + if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) + if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || + !ft_strncmp( cffface->style_name, "Black", 5 ) ) + flags |= FT_STYLE_FLAG_BOLD; + + cffface->style_flags = flags; + } + + /* CID-keyed CFF or CFF2 fonts don't have glyph names -- the SFNT */ + /* loader has unset this flag because of the 3.0 `post' table. */ + if ( dict->cid_registry == 0xFFFFU && !cff2 ) + cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; + + if ( dict->cid_registry != 0xFFFFU && pure_cff ) + cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; + + /******************************************************************** + * + * Compute char maps. + */ + + /* Try to synthesize a Unicode charmap if there is none available */ + /* already. If an OpenType font contains a Unicode "cmap", we */ + /* will use it, whatever be in the CFF part of the file. */ + { + FT_CharMapRec cmaprec; + FT_CharMap cmap; + FT_Int nn; + CFF_Encoding encoding = &cff->encoding; + + + for ( nn = 0; nn < cffface->num_charmaps; nn++ ) + { + cmap = cffface->charmaps[nn]; + + /* Windows Unicode? */ + if ( cmap->platform_id == TT_PLATFORM_MICROSOFT && + cmap->encoding_id == TT_MS_ID_UNICODE_CS ) + goto Skip_Unicode; + + /* Apple Unicode platform id? */ + if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE ) + goto Skip_Unicode; /* Apple Unicode */ + } + + /* since CID-keyed fonts don't contain glyph names, we can't */ + /* construct a cmap */ + if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) + goto Exit; + + /* we didn't find a Unicode charmap -- synthesize one */ + cmaprec.face = cffface; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; + + nn = cffface->num_charmaps; + + error = FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, + &cmaprec, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* if no Unicode charmap was previously selected, select this one */ + if ( !cffface->charmap && nn != cffface->num_charmaps ) + cffface->charmap = cffface->charmaps[nn]; + + Skip_Unicode: + if ( encoding->count > 0 ) + { + FT_CMap_Class clazz; + + + cmaprec.face = cffface; + cmaprec.platform_id = TT_PLATFORM_ADOBE; /* Adobe platform id */ + + if ( encoding->offset == 0 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; + cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; + clazz = &cff_cmap_encoding_class_rec; + } + else if ( encoding->offset == 1 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; + cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; + clazz = &cff_cmap_encoding_class_rec; + } + else + { + cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; + cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; + clazz = &cff_cmap_encoding_class_rec; + } + + error = FT_CMap_New( clazz, NULL, &cmaprec, NULL ); + } + } + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_face_done( FT_Face cffface ) /* CFF_Face */ + { + CFF_Face face = (CFF_Face)cffface; + FT_Memory memory; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = cffface->memory; + sfnt = (SFNT_Service)face->sfnt; + + if ( sfnt ) + sfnt->done_face( face ); + + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + if ( cff ) + { + cff_font_done( cff ); + FT_FREE( face->extra.data ); + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + cff_done_blend( cffface ); + face->blend = NULL; +#endif + } + + + FT_LOCAL_DEF( FT_Error ) + cff_driver_init( FT_Module module ) /* CFF_Driver */ + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftcffdrv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + cff_driver_done( FT_Module module ) /* CFF_Driver */ + { + FT_UNUSED( module ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffobjs.h b/Dependencies/freetype/freetype/src/cff/cffobjs.h new file mode 100644 index 00000000..91ad83b1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffobjs.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * + * cffobjs.h + * + * OpenType objects manager (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFOBJS_H_ +#define CFFOBJS_H_ + + + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + cff_size_init( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( void ) + cff_size_done( FT_Size size ); /* CFF_Size */ + + FT_LOCAL( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ); + +#endif + + FT_LOCAL( void ) + cff_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ); + + + /************************************************************************** + * + * Face functions + */ + FT_LOCAL( FT_Error ) + cff_face_init( FT_Stream stream, + FT_Face face, /* CFF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cff_face_done( FT_Face face ); /* CFF_Face */ + + + /************************************************************************** + * + * Driver functions + */ + FT_LOCAL( FT_Error ) + cff_driver_init( FT_Module module ); /* PS_Driver */ + + FT_LOCAL( void ) + cff_driver_done( FT_Module module ); /* PS_Driver */ + + +FT_END_HEADER + +#endif /* CFFOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffparse.c b/Dependencies/freetype/freetype/src/cff/cffparse.c new file mode 100644 index 00000000..92a69c3b --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffparse.c @@ -0,0 +1,1550 @@ +/**************************************************************************** + * + * cffparse.c + * + * CFF token stream parser (body) + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cffparse.h" +#include +#include +#include +#include +#include + +#include "cfferrs.h" +#include "cffload.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffparse + + + FT_LOCAL_DEF( FT_Error ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ) + { + FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */ + FT_Error error; /* for FT_NEW_ARRAY */ + + + FT_ZERO( parser ); + +#if 0 + parser->top = parser->stack; +#endif + parser->object_code = code; + parser->object = object; + parser->library = library; + parser->num_designs = num_designs; + parser->num_axes = num_axes; + + /* allocate the stack buffer */ + if ( FT_QNEW_ARRAY( parser->stack, stackSize ) ) + goto Exit; + + parser->stackSize = stackSize; + parser->top = parser->stack; /* empty stack */ + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_parser_done( CFF_Parser parser ) + { + FT_Memory memory = parser->library->memory; /* for FT_FREE */ + + + FT_FREE( parser->stack ); + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL ); +#endif + } + + + /* The parser limit checks in the next two functions are supposed */ + /* to detect the immediate crossing of the stream boundary. They */ + /* shall not be triggered from the distant t2_strings buffers. */ + + /* read an integer */ + static FT_Long + cff_parse_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + + + if ( v == 28 ) + { + if ( p + 2 > limit && limit >= p ) + goto Bad; + + val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] ); + } + else if ( v == 29 ) + { + if ( p + 4 > limit && limit >= p ) + goto Bad; + + val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) | + ( (FT_ULong)p[1] << 16 ) | + ( (FT_ULong)p[2] << 8 ) | + (FT_ULong)p[3] ); + } + else if ( v < 247 ) + { + val = v - 139; + } + else if ( v < 251 ) + { + if ( p + 1 > limit && limit >= p ) + goto Bad; + + val = ( v - 247 ) * 256 + p[0] + 108; + } + else + { + if ( p + 1 > limit && limit >= p ) + goto Bad; + + val = -( v - 251 ) * 256 - p[0] - 108; + } + + Exit: + return val; + + Bad: + val = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } + + + static const FT_Long power_tens[] = + { + 1L, + 10L, + 100L, + 1000L, + 10000L, + 100000L, + 1000000L, + 10000000L, + 100000000L, + 1000000000L + }; + + /* maximum values allowed for multiplying */ + /* with the corresponding `power_tens' element */ + static const FT_Long power_ten_limits[] = + { + FT_LONG_MAX / 1L, + FT_LONG_MAX / 10L, + FT_LONG_MAX / 100L, + FT_LONG_MAX / 1000L, + FT_LONG_MAX / 10000L, + FT_LONG_MAX / 100000L, + FT_LONG_MAX / 1000000L, + FT_LONG_MAX / 10000000L, + FT_LONG_MAX / 100000000L, + FT_LONG_MAX / 1000000000L, + }; + + + /* read a real */ + static FT_Fixed + cff_parse_real( FT_Byte* start, + FT_Byte* limit, + FT_Long power_ten, + FT_Long* scaling ) + { + FT_Byte* p = start; + FT_Int nib; + FT_UInt phase; + + FT_Long result, number, exponent; + FT_Int sign = 0, exponent_sign = 0, have_overflow = 0; + FT_Long exponent_add, integer_length, fraction_length; + + + if ( scaling ) + *scaling = 0; + + result = 0; + + number = 0; + exponent = 0; + + exponent_add = 0; + integer_length = 0; + fraction_length = 0; + + /* First of all, read the integer part. */ + phase = 4; + + for (;;) + { + /* If we entered this iteration with phase == 4, we need to */ + /* read a new byte. This also skips past the initial 0x1E. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = (FT_Int)( p[0] >> phase ) & 0xF; + phase = 4 - phase; + + if ( nib == 0xE ) + sign = 1; + else if ( nib > 9 ) + break; + else + { + /* Increase exponent if we can't add the digit. */ + if ( number >= 0xCCCCCCCL ) + exponent_add++; + /* Skip leading zeros. */ + else if ( nib || number ) + { + integer_length++; + number = number * 10 + nib; + } + } + } + + /* Read fraction part, if any. */ + if ( nib == 0xA ) + for (;;) + { + /* If we entered this iteration with phase == 4, we need */ + /* to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + /* Skip leading zeros if possible. */ + if ( !nib && !number ) + exponent_add--; + /* Only add digit if we don't overflow. */ + else if ( number < 0xCCCCCCCL && fraction_length < 9 ) + { + fraction_length++; + number = number * 10 + nib; + } + } + + /* Read exponent, if any. */ + if ( nib == 12 ) + { + exponent_sign = 1; + nib = 11; + } + + if ( nib == 11 ) + { + for (;;) + { + /* If we entered this iteration with phase == 4, */ + /* we need to read a new byte. */ + if ( phase ) + { + p++; + + /* Make sure we don't read past the end. */ + if ( p + 1 > limit && limit >= p ) + goto Bad; + } + + /* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; + + /* Arbitrarily limit exponent. */ + if ( exponent > 1000 ) + have_overflow = 1; + else + exponent = exponent * 10 + nib; + } + + if ( exponent_sign ) + exponent = -exponent; + } + + if ( !number ) + goto Exit; + + if ( have_overflow ) + { + if ( exponent_sign ) + goto Underflow; + else + goto Overflow; + } + + /* We don't check `power_ten' and `exponent_add'. */ + exponent += power_ten + exponent_add; + + if ( scaling ) + { + /* Only use `fraction_length'. */ + fraction_length += integer_length; + exponent += integer_length; + + if ( fraction_length <= 5 ) + { + if ( number > 0x7FFFL ) + { + result = FT_DivFix( number, 10 ); + *scaling = exponent - fraction_length + 1; + } + else + { + if ( exponent > 0 ) + { + FT_Long new_fraction_length, shift; + + + /* Make `scaling' as small as possible. */ + new_fraction_length = FT_MIN( exponent, 5 ); + shift = new_fraction_length - fraction_length; + + if ( shift > 0 ) + { + exponent -= new_fraction_length; + number *= power_tens[shift]; + if ( number > 0x7FFFL ) + { + number /= 10; + exponent += 1; + } + } + else + exponent -= fraction_length; + } + else + exponent -= fraction_length; + + result = (FT_Long)( (FT_ULong)number << 16 ); + *scaling = exponent; + } + } + else + { + if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL ) + { + result = FT_DivFix( number, power_tens[fraction_length - 4] ); + *scaling = exponent - 4; + } + else + { + result = FT_DivFix( number, power_tens[fraction_length - 5] ); + *scaling = exponent - 5; + } + } + } + else + { + integer_length += exponent; + fraction_length -= exponent; + + if ( integer_length > 5 ) + goto Overflow; + if ( integer_length < -5 ) + goto Underflow; + + /* Remove non-significant digits. */ + if ( integer_length < 0 ) + { + number /= power_tens[-integer_length]; + fraction_length += integer_length; + } + + /* this can only happen if exponent was non-zero */ + if ( fraction_length == 10 ) + { + number /= 10; + fraction_length -= 1; + } + + /* Convert into 16.16 format. */ + if ( fraction_length > 0 ) + { + if ( ( number / power_tens[fraction_length] ) > 0x7FFFL ) + goto Exit; + + result = FT_DivFix( number, power_tens[fraction_length] ); + } + else + { + number *= power_tens[-fraction_length]; + + if ( number > 0x7FFFL ) + goto Overflow; + + result = (FT_Long)( (FT_ULong)number << 16 ); + } + } + + Exit: + if ( sign ) + result = -result; + + return result; + + Overflow: + result = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + + Underflow: + result = 0; + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + goto Exit; + + Bad: + result = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } + + + /* read a number, either integer or real */ + FT_LOCAL_DEF( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ) + { + if ( **d == 30 ) + { + /* binary-coded decimal is truncated to integer */ + return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16; + } + + else if ( **d == 255 ) + { + /* 16.16 fixed-point is used internally for CFF2 blend results. */ + /* Since these are trusted values, a limit check is not needed. */ + + /* After the 255, 4 bytes give the number. */ + /* The blend value is converted to integer, with rounding; */ + /* due to the right-shift we don't need the lowest byte. */ +#if 0 + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) + 0x8000U ) >> 16 ); +#else + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 8 ) | + (FT_UInt32)*( d[0] + 3 ) ) + 0x80U ) >> 8 ); +#endif + } + + else + return cff_parse_integer( *d, parser->limit ); + } + + + /* read a floating point number, either integer or real */ + static FT_Fixed + do_fixed( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) + { + if ( **d == 30 ) + return cff_parse_real( *d, parser->limit, scaling, NULL ); + else if ( **d == 255 ) + { + FT_Fixed val = (FT_Int32)( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) ); + + if ( scaling ) + { + if ( FT_ABS( val ) > power_ten_limits[scaling] ) + { + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; + } + val *= power_tens[scaling]; + } + return val; + } + else + { + FT_Long val = cff_parse_integer( *d, parser->limit ); + + + if ( scaling ) + { + if ( ( FT_ABS( val ) << 16 ) > power_ten_limits[scaling] ) + { + val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; + goto Overflow; + } + + val *= power_tens[scaling]; + } + + if ( val > 0x7FFF ) + { + val = 0x7FFFFFFFL; + goto Overflow; + } + else if ( val < -0x7FFF ) + { + val = -0x7FFFFFFFL; + goto Overflow; + } + + return (FT_Long)( (FT_ULong)val << 16 ); + + Overflow: + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val; + } + } + + + /* read a floating point number, either integer or real */ + FT_LOCAL_DEF( FT_Fixed ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ) + { + return do_fixed( parser, d, 0 ); + } + + + /* read a floating point number, either integer or real, */ + /* but return `10^scaling' times the number read in */ + static FT_Fixed + cff_parse_fixed_scaled( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) + { + return do_fixed( parser, d, scaling ); + } + + + /* read a floating point number, either integer or real, */ + /* and return it as precise as possible -- `scaling' returns */ + /* the scaling factor (as a power of 10) */ + static FT_Fixed + cff_parse_fixed_dynamic( CFF_Parser parser, + FT_Byte** d, + FT_Long* scaling ) + { + FT_ASSERT( scaling ); + + if ( **d == 30 ) + return cff_parse_real( *d, parser->limit, 0, scaling ); + else + { + FT_Long number; + FT_Int integer_length; + + + number = cff_parse_integer( *d, parser->limit ); + + if ( number > 0x7FFFL ) + { + for ( integer_length = 5; integer_length < 10; integer_length++ ) + if ( number < power_tens[integer_length] ) + break; + + if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL ) + { + *scaling = integer_length - 4; + return FT_DivFix( number, power_tens[integer_length - 4] ); + } + else + { + *scaling = integer_length - 5; + return FT_DivFix( number, power_tens[integer_length - 5] ); + } + } + else + { + *scaling = 0; + return (FT_Long)( (FT_ULong)number << 16 ); + } + } + } + + + static FT_Error + cff_parse_font_matrix( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Byte** data = parser->stack; + + + if ( parser->top >= parser->stack + 6 ) + { + FT_Fixed values[6]; + FT_Long scalings[6]; + + FT_Long min_scaling, max_scaling; + int i; + + + dict->has_font_matrix = TRUE; + + /* We expect a well-formed font matrix, that is, the matrix elements */ + /* `xx' and `yy' are of approximately the same magnitude. To avoid */ + /* loss of precision, we use the magnitude of the largest matrix */ + /* element to scale all other elements. The scaling factor is then */ + /* contained in the `units_per_em' value. */ + + max_scaling = FT_LONG_MIN; + min_scaling = FT_LONG_MAX; + + for ( i = 0; i < 6; i++ ) + { + values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] ); + if ( values[i] ) + { + if ( scalings[i] > max_scaling ) + max_scaling = scalings[i]; + if ( scalings[i] < min_scaling ) + min_scaling = scalings[i]; + } + } + + if ( max_scaling < -9 || + max_scaling > 0 || + ( max_scaling - min_scaling ) < 0 || + ( max_scaling - min_scaling ) > 9 ) + { + FT_TRACE1(( "cff_parse_font_matrix:" + " strange scaling values (minimum %ld, maximum %ld),\n", + min_scaling, max_scaling )); + FT_TRACE1(( " " + " using default matrix\n" )); + goto Unlikely; + } + + for ( i = 0; i < 6; i++ ) + { + FT_Fixed value = values[i]; + FT_Long divisor, half_divisor; + + + if ( !value ) + continue; + + divisor = power_tens[max_scaling - scalings[i]]; + half_divisor = divisor >> 1; + + if ( value < 0 ) + { + if ( FT_LONG_MIN + half_divisor < value ) + values[i] = ( value - half_divisor ) / divisor; + else + values[i] = FT_LONG_MIN / divisor; + } + else + { + if ( FT_LONG_MAX - half_divisor > value ) + values[i] = ( value + half_divisor ) / divisor; + else + values[i] = FT_LONG_MAX / divisor; + } + } + + matrix->xx = values[0]; + matrix->yx = values[1]; + matrix->xy = values[2]; + matrix->yy = values[3]; + offset->x = values[4]; + offset->y = values[5]; + + *upm = (FT_ULong)power_tens[-max_scaling]; + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)matrix->xx / (double)*upm / 65536, + (double)matrix->xy / (double)*upm / 65536, + (double)matrix->yx / (double)*upm / 65536, + (double)matrix->yy / (double)*upm / 65536, + (double)offset->x / (double)*upm / 65536, + (double)offset->y / (double)*upm / 65536 )); + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_TRACE1(( "cff_parse_font_matrix:" + " degenerate values, using default matrix\n" )); + goto Unlikely; + } + + return FT_Err_Ok; + } + else + return FT_THROW( Stack_Underflow ); + + Unlikely: + /* Return default matrix in case of unlikely values. */ + + matrix->xx = 0x10000L; + matrix->yx = 0; + matrix->xy = 0; + matrix->yy = 0x10000L; + offset->x = 0; + offset->y = 0; + *upm = 1; + + return FT_Err_Ok; + } + + + static FT_Error + cff_parse_font_bbox( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 4 ) + { + bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) ); + error = FT_Err_Ok; + + FT_TRACE4(( " [%ld %ld %ld %ld]\n", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + + return error; + } + + + static FT_Error + cff_parse_private_dict( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 2 ) + { + FT_Long tmp; + + + tmp = cff_parse_num( parser, data++ ); + if ( tmp < 0 ) + { + FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + dict->private_size = (FT_ULong)tmp; + + tmp = cff_parse_num( parser, data ); + if ( tmp < 0 ) + { + FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + dict->private_offset = (FT_ULong)tmp; + + FT_TRACE4(( " %lu %lu\n", + dict->private_size, dict->private_offset )); + + error = FT_Err_Ok; + } + + Fail: + return error; + } + + + /* The `MultipleMaster' operator comes before any */ + /* top DICT operators that contain T2 charstrings. */ + + static FT_Error + cff_parse_multiple_master( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Error error; + + +#ifdef FT_DEBUG_LEVEL_TRACE + /* beautify tracing message */ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] < 4 ) + FT_TRACE1(( "Multiple Master CFFs not supported yet," + " handling first master design only\n" )); + else + FT_TRACE1(( " (not supported yet," + " handling first master design only)\n" )); +#endif + + error = FT_ERR( Stack_Underflow ); + + /* currently, we handle only the first argument */ + if ( parser->top >= parser->stack + 5 ) + { + FT_Long num_designs = cff_parse_num( parser, parser->stack ); + + + if ( num_designs > 16 || num_designs < 2 ) + { + FT_ERROR(( "cff_parse_multiple_master:" + " Invalid number of designs\n" )); + error = FT_THROW( Invalid_File_Format ); + } + else + { + dict->num_designs = (FT_UShort)num_designs; + dict->num_axes = (FT_UShort)( parser->top - parser->stack - 4 ); + + parser->num_designs = dict->num_designs; + parser->num_axes = dict->num_axes; + + error = FT_Err_Ok; + } + } + + return error; + } + + + static FT_Error + cff_parse_cid_ros( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( parser->top >= parser->stack + 3 ) + { + dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ ); + dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ ); + if ( **data == 30 ) + FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); + dict->cid_supplement = cff_parse_num( parser, data ); + if ( dict->cid_supplement < 0 ) + FT_TRACE1(( "cff_parse_cid_ros: negative supplement %ld is found\n", + dict->cid_supplement )); + error = FT_Err_Ok; + + FT_TRACE4(( " %d %d %ld\n", + dict->cid_registry, + dict->cid_ordering, + dict->cid_supplement )); + } + + return error; + } + + + static FT_Error + cff_parse_vsindex( CFF_Parser parser ) + { + /* vsindex operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + FT_Byte** data = parser->stack; + CFF_Blend blend; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + blend = &priv->subfont->blend; + + if ( blend->usedBV ) + { + FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); + + FT_TRACE4(( " %d\n", priv->vsindex )); + + error = FT_Err_Ok; + + Exit: + return error; + } + + + static FT_Error + cff_parse_blend( CFF_Parser parser ) + { + /* blend operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + CFF_SubFont subFont; + CFF_Blend blend; + FT_UInt numBlends; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + subFont = priv->subfont; + blend = &subFont->blend; + + if ( cff_blend_check_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ) ) + { + error = cff_blend_build_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ); + if ( error ) + goto Exit; + } + + numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 ); + if ( numBlends > parser->stackSize ) + { + FT_ERROR(( "cff_parse_blend: Invalid number of blends\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE4(( " %d value%s blended\n", + numBlends, + numBlends == 1 ? "" : "s" )); + + error = cff_blend_doBlend( subFont, parser, numBlends ); + + blend->usedBV = TRUE; + + Exit: + return error; + } + + + /* maxstack operator increases parser and operand stacks for CFF2 */ + static FT_Error + cff_parse_maxstack( CFF_Parser parser ) + { + /* maxstack operator can only be used in a Top DICT */ + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error = FT_Err_Ok; + + + if ( !dict ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ ); + if ( dict->maxstack > CFF2_MAX_STACK ) + dict->maxstack = CFF2_MAX_STACK; + if ( dict->maxstack < CFF2_DEFAULT_STACK ) + dict->maxstack = CFF2_DEFAULT_STACK; + + FT_TRACE4(( " %d\n", dict->maxstack )); + + Exit: + return error; + } + + +#define CFF_FIELD_NUM( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_num ) +#define CFF_FIELD_FIXED( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed ) +#define CFF_FIELD_FIXED_1000( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed_thousand ) +#define CFF_FIELD_STRING( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_string ) +#define CFF_FIELD_BOOL( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_bool ) +#define CFF_FIELD_DELTA( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta ) +#define CFF_FIELD_DELTA_FIXED( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta_fixed ) + + +#undef CFF_FIELD +#undef CFF_FIELD_DELTA_KIND + + +#ifndef FT_DEBUG_LEVEL_TRACE + + +#define CFF_FIELD_CALLBACK( code, name, id ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0 \ + }, + +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0 \ + }, + +#define CFF_FIELD( code, name, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + NULL, 0, 0 \ + }, + +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ + }, + + static const CFF_Field_Handler cff_field_handlers[] = + { + +#include "cfftoken.h" + + { 0, 0, 0, 0, NULL, 0, 0 } + }; + + +#else /* FT_DEBUG_LEVEL_TRACE */ + + + +#define CFF_FIELD_CALLBACK( code, name, id ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0, \ + id \ + }, + +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0, \ + id \ + }, + +#define CFF_FIELD( code, name, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + NULL, 0, 0, \ + id \ + }, + +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ), \ + id \ + }, + + static const CFF_Field_Handler cff_field_handlers[] = + { + +#include "cfftoken.h" + + { 0, 0, 0, 0, NULL, 0, 0, NULL } + }; + + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + FT_LOCAL_DEF( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Error error = FT_Err_Ok; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PSAux_Service psaux; + + FT_Library library = parser->library; + FT_Memory memory = library->memory; +#endif + + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + + while ( p < limit ) + { + FT_UInt v = *p; + + + /* Opcode 31 is legacy MM T2 operator, not a number. */ + /* Opcode 255 is reserved and should not appear in fonts; */ + /* it is used internally for CFF2 blends. */ + if ( v >= 27 && v != 31 && v != 255 ) + { + /* it's a number; we will push its position on the stack */ + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + *parser->top++ = p; + + /* now, skip it */ + if ( v == 30 ) + { + /* skip real number */ + p++; + for (;;) + { + /* An unterminated floating point number at the */ + /* end of a dictionary is invalid but harmless. */ + if ( p >= limit ) + goto Exit; + v = p[0] >> 4; + if ( v == 15 ) + break; + v = p[0] & 0xF; + if ( v == 15 ) + break; + p++; + } + } + else if ( v == 28 ) + p += 2; + else if ( v == 29 ) + p += 4; + else if ( v > 246 ) + p += 1; + } +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( v == 31 ) + { + /* a Type 2 charstring */ + + CFF_Decoder decoder; + CFF_FontRec cff_rec; + FT_Byte* charstring_base; + FT_ULong charstring_len; + + FT_Fixed* stack; + FT_Byte* q = NULL; + + + charstring_base = ++p; + + /* search `endchar' operator */ + for (;;) + { + if ( p >= limit ) + goto Exit; + if ( *p == 14 ) + break; + p++; + } + + charstring_len = (FT_ULong)( p - charstring_base ) + 1; + + /* construct CFF_Decoder object */ + FT_ZERO( &decoder ); + FT_ZERO( &cff_rec ); + + cff_rec.top_font.font_dict.num_designs = parser->num_designs; + cff_rec.top_font.font_dict.num_axes = parser->num_axes; + decoder.cff = &cff_rec; + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" ); + if ( !psaux ) + { + FT_ERROR(( "cff_parser_run: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + error = psaux->cff_decoder_funcs->parse_charstrings_old( + &decoder, charstring_base, charstring_len, 1 ); + if ( error ) + goto Exit; + + /* Now copy the stack data in the temporary decoder object, */ + /* converting it back to charstring number representations */ + /* (this is ugly, I know). */ + /* The maximum required size is 5 bytes per stack element. */ + if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) + + 5 * ( decoder.top - decoder.stack ) ) ) + goto Exit; + + FT_List_Add( &parser->t2_strings, (FT_ListNode)q ); + + q += 2 * sizeof ( FT_ListNode ); + + for ( stack = decoder.stack; stack < decoder.top; stack++ ) + { + FT_Long num = *stack; + + + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + *parser->top++ = q; + + if ( num & 0xFFFFU ) + { + *q++ = 255; + *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 8 ) & 0xFF ); + *q++ = (FT_Byte)( ( num ) & 0xFF ); + } + else + { + num >>= 16; + + if ( -107 <= num && num <= 107 ) + *q++ = (FT_Byte)( num + 139 ); + else if ( 108 <= num && num <= 1131 ) + { + *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); + *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); + } + else if ( -1131 <= num && num <= -108 ) + { + *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 ); + *q++ = (FT_Byte)( ( -num - 108) & 0xFF ); + } + else + { + *q++ = 28; + *q++ = (FT_Byte)( num >> 8 ); + *q++ = (FT_Byte)( num & 0xFF ); + } + } + } + } +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + else + { + /* This is not a number, hence it's an operator. Compute its code */ + /* and look for it in our current list. */ + + FT_UInt code; + FT_UInt num_args; + const CFF_Field_Handler* field; + + + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + num_args = (FT_UInt)( parser->top - parser->stack ); + *parser->top = p; + code = v; + + if ( v == 12 ) + { + /* two byte operator */ + p++; + if ( p >= limit ) + goto Syntax_Error; + + code = 0x100 | p[0]; + } + code = code | parser->object_code; + + for ( field = cff_field_handlers; field->kind; field++ ) + { + if ( field->code == (FT_Int)code ) + { + /* we found our field's handler; read it */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " %s", field->id )); +#endif + + /* check that we have enough arguments -- except for */ + /* delta encoded arrays, which can be empty */ + if ( field->kind != cff_kind_delta && + field->kind != cff_kind_delta_fixed && num_args < 1 ) + goto Stack_Underflow; + + switch ( field->kind ) + { + case cff_kind_bool: + case cff_kind_string: + case cff_kind_num: + val = cff_parse_num( parser, parser->stack ); + goto Store_Number; + + case cff_kind_fixed: + val = cff_parse_fixed( parser, parser->stack ); + goto Store_Number; + + case cff_kind_fixed_thousand: + val = cff_parse_fixed_scaled( parser, parser->stack, 3 ); + + Store_Number: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + switch ( field->kind ) + { + case cff_kind_bool: + FT_TRACE4(( " %s\n", val ? "true" : "false" )); + break; + + case cff_kind_string: + FT_TRACE4(( " %ld (SID)\n", val )); + break; + + case cff_kind_num: + FT_TRACE4(( " %ld\n", val )); + break; + + case cff_kind_fixed: + FT_TRACE4(( " %f\n", (double)val / 65536 )); + break; + + case cff_kind_fixed_thousand: + FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 )); + break; + + default: + ; /* never reached */ + } +#endif + + break; + + case cff_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + FT_TRACE4(( " [" )); + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val = ADD_LONG( val, cff_parse_num( parser, data++ ) ); + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + + FT_TRACE4(( " %ld", val )); + + q += field->size; + num_args--; + } + + FT_TRACE4(( "]\n" )); + } + break; + + case cff_kind_delta_fixed: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + FT_TRACE4(( " [" )); + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val = ADD_LONG( val, cff_parse_fixed( parser, data++ ) ); + *(FT_Long*)q = val; + + FT_TRACE4(( " %f\n", (double)val / 65536 )); + + q += field->size; + num_args--; + } + + FT_TRACE4(( "]\n" )); + } + break; + + default: /* callback or blend */ + error = field->reader( parser ); + if ( error ) + goto Exit; + } + goto Found; + } + } + + /* this is an unknown operator, or it is unsupported; */ + /* we will ignore it for now. */ + + Found: + /* clear stack */ + /* TODO: could clear blend stack here, */ + /* but we don't have access to subFont */ + if ( field->kind != cff_kind_blend ) + parser->top = parser->stack; + } + p++; + } /* while ( p < limit ) */ + + Exit: + return error; + + Stack_Overflow: + error = FT_THROW( Invalid_Argument ); + goto Exit; + + Stack_Underflow: + error = FT_THROW( Invalid_Argument ); + goto Exit; + + Syntax_Error: + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cffparse.h b/Dependencies/freetype/freetype/src/cff/cffparse.h new file mode 100644 index 00000000..ca6b18af --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cffparse.h @@ -0,0 +1,144 @@ +/**************************************************************************** + * + * cffparse.h + * + * CFF token stream parser (specification) + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFPARSE_H_ +#define CFFPARSE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /* CFF uses constant parser stack size; */ + /* CFF2 can increase from default 193 */ +#define CFF_MAX_STACK_DEPTH 96 + + /* + * There are plans to remove the `maxstack' operator in a forthcoming + * revision of the CFF2 specification, increasing the (then static) stack + * size to 513. By making the default stack size equal to the maximum + * stack size, the operator is essentially disabled, which has the + * desired effect in FreeType. + */ +#define CFF2_MAX_STACK 513 +#define CFF2_DEFAULT_STACK 513 + +#define CFF_CODE_TOPDICT 0x1000 +#define CFF_CODE_PRIVATE 0x2000 +#define CFF2_CODE_TOPDICT 0x3000 +#define CFF2_CODE_FONTDICT 0x4000 +#define CFF2_CODE_PRIVATE 0x5000 + + + typedef struct CFF_ParserRec_ + { + FT_Library library; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + + FT_Byte** stack; + FT_Byte** top; + FT_UInt stackSize; /* allocated size */ + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_ListRec t2_strings; +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + FT_UInt object_code; + void* object; + + FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */ + FT_UShort num_axes; /* a copy of `CFF_FontRecDict->num_axes' */ + + } CFF_ParserRec, *CFF_Parser; + + + FT_LOCAL( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ); + + FT_LOCAL( FT_Fixed ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ); + + FT_LOCAL( FT_Error ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ); + + FT_LOCAL( void ) + cff_parser_done( CFF_Parser parser ); + + FT_LOCAL( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ); + + + enum + { + cff_kind_none = 0, + cff_kind_num, + cff_kind_fixed, + cff_kind_fixed_thousand, + cff_kind_string, + cff_kind_bool, + cff_kind_delta, + cff_kind_delta_fixed, + cff_kind_callback, + cff_kind_blend, + + cff_kind_max /* do not remove */ + }; + + + /* now generate handlers for the most simple fields */ + typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser ); + + typedef struct CFF_Field_Handler_ + { + int kind; + int code; + FT_UInt offset; + FT_Byte size; + CFF_Field_Reader reader; + FT_UInt array_max; + FT_UInt count_offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* id; +#endif + + } CFF_Field_Handler; + + +FT_END_HEADER + + +#endif /* CFFPARSE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cff/cfftoken.h b/Dependencies/freetype/freetype/src/cff/cfftoken.h new file mode 100644 index 00000000..da45faa7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cff/cfftoken.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * + * cfftoken.h + * + * CFF token definitions (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec + +#undef CFFCODE +#define CFFCODE CFF_CODE_TOPDICT + + CFF_FIELD_STRING ( 0, version, "Version" ) + CFF_FIELD_STRING ( 1, notice, "Notice" ) + CFF_FIELD_STRING ( 0x100, copyright, "Copyright" ) + CFF_FIELD_STRING ( 2, full_name, "FullName" ) + CFF_FIELD_STRING ( 3, family_name, "FamilyName" ) + CFF_FIELD_STRING ( 4, weight, "Weight" ) + CFF_FIELD_BOOL ( 0x101, is_fixed_pitch, "isFixedPitch" ) + CFF_FIELD_FIXED ( 0x102, italic_angle, "ItalicAngle" ) + CFF_FIELD_FIXED ( 0x103, underline_position, "UnderlinePosition" ) + CFF_FIELD_FIXED ( 0x104, underline_thickness, "UnderlineThickness" ) + CFF_FIELD_NUM ( 0x105, paint_type, "PaintType" ) + CFF_FIELD_NUM ( 0x106, charstring_type, "CharstringType" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + CFF_FIELD_NUM ( 13, unique_id, "UniqueID" ) + CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" ) + CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" ) +#if 0 + CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" ) +#endif + CFF_FIELD_NUM ( 15, charset_offset, "charset" ) + CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" ) + CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) + CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) + CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" ) + CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" ) + +#if 0 + CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" ) + CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" ) +#endif + + /* the next two operators were removed from the Type2 specification */ + /* in version 16-March-2000 */ + CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" ) +#if 0 + CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" ) +#endif + + CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" ) + CFF_FIELD_NUM ( 0x11F, cid_font_version, "CIDFontVersion" ) + CFF_FIELD_NUM ( 0x120, cid_font_revision, "CIDFontRevision" ) + CFF_FIELD_NUM ( 0x121, cid_font_type, "CIDFontType" ) + CFF_FIELD_NUM ( 0x122, cid_count, "CIDCount" ) + CFF_FIELD_NUM ( 0x123, cid_uid_base, "UIDBase" ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) + CFF_FIELD_STRING ( 0x126, cid_font_name, "FontName" ) + +#if 0 + CFF_FIELD_NUM ( 0x127, chameleon, "Chameleon" ) +#endif + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_PrivateRec +#undef CFFCODE +#define CFFCODE CFF_CODE_PRIVATE + + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) + CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) + CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) + CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_TOPDICT + + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) + CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" ) + CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" ) + CFF_FIELD_NUM ( 24, vstore_offset, "vstore" ) + CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRecDictRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_FONTDICT + + CFF_FIELD_CALLBACK( 18, private_dict, "Private" ) + CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_PrivateRec +#undef CFFCODE +#define CFFCODE CFF2_CODE_PRIVATE + + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) + CFF_FIELD_BLEND ( 23, "blend" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/ciderrs.h b/Dependencies/freetype/freetype/src/cid/ciderrs.h new file mode 100644 index 00000000..c439a8c4 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/ciderrs.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * ciderrs.h + * + * CID error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the CID error enumeration constants. + * + */ + +#ifndef CIDERRS_H_ +#define CIDERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CID_Err_ +#define FT_ERR_BASE FT_Mod_Err_CID + +#include + +#endif /* CIDERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidgload.c b/Dependencies/freetype/freetype/src/cid/cidgload.c new file mode 100644 index 00000000..7b571322 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidgload.c @@ -0,0 +1,618 @@ +/**************************************************************************** + * + * cidgload.c + * + * CID-keyed Type1 Glyph Loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cidload.h" +#include "cidgload.h" +#include +#include +#include +#include + +#include +#include +#include + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidgload + + + /* + * A helper function to compute FD number (`fd_select`), the offset to the + * head of the glyph data (`off1`), and the offset to the and of the glyph + * data (`off2`). + * + * The number how many times `cid_get_offset` is invoked can be controlled + * by the number of non-NULL arguments. If `fd_select` is non-NULL but + * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for + * `fd_select`; `off1` and `off2` are not validated. + * + */ + FT_LOCAL_DEF( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ) + { + FT_Error error = FT_Err_Ok; + + CID_FaceInfo cid = &face->cid; + FT_Stream stream = face->cid_stream; + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + + FT_Byte* p; + FT_Bool need_frame_exit = 0; + FT_ULong fd_select, off1, off2; + + + /* For ordinary fonts, read the CID font dictionary index */ + /* and charstring offset from the CIDMap. */ + + if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len ) || + FT_FRAME_ENTER( 2 * entry_len ) ) + goto Exit; + + need_frame_exit = 1; + + p = (FT_Byte*)stream->cursor; + fd_select = cid_get_offset( &p, cid->fd_bytes ); + off1 = cid_get_offset( &p, cid->gd_bytes ); + + p += cid->fd_bytes; + off2 = cid_get_offset( &p, cid->gd_bytes ); + + if ( fd_select_p ) + *fd_select_p = fd_select; + if ( off1_p ) + *off1_p = off1; + if ( off2_p ) + *off2_p = off2; + + if ( fd_select >= cid->num_dicts ) + { + /* + * fd_select == 0xFF is often used to indicate that the CID + * has no charstring to be rendered, similar to GID = 0xFFFF + * in TrueType fonts. + */ + if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) || + ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) + { + FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE1(( " FD number %ld is the maximum\n", + fd_select )); + FT_TRACE1(( " integer fitting into %d byte%s\n", + cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" )); + } + else + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " FD number %ld is larger\n", + fd_select )); + FT_TRACE0(( " than number of dictionaries (%d)\n", + cid->num_dicts )); + } + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off2 > stream->size ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " end of the glyph data\n" )); + FT_TRACE0(( " is beyond the data stream\n" )); + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off1 > off2 ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + glyph_index )); + FT_TRACE0(( " the end position of glyph data\n" )); + FT_TRACE0(( " is set before the start position\n" )); + + error = FT_THROW( Invalid_Offset ); + } + + Exit: + if ( need_frame_exit ) + FT_FRAME_EXIT(); + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_load_glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + CID_Face face = (CID_Face)decoder->builder.face; + CID_FaceInfo cid = &face->cid; + FT_Byte* p; + FT_ULong fd_select; + FT_Stream stream = face->cid_stream; + FT_Error error = FT_Err_Ok; + FT_Byte* charstring = NULL; + FT_Memory memory = face->root.memory; + FT_ULong glyph_length = 0; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Bool force_scaling = FALSE; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; +#endif + + + FT_TRACE1(( "cid_load_glyph: glyph index %u\n", glyph_index )); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using */ + /* the callback function. */ + if ( inc ) + { + FT_Data glyph_data; + + + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, &glyph_data ); + if ( error || glyph_data.length < cid->fd_bytes ) + goto Exit; + + p = (FT_Byte*)glyph_data.pointer; + fd_select = cid_get_offset( &p, cid->fd_bytes ); + + glyph_length = glyph_data.length - cid->fd_bytes; + + if ( !FT_QALLOC( charstring, glyph_length ) ) + FT_MEM_COPY( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length ); + + inc->funcs->free_glyph_data( inc->object, &glyph_data ); + + if ( error ) + goto Exit; + } + + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ULong off1, off2; + + + error = cid_compute_fd_and_offsets( face, glyph_index, + &fd_select, &off1, &off2 ); + if ( error ) + goto Exit; + + glyph_length = off2 - off1; + + if ( glyph_length == 0 || + FT_QALLOC( charstring, glyph_length ) || + FT_STREAM_READ_AT( cid->data_offset + off1, + charstring, glyph_length ) ) + goto Exit; + } + + /* Now set up the subrs array and parse the charstrings. */ + { + CID_FaceDict dict; + CID_Subrs cid_subrs = face->subrs + fd_select; + FT_UInt cs_offset; + + + /* Set up subrs */ + decoder->num_subrs = cid_subrs->num_subrs; + decoder->subrs = cid_subrs->code; + decoder->subrs_len = 0; + decoder->subrs_hash = NULL; + + /* Set up font matrix */ + dict = cid->font_dicts + fd_select; + + decoder->font_matrix = dict->font_matrix; + decoder->font_offset = dict->font_offset; + decoder->lenIV = dict->private_dict.lenIV; + + /* Decode the charstring. */ + + /* Adjustment for seed bytes. */ + cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0; + if ( cs_offset > glyph_length ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "offset to the charstring is beyond glyph length\n", + glyph_index )); + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + + /* Decrypt only if lenIV >= 0. */ + if ( decoder->lenIV >= 0 ) + psaux->t1_decrypt( charstring, glyph_length, 4330 ); + + /* choose which renderer to use */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + if ( ( (PS_Driver)FT_FACE_DRIVER( face ) )->hinting_engine == + FT_HINTING_FREETYPE || + decoder->builder.metrics_only ) + error = psaux->t1_decoder_funcs->parse_charstrings_old( + decoder, + charstring + cs_offset, + glyph_length - cs_offset ); +#else + if ( decoder->builder.metrics_only ) + error = psaux->t1_decoder_funcs->parse_metrics( + decoder, + charstring + cs_offset, + glyph_length - cs_offset ); +#endif + else + { + PS_Decoder psdecoder; + CFF_SubFontRec subfont; + + + psaux->ps_decoder_init( &psdecoder, decoder, TRUE ); + + psaux->t1_make_subfont( FT_FACE( face ), + &dict->private_dict, + &subfont ); + psdecoder.current_subfont = &subfont; + + error = psaux->t1_decoder_funcs->parse_charstrings( + &psdecoder, + charstring + cs_offset, + glyph_length - cs_offset ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + ((CID_GlyphSlot)decoder->builder.glyph)->hint = FALSE; + + force_scaling = TRUE; + + error = psaux->t1_decoder_funcs->parse_charstrings( + &psdecoder, + charstring + cs_offset, + glyph_length - cs_offset ); + } + } + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && inc && inc->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x ); + metrics.bearing_y = 0; + metrics.advance = FIXED_TO_INT( decoder->builder.advance.x ); + metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y ); + + error = inc->funcs->get_glyph_metrics( inc->object, + glyph_index, FALSE, &metrics ); + + decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x ); + decoder->builder.advance.x = INT_TO_FIXED( metrics.advance ); + decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + Exit: + FT_FREE( charstring ); + + ((CID_GlyphSlot)decoder->builder.glyph)->scaled = force_scaling; + + return error; + } + + +#if 0 + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + *max_advance = 0; + + /* Initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + 0, /* glyph names! XXX */ + 0, /* blend == 0 */ + 0, /* hinting == 0 */ + cid_load_glyph ); + if ( error ) + return error; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; + glyph_index++ ) + { + /* now get load the unscaled outline */ + error = cid_load_glyph( &decoder, glyph_index ); + /* ignore the error if one occurred - skip to next glyph */ + } + + *max_advance = FIXED_TO_INT( decoder.builder.advance.x ); + + psaux->t1_decoder_funcs->done( &decoder ); + + return FT_Err_Ok; + } + + +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot cidglyph, /* CID_GlyphSlot */ + FT_Size cidsize, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + CID_GlyphSlot glyph = (CID_GlyphSlot)cidglyph; + FT_Error error; + T1_DecoderRec decoder; + CID_Face face = (CID_Face)cidglyph->face; + FT_Bool hinting; + FT_Bool scaled; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Bool must_finish_decoder = FALSE; + + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = cidsize->metrics.x_scale; + glyph->y_scale = cidsize->metrics.y_scale; + + cidglyph->outline.n_points = 0; + cidglyph->outline.n_contours = 0; + + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + error = psaux->t1_decoder_funcs->init( &decoder, + cidglyph->face, + cidsize, + cidglyph, + 0, /* glyph names -- XXX */ + 0, /* blend == 0 */ + hinting, + FT_LOAD_TARGET_MODE( load_flags ), + cid_load_glyph ); + if ( error ) + goto Exit; + + /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ + /* if we ever support CID-keyed multiple master fonts */ + + must_finish_decoder = TRUE; + + /* set up the decoder */ + decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + error = cid_load_glyph( &decoder, glyph_index ); + if ( error ) + goto Exit; + + /* copy flags back for forced scaling */ + hinting = glyph->hint; + scaled = glyph->scaled; + + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + psaux->t1_decoder_funcs->done( &decoder ); + + must_finish_decoder = FALSE; + + /* now set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + cidglyph->outline.flags &= FT_OUTLINE_OWNER; + cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = cidglyph->internal; + + + cidglyph->metrics.horiBearingX = + FIXED_TO_INT( decoder.builder.left_bearing.x ); + cidglyph->metrics.horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &cidglyph->metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + cidglyph->linearHoriAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + cidglyph->internal->glyph_transformed = 0; + + /* make up vertical ones */ + metrics->vertAdvance = ( face->cid.font_bbox.yMax - + face->cid.font_bbox.yMin ) >> 16; + cidglyph->linearVertAdvance = metrics->vertAdvance; + + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + if ( cidsize->metrics.y_ppem < 24 ) + cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &cidglyph->outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &cidglyph->outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || scaled ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &cidglyph->outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + + Exit: + + if ( must_finish_decoder ) + psaux->t1_decoder_funcs->done( &decoder ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidgload.h b/Dependencies/freetype/freetype/src/cid/cidgload.h new file mode 100644 index 00000000..9fdc9db5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidgload.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * cidgload.h + * + * OpenType Glyph Loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDGLOAD_H_ +#define CIDGLOAD_H_ + + +#include "cidobjs.h" + + +FT_BEGIN_HEADER + + +#if 0 + + /* Compute the maximum advance width of a font through quick parsing */ + FT_LOCAL( FT_Error ) + cid_face_compute_max_advance( CID_Face face, + FT_Int* max_advance ); + +#endif /* 0 */ + + FT_LOCAL( FT_Error ) + cid_slot_load_glyph( FT_GlyphSlot glyph, /* CID_Glyph_Slot */ + FT_Size size, /* CID_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ); + + + FT_LOCAL( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ); + + +FT_END_HEADER + +#endif /* CIDGLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidload.c b/Dependencies/freetype/freetype/src/cid/cidload.c new file mode 100644 index 00000000..722f5a34 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidload.c @@ -0,0 +1,937 @@ +/**************************************************************************** + * + * cidload.c + * + * CID-keyed Type1 font loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include + +#include "cidload.h" + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidload + + + /* read a single offset */ + FT_LOCAL_DEF( FT_ULong ) + cid_get_offset( FT_Byte* *start, + FT_UInt offsize ) + { + FT_ULong result; + FT_Byte* p = *start; + + + for ( result = 0; offsize > 0; offsize-- ) + { + result <<= 8; + result |= *p++; + } + + *start = p; + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + static FT_Error + cid_load_keyword( CID_Face face, + CID_Loader* loader, + const T1_Field keyword ) + { + FT_Error error; + CID_Parser* parser = &loader->parser; + FT_Byte* object; + void* dummy_object; + CID_FaceInfo cid = &face->cid; + + + /* if the keyword has a dedicated callback, call it */ + if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) + { + FT_TRACE4(( " %s", keyword->ident )); + + keyword->reader( (FT_Face)face, parser ); + error = parser->root.error; + goto Exit; + } + + /* we must now compute the address of our target object */ + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_CID_INFO: + object = (FT_Byte*)cid; + break; + + case T1_FIELD_LOCATION_FONT_INFO: + object = (FT_Byte*)&cid->font_info; + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + object = (FT_Byte*)&face->font_extra; + break; + + case T1_FIELD_LOCATION_BBOX: + object = (FT_Byte*)&cid->font_bbox; + break; + + default: + { + CID_FaceDict dict; + + + if ( parser->num_dict >= cid->num_dicts ) + { + FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", + keyword->ident )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + dict = cid->font_dicts + parser->num_dict; + switch ( keyword->location ) + { + case T1_FIELD_LOCATION_PRIVATE: + object = (FT_Byte*)&dict->private_dict; + break; + + default: + object = (FT_Byte*)dict; + } + } + } + + FT_TRACE4(( " %s", keyword->ident )); + + dummy_object = object; + + /* now, load the keyword data in the object's field(s) */ + if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || + keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = cid_parser_load_field_table( &loader->parser, keyword, + &dummy_object ); + else + error = cid_parser_load_field( &loader->parser, + keyword, &dummy_object ); + + FT_TRACE4(( "\n" )); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + cid_parse_font_matrix( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceDict dict; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + FT_Matrix* matrix; + FT_Vector* offset; + FT_Int result; + + + dict = cidface->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + offset = &dict->font_offset; + + /* input is scaled by 1000 to accommodate default FontMatrix */ + result = cid_parser_to_fixed_array( parser, 6, temp, 3 ); + + if ( result < 6 ) + { + FT_ERROR(( "cid_parse_font_matrix: not enough matrix elements\n" )); + goto Exit; + } + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)temp[0] / 65536 / 1000, + (double)temp[1] / 65536 / 1000, + (double)temp[2] / 65536 / 1000, + (double)temp[3] / 65536 / 1000, + (double)temp[4] / 65536 / 1000, + (double)temp[5] / 65536 / 1000 )); + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" )); + goto Exit; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + /* set units per EM based on FontMatrix values */ + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* note that the font offsets are expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + Exit: + return; + } + + + FT_CALLBACK_DEF( void ) + parse_fd_array( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceInfo cid = &cidface->cid; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Stream stream = parser->stream; + FT_Error error = FT_Err_Ok; + FT_Long num_dicts, max_dicts; + + + num_dicts = cid_parser_to_int( parser ); + if ( num_dicts < 0 || num_dicts > FT_INT_MAX ) + { + FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); + goto Exit; + } + + FT_TRACE4(( " %ld\n", num_dicts )); + + /* + * A single entry in the FDArray must (at least) contain the following + * structure elements. + * + * %ADOBeginFontDict 18 + * X dict begin 13 + * /FontMatrix [X X X X] 22 + * /Private X dict begin 22 + * end 4 + * end 4 + * %ADOEndFontDict 16 + * + * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also + * need a `dup X' at the very beginning and a `put' at the end, so a + * rough guess using 100 bytes as the minimum is justified. + */ + max_dicts = (FT_Long)( stream->size / 100 ); + if ( num_dicts > max_dicts ) + { + FT_TRACE0(( "parse_fd_array: adjusting FDArray size" + " (from %ld to %ld)\n", + num_dicts, max_dicts )); + num_dicts = max_dicts; + } + + if ( !cid->font_dicts ) + { + FT_UInt n; + + + if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) + goto Exit; + + cid->num_dicts = num_dicts; + + /* set some default values (the same as for Type 1 fonts) */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + + + dict->private_dict.blue_shift = 7; + dict->private_dict.blue_fuzz = 1; + dict->private_dict.lenIV = 4; + dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + dict->private_dict.blue_scale = (FT_Fixed)( + 0.039625 * 0x10000L * 1000 ); + } + } + + Exit: + return; + } + + + /* By mistake, `expansion_factor' appears both in PS_PrivateRec */ + /* and CID_FaceDictRec (both are public header files and can't */ + /* be thus changed). We simply copy the value. */ + + FT_CALLBACK_DEF( void ) + parse_expansion_factor( FT_Face face, /* CID_Face */ + void* parser_ ) + { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceDict dict; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + dict = cidface->cid.font_dicts + parser->num_dict; + + dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); + dict->private_dict.expansion_factor = dict->expansion_factor; + + FT_TRACE4(( "%ld\n", dict->expansion_factor )); + } + + return; + } + + + /* By mistake, `CID_FaceDictRec' doesn't contain a field for the */ + /* `FontName' keyword. FreeType doesn't need it, but it is nice */ + /* to catch it for producing better trace output. */ + + FT_CALLBACK_DEF( void ) + parse_font_name( FT_Face face, /* CID_Face */ + void* parser_ ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + + + if ( parser->num_dict < cidface->cid.num_dicts ) + { + T1_TokenRec token; + FT_UInt len; + + + cid_parser_to_token( parser, &token ); + + len = (FT_UInt)( token.limit - token.start ); + if ( len ) + FT_TRACE4(( " %.*s\n", len, token.start )); + else + FT_TRACE4(( " \n" )); + } +#else + FT_UNUSED( face ); + FT_UNUSED( parser_ ); +#endif + + return; + } + + + static + const T1_FieldRec cid_field_records[] = + { + +#include "cidtoken.h" + + T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) + T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) + T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) + + T1_FIELD_ZERO + }; + + + static FT_Error + cid_parse_dict( CID_Face face, + CID_Loader* loader, + FT_Byte* base, + FT_ULong size ) + { + CID_Parser* parser = &loader->parser; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + + for (;;) + { + FT_Byte* newlimit; + + + parser->root.cursor = cur; + cid_parser_skip_spaces( parser ); + + if ( parser->root.cursor >= limit ) + newlimit = limit - 1 - 17; + else + newlimit = parser->root.cursor - 17; + + /* look for `%ADOBeginFontDict' */ + for ( ; cur < newlimit; cur++ ) + { + if ( *cur == '%' && + ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + { + parser->num_dict++; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " FontDict %u", parser->num_dict )); + if ( parser->num_dict > face->cid.num_dicts ) + FT_TRACE4(( " (ignored)" )); + FT_TRACE4(( "\n" )); +#endif + } + } + } + + cur = parser->root.cursor; + /* no error can occur in cid_parser_skip_spaces */ + if ( cur >= limit ) + break; + + cid_parser_skip_PS_token( parser ); + if ( parser->root.cursor >= limit || parser->root.error ) + break; + + /* look for immediates */ + if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)cid_field_records; + + + while ( keyword->len ) + { + FT_Byte* name = (FT_Byte*)keyword->ident; + + + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) + { + /* we found it - run the parsing callback */ + parser->root.error = cid_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + + keyword++; + } + } + } + + cur = parser->root.cursor; + } + + if ( !face->cid.num_dicts ) + { + FT_ERROR(( "cid_parse_dict: No font dictionary found\n" )); + return FT_THROW( Invalid_File_Format ); + } + } + + return parser->root.error; + } + + + /* read the subrmap and the subrs of each font dict */ + static FT_Error + cid_read_subrs( CID_Face face ) + { + CID_FaceInfo cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->cid_stream; + FT_Error error; + FT_UInt n; + CID_Subrs subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = NULL; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) + goto Exit; + + subr = face->subrs; + for ( n = 0; n < cid->num_dicts; n++, subr++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + FT_Int lenIV = dict->private_dict.lenIV; + FT_UInt count, num_subrs = dict->num_subrs; + FT_ULong data_len; + FT_Byte* p; + + + if ( !num_subrs ) + continue; + + /* reallocate offsets array if needed */ + if ( num_subrs + 1 > max_offsets ) + { + FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); + + + if ( new_max <= max_offsets ) + { + error = FT_THROW( Syntax_Error ); + goto Fail; + } + + if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) ) + goto Fail; + + max_offsets = new_max; + } + + /* read the subrmap's offsets */ + if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || + FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) + goto Fail; + + p = (FT_Byte*)stream->cursor; + for ( count = 0; count <= num_subrs; count++ ) + offsets[count] = cid_get_offset( &p, dict->sd_bytes ); + + FT_FRAME_EXIT(); + + /* offsets must be ordered */ + for ( count = 1; count <= num_subrs; count++ ) + if ( offsets[count - 1] > offsets[count] ) + { + FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( offsets[num_subrs] > stream->size - cid->data_offset ) + { + FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* now, compute the size of subrs charstrings, */ + /* allocate, and read them */ + data_len = offsets[num_subrs] - offsets[0]; + + if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_QALLOC( subr->code[0], data_len ) ) + goto Fail; + + if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || + FT_STREAM_READ( subr->code[0], data_len ) ) + goto Fail; + + /* set up pointers */ + for ( count = 1; count <= num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count] - offsets[count - 1]; + subr->code[count] = subr->code[count - 1] + len; + } + + /* decrypt subroutines, but only if lenIV >= 0 */ + if ( lenIV >= 0 ) + { + for ( count = 0; count < num_subrs; count++ ) + { + FT_ULong len; + + + len = offsets[count + 1] - offsets[count]; + psaux->t1_decrypt( subr->code[count], len, 4330 ); + } + } + + subr->num_subrs = (FT_Int)num_subrs; + } + + Exit: + FT_FREE( offsets ); + return error; + + Fail: + if ( face->subrs ) + { + for ( n = 0; n < cid->num_dicts; n++ ) + { + if ( face->subrs[n].code ) + FT_FREE( face->subrs[n].code[0] ); + + FT_FREE( face->subrs[n].code ); + } + FT_FREE( face->subrs ); + } + goto Exit; + } + + + static void + cid_init_loader( CID_Loader* loader, + CID_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + } + + + static void + cid_done_loader( CID_Loader* loader ) + { + CID_Parser* parser = &loader->parser; + + + /* finalize parser */ + cid_parser_done( parser ); + } + + + static FT_Error + cid_hex_to_binary( FT_Byte* data, + FT_ULong data_len, + FT_ULong offset, + CID_Face face, + FT_ULong* data_written ) + { + FT_Stream stream = face->root.stream; + FT_Error error; + + FT_Byte buffer[256]; + FT_Byte *p, *plimit; + FT_Byte *d = data, *dlimit; + FT_Byte val; + + FT_Bool upper_nibble, done; + + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + + dlimit = d + data_len; + p = buffer; + plimit = p; + + upper_nibble = 1; + done = 0; + + while ( d < dlimit ) + { + if ( p >= plimit ) + { + FT_ULong oldpos = FT_STREAM_POS(); + FT_ULong size = stream->size - oldpos; + + + if ( size == 0 ) + { + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) + goto Exit; + p = buffer; + plimit = p + FT_STREAM_POS() - oldpos; + } + + if ( ft_isdigit( *p ) ) + val = (FT_Byte)( *p - '0' ); + else if ( *p >= 'a' && *p <= 'f' ) + val = (FT_Byte)( *p - 'a' + 10 ); + else if ( *p >= 'A' && *p <= 'F' ) + val = (FT_Byte)( *p - 'A' + 10 ); + else if ( *p == ' ' || + *p == '\t' || + *p == '\r' || + *p == '\n' || + *p == '\f' || + *p == '\0' ) + { + p++; + continue; + } + else if ( *p == '>' ) + { + val = 0; + done = 1; + } + else + { + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + if ( upper_nibble ) + *d = (FT_Byte)( val << 4 ); + else + { + *d = (FT_Byte)( *d + val ); + d++; + } + + upper_nibble = (FT_Byte)( 1 - upper_nibble ); + + if ( done ) + break; + + p++; + } + + error = FT_Err_Ok; + + Exit: + *data_written = (FT_ULong)( d - data ); + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ) + { + CID_Loader loader; + CID_Parser* parser; + FT_Memory memory = face->root.memory; + FT_Error error; + FT_UInt n; + + CID_FaceInfo cid = &face->cid; + + FT_ULong binary_length; + + + cid_init_loader( &loader, face ); + + parser = &loader.parser; + error = cid_parser_new( parser, face->root.stream, face->root.memory, + (PSAux_Service)face->psaux ); + if ( error ) + goto Exit; + + error = cid_parse_dict( face, &loader, + parser->postscript, + parser->postscript_len ); + if ( error ) + goto Exit; + + if ( face_index < 0 ) + goto Exit; + + if ( FT_NEW( face->cid_stream ) ) + goto Exit; + + if ( parser->binary_length ) + { + if ( parser->binary_length > + face->root.stream->size - parser->data_offset ) + { + FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" )); + FT_TRACE0(( " (from %lu to %lu bytes)\n", + parser->binary_length, + face->root.stream->size - parser->data_offset )); + parser->binary_length = face->root.stream->size - + parser->data_offset; + } + + /* we must convert the data section from hexadecimal to binary */ + if ( FT_QALLOC( face->binary_data, parser->binary_length ) || + FT_SET_ERROR( cid_hex_to_binary( face->binary_data, + parser->binary_length, + parser->data_offset, + face, + &binary_length ) ) ) + goto Exit; + + FT_Stream_OpenMemory( face->cid_stream, + face->binary_data, binary_length ); + cid->data_offset = 0; + } + else + { + *face->cid_stream = *face->root.stream; + cid->data_offset = loader.parser.data_offset; + } + + /* sanity tests */ + + if ( cid->gd_bytes == 0 ) + { + FT_ERROR(( "cid_face_open:" + " Invalid `GDBytes' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allow at most 32bit offsets */ + if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 ) + { + FT_ERROR(( "cid_face_open:" + " Values of `FDBytes' or `GDBytes' larger than 4\n" )); + FT_ERROR(( " " + " are not supported\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + binary_length = face->cid_stream->size - cid->data_offset; + + if ( cid->cidmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( cid->cid_count > FT_ULONG_MAX / 8 || + cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) > + binary_length - cid->cidmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; + + + /* the upper limits are ad-hoc values */ + if ( dict->private_dict.blue_shift > 1000 || + dict->private_dict.blue_shift < 0 ) + { + FT_TRACE2(( "cid_face_open:" + " setting unlikely BlueShift value %d to default (7)\n", + dict->private_dict.blue_shift )); + dict->private_dict.blue_shift = 7; + } + + if ( dict->private_dict.blue_fuzz > 1000 || + dict->private_dict.blue_fuzz < 0 ) + { + FT_TRACE2(( "cid_face_open:" + " setting unlikely BlueFuzz value %d to default (1)\n", + dict->private_dict.blue_fuzz )); + dict->private_dict.blue_fuzz = 1; + } + + if ( dict->num_subrs && dict->sd_bytes == 0 ) + { + FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dict->sd_bytes > 4 ) + { + FT_ERROR(( "cid_face_open:" + " Values of `SDBytes' larger than 4" + " are not supported\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dict->subrmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( dict->num_subrs > FT_UINT_MAX / 4 || + dict->num_subrs * dict->sd_bytes > + binary_length - dict->subrmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + + /* we can now safely proceed */ + error = cid_read_subrs( face ); + + Exit: + cid_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidload.h b/Dependencies/freetype/freetype/src/cid/cidload.h new file mode 100644 index 00000000..7f030b32 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidload.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * cidload.h + * + * CID-keyed Type1 font loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDLOAD_H_ +#define CIDLOAD_H_ + + +#include +#include "cidparse.h" + + +FT_BEGIN_HEADER + + + typedef struct CID_Loader_ + { + CID_Parser parser; /* parser used to read the stream */ + FT_Int num_chars; /* number of characters in encoding */ + + } CID_Loader; + + + FT_LOCAL( FT_ULong ) + cid_get_offset( FT_Byte** start, + FT_UInt offsize ); + + FT_LOCAL( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ); + + +FT_END_HEADER + +#endif /* CIDLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidobjs.c b/Dependencies/freetype/freetype/src/cid/cidobjs.c new file mode 100644 index 00000000..8d337c41 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidobjs.c @@ -0,0 +1,543 @@ +/**************************************************************************** + * + * cidobjs.c + * + * CID objects manager (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "cidgload.h" +#include "cidload.h" + +#include +#include +#include +#include + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidobjs + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + cid_slot_done( FT_GlyphSlot slot ) + { + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ) + { + CID_Face face; + PSHinter_Service pshinter; + + + face = (CID_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + + + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + cid_size_get_globals_funcs( CID_Size size ) + { + CID_Face face = (CID_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + cid_size_done( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + + + if ( cidsize->internal->module_data ) + { + PSH_Globals_Funcs funcs; + + + funcs = cid_size_get_globals_funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)cidsize->internal->module_data ); + + cidsize->internal->module_data = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + cid_size_init( FT_Size cidsize ) /* CID_Size */ + { + CID_Size size = (CID_Size)cidsize; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + CID_Face face = (CID_Face)cidsize->face; + CID_FaceDict dict = face->cid.font_dicts + face->root.face_index; + PS_Private priv = &dict->private_dict; + + + error = funcs->create( cidsize->face->memory, priv, &globals ); + if ( !error ) + cidsize->internal->module_data = globals; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + cid_size_request( FT_Size size, + FT_Size_Request req ) + { + FT_Error error; + + PSH_Globals_Funcs funcs; + + + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; + + funcs = cid_size_get_globals_funcs( (CID_Size)size ); + + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal->module_data, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + + Exit: + return error; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + /************************************************************************** + * + * @Function: + * cid_face_done + * + * @Description: + * Finalizes a given face object. + * + * @Input: + * face :: + * A pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + cid_face_done( FT_Face cidface ) /* CID_Face */ + { + CID_Face face = (CID_Face)cidface; + FT_Memory memory; + CID_FaceInfo cid; + PS_FontInfo info; + + + if ( !face ) + return; + + cid = &face->cid; + info = &cid->font_info; + memory = cidface->memory; + + /* release subrs */ + if ( face->subrs ) + { + FT_UInt n; + + + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_Subrs subr = face->subrs + n; + + + if ( subr->code ) + { + FT_FREE( subr->code[0] ); + FT_FREE( subr->code ); + } + } + + FT_FREE( face->subrs ); + } + + /* release FontInfo strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release font dictionaries */ + FT_FREE( cid->font_dicts ); + cid->num_dicts = 0; + + /* release other strings */ + FT_FREE( cid->cid_font_name ); + FT_FREE( cid->registry ); + FT_FREE( cid->ordering ); + + cidface->family_name = NULL; + cidface->style_name = NULL; + + FT_FREE( face->binary_data ); + FT_FREE( face->cid_stream ); + } + + + /************************************************************************** + * + * @Function: + * cid_face_init + * + * @Description: + * Initializes a given CID face object. + * + * @Input: + * stream :: + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. + * + * face_index :: + * The index of the font face in the resource. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The newly built face object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face cidface, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CID_Face face = (CID_Face)cidface; + FT_Error error; + PSAux_Service psaux; + PSHinter_Service pshinter; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + cidface->num_faces = 1; + + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + psaux = (PSAux_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "psaux" ); + + if ( !psaux ) + { + FT_ERROR(( "cid_face_init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + face->psaux = psaux; + } + + pshinter = (PSHinter_Service)face->pshinter; + if ( !pshinter ) + { + pshinter = (PSHinter_Service)FT_Get_Module_Interface( + FT_FACE_LIBRARY( face ), "pshinter" ); + + face->pshinter = pshinter; + } + + FT_TRACE2(( "CID driver\n" )); + + /* open the tokenizer; this will also check the font format */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = cid_face_open( face, face_index ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + /* XXX: handle CID fonts with more than a single face */ + if ( ( face_index & 0xFFFF ) != 0 ) + { + FT_ERROR(( "cid_face_init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + CID_FaceInfo cid = &face->cid; + PS_FontInfo info = &cid->font_info; + + + cidface->num_glyphs = (FT_Long)cid->cid_count; + cidface->num_charmaps = 0; + + cidface->face_index = face_index & 0xFFFF; + + cidface->face_flags |= FT_FACE_FLAG_SCALABLE | /* scalable outlines */ + FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ + FT_FACE_FLAG_HINTER; /* has native hinter */ + + if ( info->is_fixed_pitch ) + cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* + * For the sfnt-wrapped CID fonts for MacOS, currently, + * its `cmap' tables are ignored, and the content in + * its `CID ' table is treated the same as naked CID-keyed + * font. See ft_lookup_PS_in_sfnt_stream(). + */ + cidface->face_flags |= FT_FACE_FLAG_CID_KEYED; + + /* XXX: TODO: add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a /FontName dictionary entry! */ + cidface->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + cidface->style_name = (char *)"Regular"; + if ( cidface->family_name ) + { + char* full = info->full_name; + char* family = cidface->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + cidface->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( cid->cid_font_name ) + cidface->family_name = cid->cid_font_name; + } + + /* compute style flags */ + cidface->style_flags = 0; + if ( info->italic_angle ) + cidface->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + cidface->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + cidface->num_fixed_sizes = 0; + cidface->available_sizes = NULL; + + cidface->bbox.xMin = cid->font_bbox.xMin >> 16; + cidface->bbox.yMin = cid->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + cidface->bbox.xMax = ( cid->font_bbox.xMax + 0xFFFF ) >> 16; + cidface->bbox.yMax = ( cid->font_bbox.yMax + 0xFFFF ) >> 16; + + if ( !cidface->units_per_EM ) + cidface->units_per_EM = 1000; + + cidface->ascender = (FT_Short)( cidface->bbox.yMax ); + cidface->descender = (FT_Short)( cidface->bbox.yMin ); + + cidface->height = (FT_Short)( ( cidface->units_per_EM * 12 ) / 10 ); + if ( cidface->height < cidface->ascender - cidface->descender ) + cidface->height = (FT_Short)( cidface->ascender - cidface->descender ); + + cidface->underline_position = (FT_Short)info->underline_position; + cidface->underline_thickness = (FT_Short)info->underline_thickness; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * cid_driver_init + * + * @Description: + * Initializes a given CID driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cid_driver_init( FT_Module module ) + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftt1drv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * cid_driver_done + * + * @Description: + * Finalizes a given CID driver. + * + * @Input: + * driver :: + * A handle to the target CID driver. + */ + FT_LOCAL_DEF( void ) + cid_driver_done( FT_Module driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidobjs.h b/Dependencies/freetype/freetype/src/cid/cidobjs.h new file mode 100644 index 00000000..d371cbe9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidobjs.h @@ -0,0 +1,154 @@ +/**************************************************************************** + * + * cidobjs.h + * + * CID objects manager (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDOBJS_H_ +#define CIDOBJS_H_ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct CID_Size_Hints_ CID_Size_Hints; + typedef struct CID_Glyph_Hints_ CID_Glyph_Hints; + + + /************************************************************************** + * + * @Type: + * CID_Driver + * + * @Description: + * A handle to a Type 1 driver object. + */ + typedef struct CID_DriverRec_* CID_Driver; + + + /************************************************************************** + * + * @Type: + * CID_Size + * + * @Description: + * A handle to a Type 1 size object. + */ + typedef struct CID_SizeRec_* CID_Size; + + + /************************************************************************** + * + * @Type: + * CID_GlyphSlot + * + * @Description: + * A handle to a Type 1 glyph slot object. + */ + typedef struct CID_GlyphSlotRec_* CID_GlyphSlot; + + + /************************************************************************** + * + * @Type: + * CID_CharMap + * + * @Description: + * A handle to a Type 1 character mapping object. + * + * @Note: + * The Type 1 format doesn't use a charmap but an encoding table. + * The driver is responsible for making up charmap objects + * corresponding to these tables. + */ + typedef struct CID_CharMapRec_* CID_CharMap; + + + /************************************************************************** + * + * HERE BEGINS THE TYPE 1 SPECIFIC STUFF + * + */ + + + typedef struct CID_SizeRec_ + { + FT_SizeRec root; + FT_Bool valid; + + } CID_SizeRec; + + + typedef struct CID_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + } CID_GlyphSlotRec; + + + FT_LOCAL( void ) + cid_slot_done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + cid_slot_init( FT_GlyphSlot slot ); + + + FT_LOCAL( void ) + cid_size_done( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_init( FT_Size size ); /* CID_Size */ + + FT_LOCAL( FT_Error ) + cid_size_request( FT_Size size, /* CID_Size */ + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + cid_face_init( FT_Stream stream, + FT_Face face, /* CID_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + cid_face_done( FT_Face face ); /* CID_Face */ + + + FT_LOCAL( FT_Error ) + cid_driver_init( FT_Module driver ); + + FT_LOCAL( void ) + cid_driver_done( FT_Module driver ); + + +FT_END_HEADER + +#endif /* CIDOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidparse.c b/Dependencies/freetype/freetype/src/cid/cidparse.c new file mode 100644 index 00000000..73a3ade8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidparse.c @@ -0,0 +1,311 @@ +/**************************************************************************** + * + * cidparse.c + * + * CID-keyed Type1 parser (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#include "cidparse.h" + +#include "ciderrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cidparse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#define STARTDATA "StartData" +#define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 ) +#define SFNTS "/sfnts" +#define SFNTS_LEN ( sizeof ( SFNTS ) - 1 ) + + + FT_LOCAL_DEF( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_ULong base_offset, offset, ps_len; + FT_Byte *cur, *limit; + FT_Byte *arg1, *arg2; + + + FT_ZERO( parser ); + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + + parser->stream = stream; + + base_offset = FT_STREAM_POS(); + + /* first of all, check the font format in the header */ + if ( FT_FRAME_ENTER( 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( ft_strncmp( (char *)stream->cursor, + "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); + } + + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + + if ( !stream->read ) { + /* just parse memory-based streams */ + offset = stream->size; + } + else + { + /* Find the last `StartData` or `/sfnts`. The parser requires */ + /* contiguous memory; attempt to pin as little as necessary. */ + + /* + * The algorithm is as follows (omitting the case with less than 256 + * bytes to fill for simplicity). + * + * 1. Fill the buffer with 256 + STARTDATA_LEN bytes. + * + * 2. Search for the STARTDATA and SFNTS strings at positions + * buffer[0], buffer[1], ..., + * buffer[255 + STARTDATA_LEN - SFNTS_LEN]. + * + * 3. Move the last STARTDATA_LEN bytes to buffer[0]. + * + * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN. + * + * 5. Repeat with step 2. + * + */ + FT_Byte buffer[256 + STARTDATA_LEN + 1]; + + /* values for the first loop */ + FT_ULong read_len = 256 + STARTDATA_LEN; + FT_ULong read_offset = 0; + FT_Byte* p = buffer; + + + offset = 0; + while ( 1 ) + { + FT_ULong stream_len; + + + stream_len = stream->size - FT_STREAM_POS(); + + read_len = FT_MIN( read_len, stream_len ); + if ( read_len && FT_STREAM_READ( p, read_len ) ) + goto Exit; + + /* ensure that we do not compare with data beyond the buffer */ + p[read_len] = '\0'; + + limit = p + read_len - SFNTS_LEN; + + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && + ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) + { + /* save offset of binary data after `StartData' */ + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; + } + else if ( p[1] == 's' && + ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) + { + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; + } + } + + if ( read_offset + read_len <= STARTDATA_LEN ) + { + if ( offset ) + goto Found; + + FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_MEM_MOVE( buffer, + buffer + read_offset + read_len - STARTDATA_LEN, + STARTDATA_LEN ); + + /* values for the next loop */ + read_len = 256; + read_offset = STARTDATA_LEN; + p = buffer + read_offset; + } + } + + Found: + /* We have found an efficient range to look for the binary data or */ + /* `/sfnts' token. Now rewind and extract the frame corresponding to */ + /* this PostScript section. */ + + ps_len = offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + parser->num_dict = FT_UINT_MAX; + + /* Find the first real `StartData' or `/sfnts' -- the last one */ + /* could be in a comment or string. We also get the arguments */ + /* of `StartData' to find out whether the data is represented in */ + /* binary or hex format. */ + + arg1 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg2 = parser->root.cursor; + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + + limit = parser->root.limit; + cur = parser->root.cursor; + + while ( cur <= limit - SFNTS_LEN ) + { + if ( parser->root.error ) + { + error = parser->root.error; + goto Exit; + } + + if ( cur[0] == 'S' && + cur <= limit - STARTDATA_LEN && + ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) + { + T1_TokenRec type_token; + FT_Long binary_length; + FT_ULong found_offset; + + + parser->root.cursor = arg1; + cid_parser_to_token( parser, &type_token ); + if ( type_token.limit - type_token.start == 5 && + ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 ) + { + parser->root.cursor = arg2; + binary_length = cid_parser_to_int( parser ); + if ( binary_length < 0 ) + { + FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); + error = FT_THROW( Invalid_File_Format ); + } + else + parser->binary_length = (FT_ULong)binary_length; + } + + /* set the real values for the parser, if different */ + found_offset = (FT_ULong)( cur - parser->postscript ) + + STARTDATA_LEN + 1; + if ( found_offset != offset ) + { + FT_FRAME_RELEASE( parser->postscript ); + + ps_len = found_offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = found_offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + } + goto Exit; + } + else if ( cur[1] == 's' && + ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 ) + { + FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + cid_parser_skip_PS_token( parser ); + cid_parser_skip_spaces ( parser ); + arg1 = arg2; + arg2 = cur; + cur = parser->root.cursor; + } + + FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" )); + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + +#undef STARTDATA +#undef STARTDATA_LEN +#undef SFNTS +#undef SFNTS_LEN + + + FT_LOCAL_DEF( void ) + cid_parser_done( CID_Parser* parser ) + { + /* always free the private dictionary */ + if ( parser->postscript ) + { + FT_Stream stream = parser->stream; + + + FT_FRAME_RELEASE( parser->postscript ); + } + parser->root.funcs.done( &parser->root ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidparse.h b/Dependencies/freetype/freetype/src/cid/cidparse.h new file mode 100644 index 00000000..0f5baddc --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidparse.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * cidparse.h + * + * CID-keyed Type1 parser (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDPARSE_H_ +#define CIDPARSE_H_ + + +#include +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Struct: + * CID_Parser + * + * @Description: + * A CID_Parser is an object used to parse a Type 1 fonts very + * quickly. + * + * @Fields: + * root :: + * The root PS_ParserRec fields. + * + * stream :: + * The current input stream. + * + * postscript :: + * A pointer to the data to be parsed. + * + * postscript_len :: + * The length of the data to be parsed. + * + * data_offset :: + * The start position of the binary data (i.e., the + * end of the data to be parsed. + * + * binary_length :: + * The length of the data after the `StartData' + * command if the data format is hexadecimal. + * + * cid :: + * A structure which holds the information about + * the current font. + * + * num_dict :: + * The number of font dictionaries. + */ + typedef struct CID_Parser_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* postscript; + FT_ULong postscript_len; + + FT_ULong data_offset; + + FT_ULong binary_length; + + CID_FaceInfo cid; + FT_UInt num_dict; + + } CID_Parser; + + + FT_LOCAL( FT_Error ) + cid_parser_new( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + cid_parser_done( CID_Parser* parser ); + + + /************************************************************************** + * + * PARSING ROUTINES + * + */ + +#define cid_parser_skip_spaces( p ) \ + (p)->root.funcs.skip_spaces( &(p)->root ) +#define cid_parser_skip_PS_token( p ) \ + (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root ) +#define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define cid_parser_to_coord_array( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define cid_parser_to_fixed_array( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define cid_parser_to_token( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define cid_parser_to_token_array( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define cid_parser_load_field( p, f, o ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 ) +#define cid_parser_load_field_table( p, f, o ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 ) + + +FT_END_HEADER + +#endif /* CIDPARSE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidriver.c b/Dependencies/freetype/freetype/src/cid/cidriver.c new file mode 100644 index 00000000..4be8a5c0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidriver.c @@ -0,0 +1,274 @@ +/**************************************************************************** + * + * cidriver.c + * + * CID driver interface (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "cidriver.h" +#include "cidgload.h" +#include +#include + +#include "ciderrs.h" + +#include +#include +#include +#include +#include +#include + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ciddriver + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + cid_get_postscript_name( FT_Face face ) /* CID_Face */ + { + CID_Face cidface = (CID_Face)face; + const char* result = cidface->cid.cid_font_name; + + + if ( result && result[0] == '/' ) + result++; + + return result; + } + + + static const FT_Service_PsFontNameRec cid_service_ps_name = + { + (FT_PsName_GetFunc)cid_get_postscript_name /* get_ps_font_name */ + }; + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_info( FT_Face face, /* CID_Face */ + PS_FontInfoRec* afont_info ) + { + *afont_info = ( (CID_Face)face )->cid.font_info; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_extra( FT_Face face, /* CID_Face */ + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ( (CID_Face)face )->font_extra; + + return FT_Err_Ok; + } + + + static const FT_Service_PsInfoRec cid_service_ps_info = + { + cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + /* unsupported with CID fonts */ + NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + /* unsupported */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ + /* not implemented */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ + }; + + + /* + * CID INFO SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + cid_get_ros( FT_Face face, /* CID_Face */ + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + CID_Face cidface = (CID_Face)face; + CID_FaceInfo cid = &cidface->cid; + + + if ( registry ) + *registry = cid->registry; + + if ( ordering ) + *ordering = cid->ordering; + + if ( supplement ) + *supplement = cid->supplement; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_get_is_cid( FT_Face face, /* CID_Face */ + FT_Bool *is_cid ) + { + FT_Error error = FT_Err_Ok; + FT_UNUSED( face ); + + + /* + * XXX: If the ROS is Adobe-Identity-H or -V, + * the font has no reliable information about + * its glyph collection. Should we not set + * *is_cid in such cases? + */ + if ( is_cid ) + *is_cid = 1; + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */ + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = FT_Err_Ok; + CID_Face cidface = (CID_Face)face; + + + /* + * Currently, FreeType does not support incrementally-defined, CID-keyed + * fonts that store the glyph description data in a `/GlyphDirectory` + * array or dictionary. Fonts loaded by the incremental loading feature + * are thus not handled here. + */ + error = cid_compute_fd_and_offsets( cidface, glyph_index, + NULL, NULL, NULL ); + if ( error ) + *cid = 0; + else + *cid = glyph_index; + + return error; + } + + + static const FT_Service_CIDRec cid_service_cid_info = + { + cid_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cid_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cid_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ + }; + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + cid_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec cid_services[] = + { + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CID }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cid_service_ps_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &cid_service_ps_info }, + { FT_SERVICE_ID_CID, &cid_service_cid_info }, + { FT_SERVICE_ID_PROPERTIES, &cid_service_properties }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + cid_get_interface( FT_Module module, + const char* cid_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( cid_services, cid_interface ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1cid_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( PS_DriverRec ), + + "t1cid", /* module name */ + 0x10000L, /* version 1.0 of driver */ + 0x20000L, /* requires FreeType 2.0 */ + + NULL, /* module-specific interface */ + + cid_driver_init, /* FT_Module_Constructor module_init */ + cid_driver_done, /* FT_Module_Destructor module_done */ + cid_get_interface /* FT_Module_Requester get_interface */ + }, + + sizeof ( CID_FaceRec ), + sizeof ( CID_SizeRec ), + sizeof ( CID_GlyphSlotRec ), + + cid_face_init, /* FT_Face_InitFunc init_face */ + cid_face_done, /* FT_Face_DoneFunc done_face */ + cid_size_init, /* FT_Size_InitFunc init_size */ + cid_size_done, /* FT_Size_DoneFunc done_size */ + cid_slot_init, /* FT_Slot_InitFunc init_slot */ + cid_slot_done, /* FT_Slot_DoneFunc done_slot */ + + cid_slot_load_glyph, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + cid_size_request, /* FT_Size_RequestFunc request_size */ + NULL /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidriver.h b/Dependencies/freetype/freetype/src/cid/cidriver.h new file mode 100644 index 00000000..7ddce431 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidriver.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * cidriver.h + * + * High-level CID driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CIDRIVER_H_ +#define CIDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_CALLBACK_TABLE + const FT_Driver_ClassRec t1cid_driver_class; + +FT_END_HEADER + +#endif /* CIDRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/cidtoken.h b/Dependencies/freetype/freetype/src/cid/cidtoken.h new file mode 100644 index 00000000..160897d1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/cidtoken.h @@ -0,0 +1,115 @@ +/**************************************************************************** + * + * cidtoken.h + * + * CID token definitions (specification only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_CID_INFO + + T1_FIELD_KEY ( "CIDFontName", cid_font_name, 0 ) + T1_FIELD_FIXED ( "CIDFontVersion", cid_version, 0 ) + T1_FIELD_NUM ( "CIDFontType", cid_font_type, 0 ) + T1_FIELD_STRING ( "Registry", registry, 0 ) + T1_FIELD_STRING ( "Ordering", ordering, 0 ) + T1_FIELD_NUM ( "Supplement", supplement, 0 ) + T1_FIELD_NUM ( "UIDBase", uid_base, 0 ) + + T1_FIELD_NUM_TABLE( "XUID", xuid, 16, 0 ) + + T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset, 0 ) + T1_FIELD_NUM ( "FDBytes", fd_bytes, 0 ) + T1_FIELD_NUM ( "GDBytes", gd_bytes, 0 ) + T1_FIELD_NUM ( "CIDCount", cid_count, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE CID_FaceDictRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset, 0 ) + T1_FIELD_NUM ( "SDBytes", sd_bytes, 0 ) + T1_FIELD_NUM ( "SubrCount", num_subrs, 0 ) + T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar, 0 ) + T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, 0 ) + T1_FIELD_NUM ( "lenIV", lenIV, 0 ) + T1_FIELD_NUM ( "LanguageGroup", language_group, 0 ) + T1_FIELD_NUM ( "password", password, 0 ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, 0 ) + T1_FIELD_NUM ( "BlueShift", blue_shift, 0 ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, 0 ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, 0 ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, 0 ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, 0 ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, 0 ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, 0 ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, 0 ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, 0 ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, 0 ) + + T1_FIELD_BOOL ( "ForceBold", force_bold, 0 ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, 0 ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/cid/type1cid.c b/Dependencies/freetype/freetype/src/cid/type1cid.c new file mode 100644 index 00000000..890a3ac5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/cid/type1cid.c @@ -0,0 +1,28 @@ +/**************************************************************************** + * + * type1cid.c + * + * FreeType OpenType driver component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "cidgload.c" +#include "cidload.c" +#include "cidobjs.c" +#include "cidparse.c" +#include "cidriver.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/dlg/dlg.c b/Dependencies/freetype/freetype/src/dlg/dlg.c new file mode 100644 index 00000000..0e6bc74b --- /dev/null +++ b/Dependencies/freetype/freetype/src/dlg/dlg.c @@ -0,0 +1,803 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200809L +#define _WIN32_WINNT 0x0600 + +// Needed on windows so that we can use sprintf without warning. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +const char* const dlg_reset_sequence = "\033[0m"; +const struct dlg_style dlg_default_output_styles[] = { + {dlg_text_style_italic, dlg_color_green, dlg_color_none}, + {dlg_text_style_dim, dlg_color_gray, dlg_color_none}, + {dlg_text_style_none, dlg_color_cyan, dlg_color_none}, + {dlg_text_style_none, dlg_color_yellow, dlg_color_none}, + {dlg_text_style_none, dlg_color_red, dlg_color_none}, + {dlg_text_style_bold, dlg_color_red, dlg_color_none} +}; + +static void* xalloc(size_t size) { + void* ret = calloc(size, 1); + if(!ret) fprintf(stderr, "dlg: calloc returned NULL, probably crashing (size: %zu)\n", size); + return ret; +} + +static void* xrealloc(void* ptr, size_t size) { + void* ret = realloc(ptr, size); + if(!ret) fprintf(stderr, "dlg: realloc returned NULL, probably crashing (size: %zu)\n", size); + return ret; +} + +struct dlg_tag_func_pair { + const char* tag; + const char* func; +}; + +struct dlg_data { + const char** tags; // vec + struct dlg_tag_func_pair* pairs; // vec + char* buffer; + size_t buffer_size; +}; + +static dlg_handler g_handler = dlg_default_output; +static void* g_data = NULL; + +static void dlg_free_data(void* data); +static struct dlg_data* dlg_create_data(void); + +// platform-specific +#if defined(__unix__) || defined(__unix) || defined(__linux__) || defined(__APPLE__) || defined(__MACH__) + #define DLG_OS_UNIX + #include + #include + #include + + static pthread_key_t dlg_data_key; + + static void dlg_main_cleanup(void) { + void* data = pthread_getspecific(dlg_data_key); + if(data) { + dlg_free_data(data); + pthread_setspecific(dlg_data_key, NULL); + } + } + + static void init_data_key(void) { + pthread_key_create(&dlg_data_key, dlg_free_data); + atexit(dlg_main_cleanup); + } + + static struct dlg_data* dlg_data(void) { + static pthread_once_t key_once = PTHREAD_ONCE_INIT; + pthread_once(&key_once, init_data_key); + + void* data = pthread_getspecific(dlg_data_key); + if(!data) { + data = dlg_create_data(); + pthread_setspecific(dlg_data_key, data); + } + + return (struct dlg_data*) data; + } + + static void lock_file(FILE* file) { + flockfile(file); + } + + static void unlock_file(FILE* file) { + funlockfile(file); + } + + bool dlg_is_tty(FILE* stream) { + return isatty(fileno(stream)); + } + + static unsigned get_msecs(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec; + } + +// platform switch -- end unix +#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) + #define DLG_OS_WIN + #define WIN32_LEAN_AND_MEAN + #define DEFINE_CONSOLEV2_PROPERTIES + #include + #include + + // thanks for nothing, microsoft + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #endif + + // the max buffer size we will convert on the stack + #define DLG_MAX_STACK_BUF_SIZE 1024 + + static void WINAPI dlg_fls_destructor(void* data) { + dlg_free_data(data); + } + + // TODO: error handling + static BOOL CALLBACK dlg_init_fls(PINIT_ONCE io, void* param, void** lpContext) { + (void) io; + (void) param; + **((DWORD**) lpContext) = FlsAlloc(dlg_fls_destructor); + return true; + } + + static struct dlg_data* dlg_data(void) { + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static DWORD fls = 0; + void* flsp = (void*) &fls; + InitOnceExecuteOnce(&init_once, dlg_init_fls, NULL, &flsp); + void* data = FlsGetValue(fls); + if(!data) { + data = dlg_create_data(); + FlsSetValue(fls, data); + } + + return (struct dlg_data*) data; + } + + static void lock_file(FILE* file) { + _lock_file(file); + } + + static void unlock_file(FILE* file) { + _unlock_file(file); + } + + bool dlg_is_tty(FILE* stream) { + return _isatty(_fileno(stream)); + } + +#ifdef DLG_WIN_CONSOLE + static bool init_ansi_console(void) { + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE err = GetStdHandle(STD_ERROR_HANDLE); + if(out == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE) + return false; + + DWORD outMode, errMode; + if(!GetConsoleMode(out, &outMode) || !GetConsoleMode(err, &errMode)) + return false; + + outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + errMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if(!SetConsoleMode(out, outMode) || !SetConsoleMode(out, errMode)) + return false; + + return true; + } + + static bool win_write_heap(void* handle, int needed, const char* format, va_list args) { + char* buf1 = xalloc(3 * needed + 3 + (needed % 2)); + wchar_t* buf2 = (wchar_t*) (buf1 + needed + 1 + (needed % 2)); + vsnprintf(buf1, needed + 1, format, args); + needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1); + bool ret = (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0); + free(buf1); + return ret; + } + + static bool win_write_stack(void* handle, int needed, const char* format, va_list args) { + char buf1[DLG_MAX_STACK_BUF_SIZE]; + wchar_t buf2[DLG_MAX_STACK_BUF_SIZE]; + vsnprintf(buf1, needed + 1, format, args); + needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1); + return (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0); + } +#endif // DLG_WIN_CONSOLE + + static unsigned get_msecs() { + SYSTEMTIME st; + GetSystemTime(&st); + return st.wMilliseconds; + } + +#else // platform switch -- end windows + #error Cannot determine platform (needed for color and utf-8 and stuff) +#endif + +// general +void dlg_escape_sequence(struct dlg_style style, char buf[12]) { + int nums[3]; + unsigned int count = 0; + + if(style.fg != dlg_color_none) { + nums[count++] = style.fg + 30; + } + + if(style.bg != dlg_color_none) { + nums[count++] = style.fg + 40; + } + + if(style.style != dlg_text_style_none) { + nums[count++] = style.style; + } + + switch(count) { + case 1: snprintf(buf, 12, "\033[%dm", nums[0]); break; + case 2: snprintf(buf, 12, "\033[%d;%dm", nums[0], nums[1]); break; + case 3: snprintf(buf, 12, "\033[%d;%d;%dm", nums[0], nums[1], nums[2]); break; + default: buf[0] = '\0'; break; + } +} + +int dlg_vfprintf(FILE* stream, const char* format, va_list args) { +#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE) + void* handle = NULL; + if(stream == stdout) { + handle = GetStdHandle(STD_OUTPUT_HANDLE); + } else if(stream == stderr) { + handle = GetStdHandle(STD_ERROR_HANDLE); + } + + if(handle) { + va_list args_copy; + va_copy(args_copy, args); + int needed = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + + if(needed < 0) { + return needed; + } + + // We don't allocate too much on the stack + // but we also don't want to call alloc every logging call + // or use another cached buffer + if(needed >= DLG_MAX_STACK_BUF_SIZE) { + if(win_write_heap(handle, needed, format, args)) { + return needed; + } + } else { + if(win_write_stack(handle, needed, format, args)) { + return needed; + } + } + } +#endif + + return vfprintf(stream, format, args); +} + +int dlg_fprintf(FILE* stream, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = dlg_vfprintf(stream, format, args); + va_end(args); + return ret; +} + +int dlg_styled_fprintf(FILE* stream, struct dlg_style style, const char* format, ...) { + char buf[12]; + dlg_escape_sequence(style, buf); + + fprintf(stream, "%s", buf); + va_list args; + va_start(args, format); + int ret = dlg_vfprintf(stream, format, args); + va_end(args); + fprintf(stream, "%s", dlg_reset_sequence); + return ret; +} + +void dlg_generic_output(dlg_generic_output_handler output, void* data, + unsigned int features, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + // We never print any dynamic content below so we can be sure at compile + // time that a buffer of size 64 is large enough. + char format_buf[64]; + char* format = format_buf; + + if(features & dlg_output_style) { + format += sprintf(format, "%%s"); + } + + if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) { + format += sprintf(format, "["); + } + + bool first_meta = true; + if(features & dlg_output_time) { + format += sprintf(format, "%%h"); + first_meta = false; + } + + if(features & dlg_output_time_msecs) { + if(!first_meta) { + format += sprintf(format, ":"); + } + + format += sprintf(format, "%%m"); + first_meta = false; + } + + if(features & dlg_output_file_line) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "%%o"); + first_meta = false; + } + + if(features & dlg_output_func) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "%%f"); + first_meta = false; + } + + if(features & dlg_output_tags) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "{%%t}"); + first_meta = false; + } + + if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) { + format += sprintf(format, "] "); + } + + format += sprintf(format, "%%c"); + + if(features & dlg_output_newline) { + format += sprintf(format, "\n"); + } + + *format = '\0'; + dlg_generic_outputf(output, data, format_buf, origin, string, styles); +} + +void dlg_generic_outputf(dlg_generic_output_handler output, void* data, + const char* format_string, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + bool reset_style = false; + for(const char* it = format_string; *it; it++) { + if(*it != '%') { + output(data, "%c", *it); + continue; + } + + char next = *(it + 1); // must be valid since *it is not '\0' + if(next == 'h') { + time_t t = time(NULL); + struct tm tm_info; + + #ifdef DLG_OS_WIN + if(localtime_s(&tm_info, &t)) { + #else + if(!localtime_r(&t, &tm_info)) { + #endif + output(data, ""); + } else { + char timebuf[32]; + strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm_info); + output(data, "%s", timebuf); + } + it++; + } else if(next == 'm') { + output(data, "%06d", get_msecs()); + it++; + } else if(next == 't') { + bool first_tag = true; + for(const char** tags = origin->tags; *tags; ++tags) { + if(!first_tag) { + output(data, ", "); + } + + output(data, "%s", *tags); + first_tag = false; + } + ++it; + } else if(next == 'f') { + output(data, "%s", origin->func); + ++it; + } else if(next == 'o') { + output(data, "%s:%u", origin->file, origin->line); + ++it; + } else if(next == 's') { + char buf[12]; + dlg_escape_sequence(styles[origin->level], buf); + output(data, "%s", buf); + reset_style = true; + ++it; + } else if(next == 'r') { + output(data, "%s", dlg_reset_sequence); + reset_style = false; + ++it; + } else if(next == 'c') { + if(origin->expr && string) { + output(data, "assertion '%s' failed: '%s'", origin->expr, string); + } else if(origin->expr) { + output(data, "assertion '%s' failed", origin->expr); + } else if(string) { + output(data, "%s", string); + } + ++it; + } else if(next == '%') { + output(data, "%s", "%"); + ++it; + } else { + // in this case it's a '%' without known format specifier following + output(data, "%s", "%"); + } + } + + if(reset_style) { + output(data, "%s", dlg_reset_sequence); + } +} + +struct buf { + char* buf; + size_t* size; +}; + +static void print_size(void* size, const char* format, ...) { + va_list args; + va_start(args, format); + + int ret = vsnprintf(NULL, 0, format, args); + va_end(args); + + if(ret > 0) { + *((size_t*) size) += ret; + } +} + +static void print_buf(void* dbuf, const char* format, ...) { + struct buf* buf = (struct buf*) dbuf; + va_list args; + va_start(args, format); + + int printed = vsnprintf(buf->buf, *buf->size, format, args); + va_end(args); + + if(printed > 0) { + *buf->size -= printed; + buf->buf += printed; + } +} + +void dlg_generic_output_buf(char* buf, size_t* size, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + if(buf) { + struct buf mbuf; + mbuf.buf = buf; + mbuf.size = size; + dlg_generic_output(print_buf, &mbuf, features, origin, string, styles); + } else { + *size = 0; + dlg_generic_output(print_size, size, features, origin, string, styles); + } +} + +void dlg_generic_outputf_buf(char* buf, size_t* size, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + if(buf) { + struct buf mbuf; + mbuf.buf = buf; + mbuf.size = size; + dlg_generic_outputf(print_buf, &mbuf, format_string, origin, string, styles); + } else { + *size = 0; + dlg_generic_outputf(print_size, size, format_string, origin, string, styles); + } +} + +static void print_stream(void* stream, const char* format, ...) { + va_list args; + va_start(args, format); + dlg_vfprintf((FILE*) stream, format, args); + va_end(args); +} + +void dlg_generic_output_stream(FILE* stream, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + stream = stream ? stream : stdout; + if(features & dlg_output_threadsafe) { + lock_file(stream); + } + + dlg_generic_output(print_stream, stream, features, origin, string, styles); + if(features & dlg_output_threadsafe) { + unlock_file(stream); + } +} + +void dlg_generic_outputf_stream(FILE* stream, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6], bool lock_stream) { + stream = stream ? stream : stdout; + if(lock_stream) { + lock_file(stream); + } + + dlg_generic_outputf(print_stream, stream, format_string, origin, string, styles); + if(lock_stream) { + unlock_file(stream); + } +} + +void dlg_default_output(const struct dlg_origin* origin, const char* string, void* data) { + FILE* stream = data ? (FILE*) data : stdout; + unsigned int features = dlg_output_file_line | + dlg_output_newline | + dlg_output_threadsafe; + +#ifdef DLG_DEFAULT_OUTPUT_ALWAYS_COLOR + dlg_win_init_ansi(); + features |= dlg_output_style; +#else + if(dlg_is_tty(stream) && dlg_win_init_ansi()) { + features |= dlg_output_style; + } +#endif + + dlg_generic_output_stream(stream, features, origin, string, dlg_default_output_styles); + fflush(stream); +} + +bool dlg_win_init_ansi(void) { +#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE) + // TODO: use init once + static volatile LONG status = 0; + LONG res = InterlockedCompareExchange(&status, 1, 0); + if(res == 0) { // not initialized + InterlockedExchange(&status, 3 + init_ansi_console()); + } + + while(status == 1); // currently initialized in another thread, spinlock + return (status == 4); +#else + return true; +#endif +} + +// small dynamic vec/array implementation +// Since the macros vec_init and vec_add[c]/vec_push might +// change the pointers value it must not be referenced somewhere else. +#define vec__raw(vec) (((unsigned int*) vec) - 2) + +static void* vec_do_create(unsigned int typesize, unsigned int cap, unsigned int size) { + unsigned long a = (size > cap) ? size : cap; + void* ptr = xalloc(2 * sizeof(unsigned int) + a * typesize); + unsigned int* begin = (unsigned int*) ptr; + begin[0] = size * typesize; + begin[1] = a * typesize; + return begin + 2; +} + +// NOTE: can be more efficient if we are allowed to reorder vector +static void vec_do_erase(void* vec, unsigned int pos, unsigned int size) { + unsigned int* begin = vec__raw(vec); + begin[0] -= size; + char* buf = (char*) vec; + memcpy(buf + pos, buf + pos + size, size); +} + +static void* vec_do_add(void** vec, unsigned int size) { + unsigned int* begin = vec__raw(*vec); + unsigned int needed = begin[0] + size; + if(needed >= begin[1]) { + void* ptr = xrealloc(begin, sizeof(unsigned int) * 2 + needed * 2); + begin = (unsigned int*) ptr; + begin[1] = needed * 2; + (*vec) = begin + 2; + } + + void* ptr = ((char*) (*vec)) + begin[0]; + begin[0] += size; + return ptr; +} + +#define vec_create(type, size) (type*) vec_do_create(sizeof(type), size * 2, size) +#define vec_create_reserve(type, size, capacity) (type*) vec_do_create(sizeof(type), capcity, size) +#define vec_init(array, size) array = vec_do_create(sizeof(*array), size * 2, size) +#define vec_init_reserve(array, size, capacity) *((void**) &array) = vec_do_create(sizeof(*array), capacity, size) +#define vec_free(vec) (free((vec) ? vec__raw(vec) : NULL), vec = NULL) +#define vec_erase_range(vec, pos, count) vec_do_erase(vec, pos * sizeof(*vec), count * sizeof(*vec)) +#define vec_erase(vec, pos) vec_do_erase(vec, pos * sizeof(*vec), sizeof(*vec)) +#define vec_size(vec) (vec__raw(vec)[0] / sizeof(*vec)) +#define vec_capacity(vec) (vec_raw(vec)[1] / sizeof(*vec)) +#define vec_add(vec) vec_do_add((void**) &vec, sizeof(*vec)) +#define vec_addc(vec, count) (vec_do_add((void**) &vec, sizeof(*vec) * count)) +#define vec_push(vec, value) (vec_do_add((void**) &vec, sizeof(*vec)), vec_last(vec) = (value)) +#define vec_pop(vec) (vec__raw(vec)[0] -= sizeof(*vec)) +#define vec_popc(vec, count) (vec__raw(vec)[0] -= sizeof(*vec) * count) +#define vec_clear(vec) (vec__raw(vec)[0] = 0) +#define vec_last(vec) (vec[vec_size(vec) - 1]) + +static struct dlg_data* dlg_create_data(void) { + struct dlg_data* data = (struct dlg_data*) xalloc(sizeof(struct dlg_data)); + vec_init_reserve(data->tags, 0, 20); + vec_init_reserve(data->pairs, 0, 20); + data->buffer_size = 100; + data->buffer = (char*) xalloc(data->buffer_size); + return data; +} + +static void dlg_free_data(void* ddata) { + struct dlg_data* data = (struct dlg_data*) ddata; + if(data) { + vec_free(data->pairs); + vec_free(data->tags); + free(data->buffer); + free(data); + } +} + +void dlg_add_tag(const char* tag, const char* func) { + struct dlg_data* data = dlg_data(); + struct dlg_tag_func_pair* pair = + (struct dlg_tag_func_pair*) vec_add(data->pairs); + pair->tag = tag; + pair->func = func; +} + +bool dlg_remove_tag(const char* tag, const char* func) { + struct dlg_data* data = dlg_data(); + for(unsigned int i = 0; i < vec_size(data->pairs); ++i) { + if(data->pairs[i].func == func && data->pairs[i].tag == tag) { + vec_erase(data->pairs, i); + return true; + } + } + + return false; +} + +char** dlg_thread_buffer(size_t** size) { + struct dlg_data* data = dlg_data(); + if(size) { + *size = &data->buffer_size; + } + return &data->buffer; +} + +void dlg_set_handler(dlg_handler handler, void* data) { + g_handler = handler; + g_data = data; +} + +dlg_handler dlg_get_handler(void** data) { + *data = g_data; + return g_handler; +} + +const char* dlg__printf_format(const char* str, ...) { + va_list vlist; + va_start(vlist, str); + + va_list vlistcopy; + va_copy(vlistcopy, vlist); + int needed = vsnprintf(NULL, 0, str, vlist); + if(needed < 0) { + printf("dlg__printf_format: invalid format given\n"); + va_end(vlist); + va_end(vlistcopy); + return NULL; + } + + va_end(vlist); + + size_t* buf_size; + char** buf = dlg_thread_buffer(&buf_size); + if(*buf_size <= (unsigned int) needed) { + *buf_size = (needed + 1) * 2; + *buf = (char*) xrealloc(*buf, *buf_size); + } + + vsnprintf(*buf, *buf_size, str, vlistcopy); + va_end(vlistcopy); + + return *buf; +} + +void dlg__do_log(enum dlg_level lvl, const char* const* tags, const char* file, int line, + const char* func, const char* string, const char* expr) { + struct dlg_data* data = dlg_data(); + unsigned int tag_count = 0; + + // push default tags + while(tags[tag_count]) { + vec_push(data->tags, tags[tag_count++]); + } + + // push current global tags + for(size_t i = 0; i < vec_size(data->pairs); ++i) { + const struct dlg_tag_func_pair pair = data->pairs[i]; + if(pair.func == NULL || !strcmp(pair.func, func)) { + vec_push(data->tags, pair.tag); + } + } + + // push call-specific tags, skip first terminating NULL + ++tag_count; + while(tags[tag_count]) { + vec_push(data->tags, tags[tag_count++]); + } + + vec_push(data->tags, NULL); // terminating NULL + struct dlg_origin origin; + origin.level = lvl; + origin.file = file; + origin.line = line; + origin.func = func; + origin.expr = expr; + origin.tags = data->tags; + + g_handler(&origin, string, g_data); + vec_clear(data->tags); +} + +#ifdef _MSC_VER +// shitty msvc compatbility +// meson gives us sane paths (separated by '/') while on MSVC, +// __FILE__ contains a '\\' separator. +static bool path_same(char a, char b) { + return (a == b) || + (a == '/' && b == '\\') || + (a == '\\' && b == '/'); +} +#else + +static inline bool path_same(char a, char b) { + return a == b; +} + +#endif + +const char* dlg__strip_root_path(const char* file, const char* base) { + if(!file) { + return NULL; + } + + const char* saved = file; + if(*file == '.') { // relative path detected + while(*(++file) == '.' || *file == '/' || *file == '\\'); + if(*file == '\0') { // weird case: purely relative path without file + return saved; + } + + return file; + } + + // strip base from file if it is given + if(base) { + char fn = *file; + char bn = *base; + while(bn != '\0' && path_same(fn, bn)) { + fn = *(++file); + bn = *(++base); + } + + if(fn == '\0' || bn != '\0') { // weird case: base isn't prefix of file + return saved; + } + } + + return file; +} diff --git a/Dependencies/freetype/freetype/src/dlg/dlgwrap.c b/Dependencies/freetype/freetype/src/dlg/dlgwrap.c new file mode 100644 index 00000000..e6053cd5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/dlg/dlgwrap.c @@ -0,0 +1,32 @@ +/**************************************************************************** + * + * dlgwrap.c + * + * Wrapper file for the 'dlg' library (body only) + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include FT_CONFIG_OPTIONS_H + + +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include "dlg.c" +#else + /* ANSI C doesn't like empty source files */ + typedef int dlg_dummy_; +#endif + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/README b/Dependencies/freetype/freetype/src/gxvalid/README new file mode 100644 index 00000000..efd792c9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/README @@ -0,0 +1,532 @@ +gxvalid: TrueType GX validator +============================== + + +1. What is this +--------------- + + `gxvalid' is a module to validate TrueType GX tables: a collection of + additional tables in TrueType font which are used by `QuickDraw GX + Text', Apple Advanced Typography (AAT). In addition, gxvalid can + validates `kern' tables which have been extended for AAT. Like the + otvalid module, gxvalid uses FreeType 2's validator framework + (ftvalid). + + You can link gxvalid with your program; before running your own layout + engine, gxvalid validates a font file. As the result, you can remove + error-checking code from the layout engine. It is also possible to + use gxvalid as a stand-alone font validator; the `ftvalid' test + program included in the ft2demo bundle calls gxvalid internally. + A stand-alone font validator may be useful for font developers. + + This documents documents the following issues. + + - supported TrueType GX tables + - fundamental validation limitations + - permissive error handling of broken GX tables + - `kern' table issue. + + +2. Supported tables +------------------- + + The following GX tables are currently supported. + + bsln + feat + just + kern(*) + lcar + mort + morx + opbd + prop + trak + + The following GX tables are currently unsupported. + + cvar + fdsc + fmtx + fvar + gvar + Zapf + + The following GX tables won't be supported. + + acnt(**) + hsty(***) + + The following undocumented tables in TrueType fonts designed for Apple + platform aren't handled either. + + addg + CVTM + TPNM + umif + + + *) The `kern' validator handles both the classic and the new kern + formats; the former is supported on both Microsoft and Apple + platforms, while the latter is supported on Apple platforms. + + **) `acnt' tables are not supported by currently available Apple font + tools. + + ***) There is one more Apple extension, `hsty', but it is for + Newton-OS, not GX (Newton-OS is a platform by Apple, but it can + use sfnt- housed bitmap fonts only). Therefore, it should be + excluded from `Apple platform' in the context of TrueType. + gxvalid ignores it as Apple font tools do so. + + + We have checked 183 fonts bundled with MacOS 9.1, MacOS 9.2, MacOS + 10.0, MacOS X 10.1, MSIE for MacOS, and AppleWorks 6.0. In addition, + we have checked 67 Dynalab fonts (designed for MacOS) and 189 Ricoh + fonts (designed for Windows and MacOS dual platforms). The number of + fonts including TrueType GX tables are as follows. + + bsln: 76 + feat: 191 + just: 84 + kern: 59 + lcar: 4 + mort: 326 + morx: 19 + opbd: 4 + prop: 114 + trak: 16 + + Dynalab and Ricoh fonts don't have GX tables except of `feat' and + `mort'. + + +3. Fundamental validation limitations +------------------------------------- + + TrueType GX provides layout information to libraries for font + rasterizers and text layout. gxvalid can check whether the layout + data in a font is conformant to the TrueType GX format specified by + Apple. But gxvalid cannot check a how QuickDraw GX/AAT renderer uses + the stored information. + + 3-1. Validation of State Machine activity + ----------------------------------------- + + QuickDraw GX/AAT uses a `State Machine' to provide `stateful' layout + features, and TrueType GX stores the state transition diagram of + this `State Machine' in a `StateTable' data structure. While the + State Machine receives a series of glyph IDs, the State Machine + starts with `start of text' state, walks around various states and + generates various layout information to the renderer, and finally + reaches the `end of text' state. + + gxvalid can check essential errors like: + + - possibility of state transitions to undefined states + - existence of glyph IDs that the State Machine doesn't know how + to handle + - the State Machine cannot compute the layout information from + given diagram + + These errors can be checked within finite steps, and without the + State Machine itself, because these are `expression' errors of state + transition diagram. + + There is no limitation about how long the State Machine walks + around, so validation of the algorithm in the state transition + diagram requires infinite steps, even if we had a State Machine in + gxvalid. Therefore, the following errors and problems cannot be + checked. + + - existence of states which the State Machine never transits to + - the possibility that the State Machine never reaches `end of + text' + - the possibility of stack underflow/overflow in the State Machine + (in ligature and contextual glyph substitutions, the State + Machine can store 16 glyphs onto its stack) + + In addition, gxvalid doesn't check `temporary glyph IDs' used in the + chained State Machines (in `mort' and `morx' tables). If a layout + feature is implemented by a single State Machine, a glyph ID + converted by the State Machine is passed to the glyph renderer, thus + it should not point to an undefined glyph ID. But if a layout + feature is implemented by chained State Machines, a component State + Machine (if it is not the final one) is permitted to generate + undefined glyph IDs for temporary use, because it is handled by next + component State Machine and not by the glyph renderer. To validate + such temporary glyph IDs, gxvalid must stack all undefined glyph IDs + which can occur in the output of the previous State Machine and + search them in the `ClassTable' structure of the current State + Machine. It is too complex to list all possible glyph IDs from the + StateTable, especially from a ligature substitution table. + + 3-2. Validation of relationship between multiple layout features + ---------------------------------------------------------------- + + gxvalid does not validate the relationship between multiple layout + features at all. + + If multiple layout features are defined in TrueType GX tables, + possible interactions, overrides, and conflicts between layout + features are implicitly given in the font too. For example, there + are several predefined spacing control features: + + - Text Spacing (Proportional/Monospace/Half-width/Normal) + - Number Spacing (Monospaced-numbers/Proportional-numbers) + - Kana Spacing (Full-width/Proportional) + - Ideographic Spacing (Full-width/Proportional) + - CJK Roman Spacing (Half-width/Proportional/Default-roman + /Full-width-roman/Proportional) + + If all layout features are independently managed, we can activate + inconsistent typographic rules like `Text Spacing=Monospace' and + `Ideographic Spacing=Proportional' at the same time. + + The combinations of layout features is managed by a 32bit integer + (one bit each for selector setting), so we can define relationships + between up to 32 features, theoretically. But if one feature + setting affects another feature setting, we need typographic + priority rules to validate the relationship. Unfortunately, the + TrueType GX format specification does not give such information even + for predefined features. + + +4. Permissive error handling of broken GX tables +------------------------------------------------ + + When Apple's font rendering system finds an inconsistency, like a + specification violation or an unspecified value in a TrueType GX + table, it does not always return error. In most cases, the rendering + engine silently ignores such wrong values or even whole tables. In + fact, MacOS is shipped with fonts including broken GX/AAT tables, but + no harmful effects due to `officially broken' fonts are observed by + end-users. + + gxvalid is designed to continue the validation process as long as + possible. When gxvalid find wrong values, gxvalid warns it at least, + and takes a fallback procedure if possible. The fallback procedure + depends on the debug level. + + We used the following three tools to investigate Apple's error handling. + + - FontValidator (for MacOS 8.5 - 9.2) resource fork font + - ftxvalidator (for MacOS X 10.1 -) dfont or naked-sfnt + - ftxdumperfuser (for MacOS X 10.1 -) dfont or naked-sfnt + + However, all tests were done on a PowerPC based Macintosh; at present, + we have not checked those tools on a m68k-based Macintosh. + + In total, we checked 183 fonts bundled to MacOS 9.1, MacOS 9.2, MacOS + 10.0, MacOS X 10.1, MSIE for MacOS, and AppleWorks 6.0. These fonts + are distributed officially, but many broken GX/AAT tables were found + by Apple's font tools. In the following, we list typical violation of + the GX specification, in fonts officially distributed with those Apple + systems. + + 4-1. broken BinSrchHeader (19/183) + ---------------------------------- + + `BinSrchHeader' is a header of a data array for m68k platforms to + access memory efficiently. Although there are only two independent + parameters for real (`unitSize' and `nUnits'), BinSrchHeader has + three additional parameters which can be calculated from `unitSize' + and `nUnits', for fast setup. Apple font tools ignore them + silently, so gxvalid warns if it finds and inconsistency, and always + continues validation. The additional parameters are ignored + regardless of the consistency. + + 19 fonts include such inconsistencies; all breaks are in the + BinSrchHeader structure of the `kern' table. + + 4-2. too-short LookupTable (5/183) + ---------------------------------- + + LookupTable format 0 is a simple array to get a value from a given + GID (glyph ID); the index of this array is a GID too. Therefore, + the length of the array is expected to be same as the maximum GID + value defined in the `maxp' table, but there are some fonts whose + LookupTable format 0 is too short to cover all GIDs. FontValidator + ignores this error silently, ftxvalidator and ftxdumperfuser both + warn and continue. Similar problems are found in format 3 subtables + of `kern'. gxvalid warns always and abort if the validation level + is set to FT_VALIDATE_PARANOID. + + 5 fonts include too-short kern format 0 subtables. + 1 font includes too-short kern format 3 subtable. + + 4-3. broken LookupTable format 2 (1/183) + ---------------------------------------- + + LookupTable format 2, subformat 4 covers the GID space by a + collection of segments which are specified by `firstGlyph' and + `lastGlyph'. Some fonts store `firstGlyph' and `lastGlyph' in + reverse order, so the segment specification is broken. Apple font + tools ignore this error silently; a broken segment is ignored as if + it did not exist. gxvalid warns and normalize the segment at + FT_VALIDATE_DEFAULT, or ignore the segment at FT_VALIDATE_TIGHT, or + abort at FT_VALIDATE_PARANOID. + + 1 font includes broken LookupTable format 2, in the `just' table. + + *) It seems that all fonts manufactured by ITC for AppleWorks have + this error. + + 4-4. bad bracketing in glyph property (14/183) + ---------------------------------------------- + + GX/AAT defines a `bracketing' property of the glyphs in the `prop' + table, to control layout features of strings enclosed inside and + outside of brackets. Some fonts give inappropriate bracket + properties to glyphs. Apple font tools warn about this error; + gxvalid warns too and aborts at FT_VALIDATE_PARANOID. + + 14 fonts include wrong bracket properties. + + + 4-5. invalid feature number (117/183) + ------------------------------------- + + The GX/AAT extension can include 255 different layout features, + but popular layout features are predefined (see + https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html). + Some fonts include feature numbers which are incompatible with the + predefined feature registry. + + In our survey, there are 140 fonts including `feat' table. + + a) 67 fonts use a feature number which should not be used. + b) 117 fonts set the wrong feature range (nSetting). This is mostly + found in the `mort' and `morx' tables. + + Apple font tools give no warning, although they cannot recognize + what the feature is. At FT_VALIDATE_DEFAULT, gxvalid warns but + continues in both cases (a, b). At FT_VALIDATE_TIGHT, gxvalid warns + and aborts for (a), but continues for (b). At FT_VALIDATE_PARANOID, + gxvalid warns and aborts in both cases (a, b). + + 4-6. invalid prop version (10/183) + ---------------------------------- + + As most TrueType GX tables, the `prop' table must start with a 32bit + version identifier: 0x00010000, 0x00020000 or 0x00030000. But some + fonts store nonsense binary data instead. When Apple font tools + find them, they abort the processing immediately, and the data which + follows is unhandled. gxvalid does the same. + + 10 fonts include broken `prop' version. + + All of these fonts are classic TrueType fonts for the Japanese + script, manufactured by Apple. + + 4-7. unknown resource name (2/183) + ------------------------------------ + + NOTE: THIS IS NOT A TRUETYPE GX ERROR. + + If a TrueType font is stored in the resource fork or in dfont + format, the data must be tagged as `sfnt' in the resource fork index + to invoke TrueType font handler for the data. But the TrueType font + data in `Keyboard.dfont' is tagged as `kbd', and that in + `LastResort.dfont' is tagged as `lst'. Apple font tools can detect + that the data is in TrueType format and successfully validate them. + Maybe this is possible because they are known to be dfont. The + current implementation of the resource fork driver of FreeType + cannot do that, thus gxvalid cannot validate them. + + 2 fonts use an unknown tag for the TrueType font resource. + +5. `kern' table issues +---------------------- + + In common terminology of TrueType, `kern' is classified as a basic and + platform-independent table. But there are Apple extensions of `kern', + and there is an extension which requires a GX state machine for + contextual kerning. Therefore, gxvalid includes a special validator + for `kern' tables. Unfortunately, there is no exact algorithm to + check Apple's extension, so gxvalid includes a heuristic algorithm to + find the proper validation routines for all possible data formats, + including the data format for Microsoft. By calling + classic_kern_validate() instead of gxv_validate(), you can specify the + `kern' format explicitly. However, current FreeType2 uses Microsoft + `kern' format only, others are ignored (and should be handled in a + library one level higher than FreeType). + + 5-1. History + ------------ + + The original 16bit version of `kern' was designed by Apple in the + pre-GX era, and it was also approved by Microsoft. Afterwards, + Apple designed a new 32bit version of the `kern' table. According + to the documentation, the difference between the 16bit and 32bit + version is only the size of variables in the `kern' header. In the + following, we call the original 16bit version as `classic', and + 32bit version as `new'. + + 5-2. Versions and dialects which should be differentiated + --------------------------------------------------------- + + The `kern' table consists of a table header and several subtables. + The version number which identifies a `classic' or a `new' version + is explicitly written in the table header, but there are + undocumented differences between Microsoft's and Apple's formats. + It is called a `dialect' in the following. There are three cases + which should be handled: the new Apple-dialect, the classic + Apple-dialect, and the classic Microsoft-dialect. An analysis of + the formats and the auto detection algorithm of gxvalid is described + in the following. + + 5-2-1. Version detection: classic and new kern + ---------------------------------------------- + + According to Apple TrueType specification, there are only two + differences between the classic and the new: + + - The `kern' table header starts with the version number. + The classic version starts with 0x0000 (16bit), + the new version starts with 0x00010000 (32bit). + + - In the `kern' table header, the number of subtables follows + the version number. + In the classic version, it is stored as a 16bit value. + In the new version, it is stored as a 32bit value. + + From Apple font tool's output (DumpKERN is also tested in addition + to the three Apple font tools in above), there is another + undocumented difference. In the new version, the subtable header + includes a 16bit variable named `tupleIndex' which does not exist + in the classic version. + + The new version can store all subtable formats (0, 1, 2, and 3), + but the Apple TrueType specification does not mention the subtable + formats available in the classic version. + + 5-2-2. Available subtable formats in classic version + ---------------------------------------------------- + + Although the Apple TrueType specification recommends to use the + classic version in the case if the font is designed for both the + Apple and Microsoft platforms, it does not document the available + subtable formats in the classic version. + + According to the Microsoft TrueType specification, the subtable + format assured for Windows and OS/2 support is only subtable + format 0. The Microsoft TrueType specification also describes + subtable format 2, but does not mention which platforms support + it. Subtable formats 1, 3, and higher are documented as reserved + for future use. Therefore, the classic version can store subtable + formats 0 and 2, at least. `ttfdump.exe', a font tool provided by + Microsoft, ignores the subtable format written in the subtable + header, and parses the table as if all subtables are in format 0. + + `kern' subtable format 1 uses a StateTable, so it cannot be + utilized without a GX State Machine. Therefore, it is reasonable + to assume that format 1 (and 3) were introduced after Apple had + introduced GX and moved to the new 32bit version. + + 5-2-3. Apple and Microsoft dialects + ----------------------------------- + + The `kern' subtable has a 16bit `coverage' field to describe + kerning attributes, but bit interpretations by Apple and Microsoft + are different: For example, Apple uses bits 0-7 to identify the + subtable, while Microsoft uses bits 8-15. + + In addition, due to the output of DumpKERN and FontValidator, + Apple's bit interpretations of coverage in classic and new version + are incompatible also. In summary, there are three dialects: + classic Apple dialect, classic Microsoft dialect, and new Apple + dialect. The classic Microsoft dialect and the new Apple dialect + are documented by each vendors' TrueType font specification, but + the documentation for classic Apple dialect is not available. + + For example, in the new Apple dialect, bit 15 is documented as + `set to 1 if the kerning is vertical'. On the other hand, in + classic Microsoft dialect, bit 1 is documented as `set to 1 if the + kerning is horizontal'. From the outputs of DumpKERN and + FontValidator, classic Apple dialect recognizes 15 as `set to 1 + when the kerning is horizontal'. From the results of similar + experiments, classic Apple dialect seems to be the Endian reverse + of the classic Microsoft dialect. + + As a conclusion it must be noted that no font tool can identify + classic Apple dialect or classic Microsoft dialect automatically. + + 5-2-4. gxvalid auto dialect detection algorithm + ----------------------------------------------- + + The first 16 bits of the `kern' table are enough to identify the + version: + + - if the first 16 bits are 0x0000, the `kern' table is in + classic Apple dialect or classic Microsoft dialect + - if the first 16 bits are 0x0001, and next 16 bits are 0x0000, + the kern table is in new Apple dialect. + + If the `kern' table is a classic one, the 16bit `coverage' field + is checked next. Firstly, the coverage bits are decoded for the + classic Apple dialect using the following bit masks (this is based + on DumpKERN output): + + 0x8000: 1=horizontal, 0=vertical + 0x4000: not used + 0x2000: 1=cross-stream, 0=normal + 0x1FF0: reserved + 0x000F: subtable format + + If any of reserved bits are set or the subtable bits is + interpreted as format 1 or 3, we take it as `impossible in classic + Apple dialect' and retry, using the classic Microsoft dialect. + + The most popular coverage in new Apple-dialect: 0x8000, + The most popular coverage in classic Apple-dialect: 0x0000, + The most popular coverage in classic Microsoft dialect: 0x0001. + + 5-3. Tested fonts + ----------------- + + We checked 59 fonts bundled with MacOS and 38 fonts bundled with + Windows, where all font include a `kern' table. + + - fonts bundled with MacOS + * new Apple dialect + format 0: 18 + format 2: 1 + format 3: 1 + * classic Apple dialect + format 0: 14 + * classic Microsoft dialect + format 0: 15 + + - fonts bundled with Windows + * classic Microsoft dialect + format 0: 38 + + It looks strange that classic Microsoft-dialect fonts are bundled to + MacOS: they come from MSIE for MacOS, except of MarkerFelt.dfont. + + + ACKNOWLEDGEMENT + --------------- + + Some parts of gxvalid are derived from both the `gxlayout' module and + the `otvalid' module. Development of gxlayout was supported by the + Information-technology Promotion Agency(IPA), Japan. + + The detailed analysis of undefined glyph ID utilization in `mort' and + `morx' tables is provided by George Williams. + +------------------------------------------------------------------------ + +Copyright (C) 2004-2024 by +suzuki toshiya, Masatake YAMATO, Red hat K.K., +David Turner, Robert Wilhelm, and Werner Lemberg. + +This file is part of the FreeType project, and may only be used, +modified, and distributed under the terms of the FreeType project +license, LICENSE.TXT. By continuing to use, modify, or distribute this +file you indicate that you have read the license and understand and +accept it fully. + + +--- end of README --- diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvalid.c b/Dependencies/freetype/freetype/src/gxvalid/gxvalid.c new file mode 100644 index 00000000..6694c342 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvalid.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * gxvalid.c + * + * FreeType validator for TrueTypeGX/AAT tables (body only). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "gxvbsln.c" +#include "gxvcommn.c" +#include "gxvfeat.c" +#include "gxvjust.c" +#include "gxvkern.c" +#include "gxvlcar.c" +#include "gxvmod.c" +#include "gxvmort.c" +#include "gxvmort0.c" +#include "gxvmort1.c" +#include "gxvmort2.c" +#include "gxvmort4.c" +#include "gxvmort5.c" +#include "gxvmorx.c" +#include "gxvmorx0.c" +#include "gxvmorx1.c" +#include "gxvmorx2.c" +#include "gxvmorx4.c" +#include "gxvmorx5.c" +#include "gxvopbd.c" +#include "gxvprop.c" +#include "gxvtrak.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvalid.h b/Dependencies/freetype/freetype/src/gxvalid/gxvalid.h new file mode 100644 index 00000000..4ddb625e --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvalid.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * gxvalid.h + * + * TrueTypeGX/AAT table validation (specification only). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVALID_H_ +#define GXVALID_H_ + +#include + +#include "gxverror.h" /* must come before `ftvalid.h' */ + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + + FT_LOCAL( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + FT_LOCAL( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator valid ); + + +FT_END_HEADER + + +#endif /* GXVALID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvbsln.c b/Dependencies/freetype/freetype/src/gxvalid/gxvbsln.c new file mode 100644 index 00000000..e3a922ae --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvbsln.c @@ -0,0 +1,334 @@ +/**************************************************************************** + * + * gxvbsln.c + * + * TrueTypeGX/AAT bsln table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvbsln + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_BSLN_VALUE_COUNT 32 +#define GXV_BSLN_VALUE_EMPTY 0xFFFFU + + + typedef struct GXV_bsln_DataRec_ + { + FT_Bytes ctlPoints_p; + FT_UShort defaultBaseline; + + } GXV_bsln_DataRec, *GXV_bsln_Data; + + +#define GXV_BSLN_DATA( field ) GXV_TABLE_DATA( bsln, field ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_bsln_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UShort v = value_p->u; + FT_UShort* ctlPoints; + + FT_UNUSED( glyph ); + + + GXV_NAME_ENTER( "lookup value" ); + + if ( v >= GXV_BSLN_VALUE_COUNT ) + FT_INVALID_DATA; + + ctlPoints = (FT_UShort*)GXV_BSLN_DATA( ctlPoints_p ); + if ( ctlPoints && ctlPoints[v] == GXV_BSLN_VALUE_EMPTY ) + FT_INVALID_DATA; + + GXV_EXIT; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_bsln_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range ? */ + offset = (FT_UShort)( base_value_p->u + + ( relative_gindex * sizeof ( FT_UShort ) ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + GXV_LIMIT_CHECK( 2 ); + + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_bsln_parts_fmt0_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 0" ); + + /* deltas */ + GXV_LIMIT_CHECK( 2 * GXV_BSLN_VALUE_COUNT ); + + gxvalid->table_data = NULL; /* No ctlPoints here. */ + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt1_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 1" ); + + /* deltas */ + gxv_bsln_parts_fmt0_validate( p, limit, gxvalid ); + + /* mappingData */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_bsln_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + 2 * GXV_BSLN_VALUE_COUNT, + limit, + gxvalid ); + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt2_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = tables; + + FT_UShort stdGlyph; + FT_UShort ctlPoint; + FT_Int i; + + FT_UShort defaultBaseline = GXV_BSLN_DATA( defaultBaseline ); + + + GXV_NAME_ENTER( "parts format 2" ); + + GXV_LIMIT_CHECK( 2 + ( 2 * GXV_BSLN_VALUE_COUNT ) ); + + /* stdGlyph */ + stdGlyph = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (stdGlyph = %u)\n", stdGlyph )); + + gxv_glyphid_validate( stdGlyph, gxvalid ); + + /* Record the position of ctlPoints */ + GXV_BSLN_DATA( ctlPoints_p ) = p; + + /* ctlPoints */ + for ( i = 0; i < GXV_BSLN_VALUE_COUNT; i++ ) + { + ctlPoint = FT_NEXT_USHORT( p ); + if ( ctlPoint == GXV_BSLN_VALUE_EMPTY ) + { + if ( i == defaultBaseline ) + FT_INVALID_DATA; + } + else + gxv_ctlPoint_validate( stdGlyph, ctlPoint, gxvalid ); + } + + GXV_EXIT; + } + + + static void + gxv_bsln_parts_fmt3_validate( FT_Bytes tables, + FT_Bytes limit, + GXV_Validator gxvalid) + { + FT_Bytes p = tables; + + + GXV_NAME_ENTER( "parts format 3" ); + + /* stdGlyph + ctlPoints */ + gxv_bsln_parts_fmt2_validate( p, limit, gxvalid ); + + /* mappingData */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_bsln_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit; + gxv_LookupTable_validate( p + ( 2 + 2 * GXV_BSLN_VALUE_COUNT ), + limit, + gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** bsln TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_bsln_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_bsln_DataRec bslnrec; + GXV_bsln_Data bsln = &bslnrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + FT_UShort format; + FT_UShort defaultBaseline; + + GXV_Validate_Func fmt_funcs_table [] = + { + gxv_bsln_parts_fmt0_validate, + gxv_bsln_parts_fmt1_validate, + gxv_bsln_parts_fmt2_validate, + gxv_bsln_parts_fmt3_validate, + }; + + + gxvalid->root = ftvalid; + gxvalid->table_data = bsln; + gxvalid->face = face; + + FT_TRACE3(( "validating `bsln' table\n" )); + GXV_INIT; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + defaultBaseline = FT_NEXT_USHORT( p ); + + /* only version 1.0 is defined (1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* only format 1, 2, 3 are defined (1996) */ + GXV_TRACE(( " (format = %d)\n", format )); + if ( format > 3 ) + FT_INVALID_FORMAT; + + if ( defaultBaseline > 31 ) + FT_INVALID_FORMAT; + + bsln->defaultBaseline = defaultBaseline; + + fmt_funcs_table[format]( p, limit, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* arch-tag: ebe81143-fdaa-4c68-a4d1-b57227daa3bc + (do not change this comment) */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.c b/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.c new file mode 100644 index 00000000..5f8fa115 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.c @@ -0,0 +1,1747 @@ +/**************************************************************************** + * + * gxvcommn.c + * + * TrueTypeGX/AAT common tables validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 16bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_COMPARE_DEF( int ) + gxv_compare_ushort_offset( const void* a, + const void* b ) + { + return *(FT_UShort*)a - *(FT_UShort*)b; + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator gxvalid ) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), + gxv_compare_ushort_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = (FT_UShort)( buff[j + 1] - buff[j] ); + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit offset sorter *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_COMPARE_DEF( int ) + gxv_compare_ulong_offset( const void* a, + const void* b ) + { + FT_ULong a_ = *(FT_ULong*)a; + FT_ULong b_ = *(FT_ULong*)b; + + + if ( a_ < b_ ) + return -1; + else if ( a_ > b_ ) + return 1; + else + return 0; + } + + + FT_LOCAL_DEF( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator gxvalid) + { + FT_UInt i; + + + for ( i = 0; i < nmemb; i++ ) + *(length[i]) = 0; + + for ( i = 0; i < nmemb; i++ ) + buff[i] = offset[i]; + buff[nmemb] = limit; + + ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), + gxv_compare_ulong_offset ); + + if ( buff[nmemb] > limit ) + FT_INVALID_OFFSET; + + for ( i = 0; i < nmemb; i++ ) + { + FT_UInt j; + + + for ( j = 0; j < nmemb; j++ ) + if ( buff[j] == offset[i] ) + break; + + if ( j == nmemb ) + FT_INVALID_OFFSET; + + *(length[i]) = buff[j + 1] - buff[j]; + + if ( 0 != offset[i] && 0 == *(length[i]) ) + FT_INVALID_OFFSET; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** scan value array and get min & max *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + *min = 0xFF; + *max = 0x00; + + while ( p < limit ) + { + FT_Byte val; + + + GXV_LIMIT_CHECK( 1 ); + val = FT_NEXT_BYTE( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + FT_LOCAL_DEF( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + *min = 0xFFFFU; + *max = 0x0000; + + while ( p < limit ) + { + FT_UShort val; + + + GXV_LIMIT_CHECK( 2 ); + val = FT_NEXT_USHORT( p ); + + *min = (FT_Byte)FT_MIN( *min, val ); + *max = (FT_Byte)FT_MAX( *max, val ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BINSEARCHHEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_BinSrchHeader_ + { + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + } GXV_BinSrchHeader; + + + static void + gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader* binSrchHeader, + GXV_Validator gxvalid ) + { + FT_UShort searchRange; + FT_UShort entrySelector; + FT_UShort rangeShift; + + + if ( binSrchHeader->unitSize == 0 ) + FT_INVALID_DATA; + + if ( binSrchHeader->nUnits == 0 ) + { + if ( binSrchHeader->searchRange == 0 && + binSrchHeader->entrySelector == 0 && + binSrchHeader->rangeShift == 0 ) + return; + else + FT_INVALID_DATA; + } + + for ( searchRange = 1, entrySelector = 1; + ( searchRange * 2 ) <= binSrchHeader->nUnits && + searchRange < 0x8000U; + searchRange *= 2, entrySelector++ ) + ; + + entrySelector--; + searchRange = (FT_UShort)( searchRange * binSrchHeader->unitSize ); + rangeShift = (FT_UShort)( binSrchHeader->nUnits * binSrchHeader->unitSize + - searchRange ); + + if ( searchRange != binSrchHeader->searchRange || + entrySelector != binSrchHeader->entrySelector || + rangeShift != binSrchHeader->rangeShift ) + { + GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" )); + GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + binSrchHeader->searchRange, binSrchHeader->entrySelector, + binSrchHeader->rangeShift )); + GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, " + "searchRange=%d, entrySelector=%d, " + "rangeShift=%d\n", + binSrchHeader->unitSize, binSrchHeader->nUnits, + searchRange, entrySelector, rangeShift )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + } + + + /* + * parser & validator of BinSrchHeader + * which is used in LookupTable format 2, 4, 6. + * + * Essential parameters (unitSize, nUnits) are returned by + * given pointer, others (searchRange, entrySelector, rangeShift) + * can be calculated by essential parameters, so they are just + * validated and discarded. + * + * However, wrong values in searchRange, entrySelector, rangeShift + * won't cause fatal errors, because these parameters might be + * only used in old m68k font driver in MacOS. + * -- suzuki toshiya + */ + + FT_LOCAL_DEF( void ) + gxv_BinSrchHeader_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_BinSrchHeader binSrchHeader; + + + GXV_NAME_ENTER( "BinSrchHeader validate" ); + + if ( *unitSize_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.unitSize = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.unitSize = *unitSize_p; + + if ( *nUnits_p == 0 ) + { + GXV_LIMIT_CHECK( 2 ); + binSrchHeader.nUnits = FT_NEXT_USHORT( p ); + } + else + binSrchHeader.nUnits = *nUnits_p; + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + binSrchHeader.searchRange = FT_NEXT_USHORT( p ); + binSrchHeader.entrySelector = FT_NEXT_USHORT( p ); + binSrchHeader.rangeShift = FT_NEXT_USHORT( p ); + GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits )); + + gxv_BinSrchHeader_check_consistency( &binSrchHeader, gxvalid ); + + if ( *unitSize_p == 0 ) + *unitSize_p = binSrchHeader.unitSize; + + if ( *nUnits_p == 0 ) + *nUnits_p = binSrchHeader.nUnits; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_LOOKUP_VALUE_LOAD( P, SIGNSPEC ) \ + ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) ) + + static GXV_LookupValueDesc + gxv_lookup_value_load( FT_Bytes p, + GXV_LookupValue_SignSpec signspec ) + { + GXV_LookupValueDesc v; + + + if ( signspec == GXV_LOOKUPVALUE_UNSIGNED ) + v.u = FT_NEXT_USHORT( p ); + else + v.s = FT_NEXT_SHORT( p ); + + return v; + } + + +#define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \ + FT_BEGIN_STMNT \ + if ( UNITSIZE != CORRECTSIZE ) \ + { \ + FT_ERROR(( "unitSize=%d differs from" \ + " expected unitSize=%d" \ + " in LookupTable %s\n", \ + UNITSIZE, CORRECTSIZE, FORMAT )); \ + if ( UNITSIZE != 0 && NUNITS != 0 ) \ + { \ + FT_ERROR(( " cannot validate anymore\n" )); \ + FT_INVALID_FORMAT; \ + } \ + else \ + FT_ERROR(( " forcibly continues\n" )); \ + } \ + FT_END_STMNT + + + /* ================= Simple Array Format 0 Lookup Table ================ */ + static void + gxv_LookupTable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 0" ); + + GXV_LIMIT_CHECK( 2 * gxvalid->face->num_glyphs ); + + for ( i = 0; i < gxvalid->face->num_glyphs; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + if ( p + 2 >= limit ) /* some fonts have too-short fmt0 array */ + { + GXV_TRACE(( "too short, glyphs %d - %ld are missing\n", + i, gxvalid->face->num_glyphs )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + break; + } + + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + gxvalid->lookupval_func( i, &value, gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Single Format 2 Lookup Table ============== */ + /* + * Apple spec says: + * + * To guarantee that a binary search terminates, you must include one or + * more special `end of search table' values at the end of the data to + * be searched. The number of termination values that need to be + * included is table-specific. The value that indicates binary search + * termination is 0xFFFF. + * + * The problem is that nUnits does not include this end-marker. It's + * quite difficult to discriminate whether the following 0xFFFF comes from + * the end-marker or some next data. + * + * -- suzuki toshiya + */ + static void + gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + while ( ( p + 4 ) < gxvalid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */ + p[2] != 0xFF || p[3] != 0xFF ) /* firstGlyph */ + break; + p += unitSize; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_LookupTable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort unit; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 2" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( lastGlyph, gxvalid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:" + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + + if ( gxvalid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + gxvalid->lookupval_func( gid, &value, gxvalid ); + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Array Format 4 Lookup Table =============== */ + static void + gxv_LookupTable_fmt4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort gid; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort lastGlyph; + FT_UShort firstGlyph; + GXV_LookupValueDesc base_value; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 4" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 ); + + for ( unit = 0, gid = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + lastGlyph = FT_NEXT_USHORT( p ); + firstGlyph = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( lastGlyph, gxvalid ); + + if ( lastGlyph < gid ) + { + GXV_TRACE(( "reverse ordered segment specification:" + " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n", + unit, lastGlyph, unit - 1 , gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( lastGlyph < firstGlyph ) + { + GXV_TRACE(( "reverse ordered range specification at unit %d:" + " lastGlyph %d < firstGlyph %d ", + unit, lastGlyph, firstGlyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + + if ( gxvalid->root->level == FT_VALIDATE_TIGHT ) + continue; /* ftxvalidator silently skips such an entry */ + + FT_TRACE4(( "continuing with exchanged values\n" )); + gid = firstGlyph; + firstGlyph = lastGlyph; + lastGlyph = gid; + } + + GXV_LIMIT_CHECK( 2 ); + base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED ); + + for ( gid = firstGlyph; gid <= lastGlyph; gid++ ) + { + value = gxvalid->lookupfmt4_trans( (FT_UShort)( gid - firstGlyph ), + &base_value, + limit, + gxvalid ); + + gxvalid->lookupval_func( gid, &value, gxvalid ); + } + } + + gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Segment Table Format 6 Lookup Table =============== */ + static void + gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes table, + FT_UShort unitSize, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + while ( p < gxvalid->root->limit ) + { + if ( p[0] != 0xFF || p[1] != 0xFF ) + break; + p += unitSize; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_LookupTable_fmt6_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort unit; + FT_UShort prev_glyph; + + FT_UShort unitSize; + FT_UShort nUnits; + FT_UShort glyph; + GXV_LookupValueDesc value; + + + GXV_NAME_ENTER( "LookupTable format 6" ); + + unitSize = nUnits = 0; + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, gxvalid ); + p += gxvalid->subtable_length; + + GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 ); + + for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ ) + { + GXV_LIMIT_CHECK( 2 + 2 ); + glyph = FT_NEXT_USHORT( p ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + + if ( gxv_glyphid_validate( glyph, gxvalid ) ) + GXV_TRACE(( " endmarker found within defined range" + " (entry %d < nUnits=%d)\n", + unit, nUnits )); + + if ( prev_glyph > glyph ) + { + GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n", + glyph, prev_glyph )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + prev_glyph = glyph; + + gxvalid->lookupval_func( glyph, &value, gxvalid ); + } + + gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + /* ================= Trimmed Array Format 8 Lookup Table =============== */ + static void + gxv_LookupTable_fmt8_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_LookupValueDesc value; + FT_UShort firstGlyph; + FT_UShort glyphCount; + + + GXV_NAME_ENTER( "LookupTable format 8" ); + + /* firstGlyph + glyphCount */ + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + glyphCount = FT_NEXT_USHORT( p ); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + glyphCount ), gxvalid ); + + /* valueArray */ + for ( i = 0; i < glyphCount; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + value = GXV_LOOKUP_VALUE_LOAD( p, gxvalid->lookupval_sign ); + gxvalid->lookupval_func( (FT_UShort)( firstGlyph + i ), &value, gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort format; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_LookupTable_fmt0_validate, /* 0 */ + NULL, /* 1 */ + gxv_LookupTable_fmt2_validate, /* 2 */ + NULL, /* 3 */ + gxv_LookupTable_fmt4_validate, /* 4 */ + NULL, /* 5 */ + gxv_LookupTable_fmt6_validate, /* 6 */ + NULL, /* 7 */ + gxv_LookupTable_fmt8_validate, /* 8 */ + }; + + GXV_Validate_Func func; + + + GXV_NAME_ENTER( "LookupTable" ); + + /* lookuptbl_head may be used in fmt4 transit function. */ + gxvalid->lookuptbl_head = table; + + /* format */ + GXV_LIMIT_CHECK( 2 ); + format = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (format %d)\n", format )); + + if ( format > 8 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[format]; + if ( !func ) + FT_INVALID_FORMAT; + + func( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator gxvalid ) + { + FT_Face face; + + + if ( gid == 0xFFFFU ) + { + GXV_EXIT; + return 1; + } + + face = gxvalid->face; + if ( face->num_glyphs < gid ) + { + GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %ld < %d\n", + face->num_glyphs, gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + return 0; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_UShort ctl_point, + GXV_Validator gxvalid ) + { + FT_Face face; + FT_Error error; + + FT_GlyphSlot glyph; + FT_Outline outline; + FT_UShort n_points; + + + face = gxvalid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + outline = glyph->outline; + n_points = (FT_UShort)outline.n_points; + + if ( !( ctl_point < n_points ) ) + FT_INVALID_DATA; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator gxvalid ) + { + FT_SfntName name; + FT_UInt i; + FT_UInt nnames; + + + GXV_NAME_ENTER( "sfntName" ); + + if ( name_index < min_index || max_index < name_index ) + FT_INVALID_FORMAT; + + nnames = FT_Get_Sfnt_Name_Count( gxvalid->face ); + for ( i = 0; i < nnames; i++ ) + { + if ( FT_Get_Sfnt_Name( gxvalid->face, i, &name ) != FT_Err_Ok ) + continue; + + if ( name.name_id == name_index ) + goto Out; + } + + GXV_TRACE(( " nameIndex = %d (UNTITLED)\n", name_index )); + FT_INVALID_DATA; + goto Exit; /* make compiler happy */ + + Out: + FT_TRACE1(( " nameIndex = %d (", name_index )); + GXV_TRACE_HEXDUMP_SFNTNAME( name ); + FT_TRACE1(( ")\n" )); + + Exit: + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* -------------------------- Class Table --------------------------- */ + + /* + * highestClass specifies how many classes are defined in this + * Class Subtable. Apple spec does not mention whether undefined + * holes in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used) + * are permitted. At present, holes in a defined class are not checked. + * -- suzuki toshiya + */ + + static void + gxv_ClassTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_UShort stateSize, + FT_Byte* maxClassID_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "ClassTable" ); + + *maxClassID_p = 3; /* Classes 0, 2, and 3 are predefined */ + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs )); + + if ( !nGlyphs ) + goto Out; + + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs ), gxvalid ); + + { + FT_Byte nGlyphInClass[256]; + FT_Byte classID; + FT_UShort i; + + + FT_MEM_ZERO( nGlyphInClass, 256 ); + + + for ( i = 0; i < nGlyphs; i++ ) + { + GXV_LIMIT_CHECK( 1 ); + classID = FT_NEXT_BYTE( p ); + switch ( classID ) + { + /* following classes should not appear in class array */ + case 0: /* end of text */ + case 2: /* out of bounds */ + case 3: /* end of line */ + FT_INVALID_DATA; + break; + + case 1: /* out of bounds */ + default: /* user-defined: 4 - ( stateSize - 1 ) */ + if ( classID >= stateSize ) + FT_INVALID_DATA; /* assign glyph to undefined state */ + + nGlyphInClass[classID]++; + break; + } + } + *length_p = (FT_UShort)( p - table ); + + /* scan max ClassID in use */ + for ( i = 0; i < stateSize; i++ ) + if ( ( 3 < i ) && ( nGlyphInClass[i] > 0 ) ) + *maxClassID_p = (FT_Byte)i; /* XXX: Check Range? */ + } + + Out: + GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", + stateSize, *maxClassID_p )); + GXV_EXIT; + } + + + /* --------------------------- State Array ----------------------------- */ + + static void + gxv_StateArray_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxClassID, + FT_UShort stateSize, + FT_Byte* maxState_p, + FT_Byte* maxEntry_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte clazz; + FT_Byte entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "StateArray" ); + + GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", + (int)( *length_p ), stateSize, (int)maxClassID )); + + /* + * 2 states are predefined and must be described in StateArray: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( 1 + maxClassID ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_BYTE( p ); + *maxEntry_p = (FT_Byte)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* --------------------------- Entry Table ----------------------------- */ + + static void + gxv_EntryTable_validate( FT_Bytes table, + FT_UShort* length_p, + FT_Byte maxEntry, + FT_UShort stateArray, + FT_UShort stateArray_length, + FT_Byte maxClassID, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_Byte entry; + FT_Byte state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable ); + + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_NAME_ENTER( "EntryTable" ); + + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( maxEntry + 1 ) * entrySize > *length_p ) + { + GXV_SET_ERR_IF_PARANOID( FT_INVALID_TOO_SHORT ); + + /* ftxvalidator and FontValidator both warn and continue */ + maxEntry = (FT_Byte)( *length_p / entrySize - 1 ); + GXV_TRACE(( "too large maxEntry, shrinking to %d fit EntryTable length\n", + maxEntry )); + } + + for ( entry = 0; entry <= maxEntry; entry++ ) + { + FT_UShort newState; + FT_UShort flags; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + + if ( newState < stateArray || + stateArray + stateArray_length < newState ) + { + GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", + newState )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + continue; + } + + if ( 0 != ( ( newState - stateArray ) % ( 1 + maxClassID ) ) ) + { + GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n", + newState, 1 + maxClassID )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + continue; + } + + state = (FT_Byte)( ( newState - stateArray ) / ( 1 + maxClassID ) ); + + switch ( GXV_GLYPHOFFSET_FMT( statetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + } + + if ( gxvalid->statetable.entry_validate_func ) + gxvalid->statetable.entry_validate_func( state, + flags, + &glyphOffset, + statetable_table, + statetable_limit, + gxvalid ); + } + + *length_p = (FT_UShort)( p - table ); + + GXV_EXIT; + } + + + /* =========================== State Table ============================= */ + + FT_LOCAL_DEF( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[3]; + FT_UShort* l[3]; + FT_UShort buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, gxvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_UShort stateSize; + FT_UShort classTable; /* offset to Class(Sub)Table */ + FT_UShort stateArray; /* offset to StateArray */ + FT_UShort entryTable; /* offset to EntryTable */ + + FT_UShort classTable_length; + FT_UShort stateArray_length; + FT_UShort entryTable_length; + FT_Byte maxClassID; + FT_Byte maxState; + FT_Byte maxEntry; + + GXV_StateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "StateTable" ); + + GXV_TRACE(( "StateTable header\n" )); + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + stateSize = FT_NEXT_USHORT( p ); + classTable = FT_NEXT_USHORT( p ); + stateArray = FT_NEXT_USHORT( p ); + entryTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "stateSize=0x%04x\n", stateSize )); + GXV_TRACE(( "offset to classTable=0x%04x\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable )); + + if ( stateSize > 0xFF ) + FT_INVALID_DATA; + + if ( gxvalid->statetable.optdata_load_func ) + gxvalid->statetable.optdata_load_func( p, limit, gxvalid ); + + if ( gxvalid->statetable.subtable_setup_func ) + setup_func = gxvalid->statetable.subtable_setup_func; + else + setup_func = gxv_StateTable_subtable_setup; + + setup_func( (FT_UShort)( limit - table ), + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + gxvalid ); + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( classTable != 0 ) + gxv_ClassTable_validate( table + classTable, + &classTable_length, + stateSize, + &maxClassID, + gxvalid ); + else + maxClassID = (FT_Byte)( stateSize - 1 ); + + if ( stateArray != 0 ) + gxv_StateArray_validate( table + stateArray, + &stateArray_length, + maxClassID, + stateSize, + &maxState, + &maxEntry, + gxvalid ); + else + { +#if 0 + maxState = 1; /* 0:start of text, 1:start of line are predefined */ +#endif + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_EntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray, + stateArray_length, + maxClassID, + table, + limit, + gxvalid ); + + GXV_EXIT; + } + + + /* ================= eXtended State Table (for morx) =================== */ + + FT_LOCAL_DEF( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[3]; + FT_ULong* l[3]; + FT_ULong buff[4]; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + + gxv_set_length_by_ulong_offset( o, l, buff, 3, table_size, gxvalid ); + } + + + static void + gxv_XClassTable_lookupval_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u >= gxvalid->xstatetable.nClasses ) + FT_INVALID_DATA; + if ( value_p->u > gxvalid->xstatetable.maxClassID ) + gxvalid->xstatetable.maxClassID = value_p->u; + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + static GXV_LookupValueDesc + gxv_XClassTable_lookupfmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + static void + gxv_XStateArray_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxClassID, + FT_ULong stateSize, + FT_UShort* maxState_p, + FT_UShort* maxEntry_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort clazz; + FT_UShort entry; + + FT_UNUSED( stateSize ); /* for the non-debugging case */ + + + GXV_NAME_ENTER( "XStateArray" ); + + GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", + (int)( *length_p ), (int)stateSize, (int)maxClassID )); + + /* + * 2 states are predefined and must be described: + * state 0 (start of text), 1 (start of line) + */ + GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 ); + + *maxState_p = 0; + *maxEntry_p = 0; + + /* read if enough to read another state */ + while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit ) + { + (*maxState_p)++; + for ( clazz = 0; clazz <= maxClassID; clazz++ ) + { + entry = FT_NEXT_USHORT( p ); + *maxEntry_p = (FT_UShort)FT_MAX( *maxEntry_p, entry ); + } + } + GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n", + *maxState_p, *maxEntry_p )); + + *length_p = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_XEntryTable_validate( FT_Bytes table, + FT_ULong* length_p, + FT_UShort maxEntry, + FT_ULong stateArray_length, + FT_UShort maxClassID, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = table + *length_p; + FT_UShort entry; + FT_UShort state; + FT_Int entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable ); + + + GXV_NAME_ENTER( "XEntryTable" ); + GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize )); + + if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit ) + FT_INVALID_TOO_SHORT; + + for (entry = 0; entry <= maxEntry; entry++ ) + { + FT_UShort newState_idx; + FT_UShort flags; + GXV_XStateTable_GlyphOffsetDesc glyphOffset; + + + GXV_LIMIT_CHECK( 2 + 2 ); + newState_idx = FT_NEXT_USHORT( p ); + flags = FT_NEXT_USHORT( p ); + + if ( stateArray_length < (FT_ULong)( newState_idx * 2 ) ) + { + GXV_TRACE(( " newState index 0x%04x points out of stateArray\n", + newState_idx )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + state = (FT_UShort)( newState_idx / ( 1 + maxClassID ) ); + if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) ) + { + FT_TRACE4(( "-> new state = %d (supposed)\n", + state )); + FT_TRACE4(( "but newState index 0x%04x" + " is not aligned to %d-classes\n", + newState_idx, 1 + maxClassID )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) ) + { + case GXV_GLYPHOFFSET_NONE: + glyphOffset.uc = 0; /* make compiler happy */ + break; + + case GXV_GLYPHOFFSET_UCHAR: + glyphOffset.uc = FT_NEXT_BYTE( p ); + break; + + case GXV_GLYPHOFFSET_CHAR: + glyphOffset.c = FT_NEXT_CHAR( p ); + break; + + case GXV_GLYPHOFFSET_USHORT: + glyphOffset.u = FT_NEXT_USHORT( p ); + break; + + case GXV_GLYPHOFFSET_SHORT: + glyphOffset.s = FT_NEXT_SHORT( p ); + break; + + case GXV_GLYPHOFFSET_ULONG: + glyphOffset.ul = FT_NEXT_ULONG( p ); + break; + + case GXV_GLYPHOFFSET_LONG: + glyphOffset.l = FT_NEXT_LONG( p ); + break; + + default: + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + goto Exit; + } + + if ( gxvalid->xstatetable.entry_validate_func ) + gxvalid->xstatetable.entry_validate_func( state, + flags, + &glyphOffset, + xstatetable_table, + xstatetable_limit, + gxvalid ); + } + + Exit: + *length_p = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* StateHeader members */ + FT_ULong classTable; /* offset to Class(Sub)Table */ + FT_ULong stateArray; /* offset to StateArray */ + FT_ULong entryTable; /* offset to EntryTable */ + + FT_ULong classTable_length; + FT_ULong stateArray_length; + FT_ULong entryTable_length; + FT_UShort maxState; + FT_UShort maxEntry; + + GXV_XStateTable_Subtable_Setup_Func setup_func; + + FT_Bytes p = table; + + + GXV_NAME_ENTER( "XStateTable" ); + + GXV_TRACE(( "XStateTable header\n" )); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + gxvalid->xstatetable.nClasses = FT_NEXT_ULONG( p ); + classTable = FT_NEXT_ULONG( p ); + stateArray = FT_NEXT_ULONG( p ); + entryTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "nClasses =0x%08lx\n", gxvalid->xstatetable.nClasses )); + GXV_TRACE(( "offset to classTable=0x%08lx\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%08lx\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%08lx\n", entryTable )); + + if ( gxvalid->xstatetable.nClasses > 0xFFFFU ) + FT_INVALID_DATA; + + GXV_TRACE(( "StateTable Subtables\n" )); + + if ( gxvalid->xstatetable.optdata_load_func ) + gxvalid->xstatetable.optdata_load_func( p, limit, gxvalid ); + + if ( gxvalid->xstatetable.subtable_setup_func ) + setup_func = gxvalid->xstatetable.subtable_setup_func; + else + setup_func = gxv_XStateTable_subtable_setup; + + setup_func( (FT_ULong)( limit - table ), + classTable, + stateArray, + entryTable, + &classTable_length, + &stateArray_length, + &entryTable_length, + gxvalid ); + + if ( classTable != 0 ) + { + gxvalid->xstatetable.maxClassID = 0; + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_XClassTable_lookupval_validate; + gxvalid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit; + gxv_LookupTable_validate( table + classTable, + table + classTable + classTable_length, + gxvalid ); +#if 0 + if ( gxvalid->subtable_length < classTable_length ) + classTable_length = gxvalid->subtable_length; +#endif + } + else + { + /* XXX: check range? */ + gxvalid->xstatetable.maxClassID = + (FT_UShort)( gxvalid->xstatetable.nClasses - 1 ); + } + + if ( stateArray != 0 ) + gxv_XStateArray_validate( table + stateArray, + &stateArray_length, + gxvalid->xstatetable.maxClassID, + gxvalid->xstatetable.nClasses, + &maxState, + &maxEntry, + gxvalid ); + else + { +#if 0 + maxState = 1; /* 0:start of text, 1:start of line are predefined */ +#endif + maxEntry = 0; + } + + if ( maxEntry > 0 && entryTable == 0 ) + FT_INVALID_OFFSET; + + if ( entryTable != 0 ) + gxv_XEntryTable_validate( table + entryTable, + &entryTable_length, + maxEntry, + stateArray_length, + gxvalid->xstatetable.maxClassID, + table, + limit, + gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static int + gxv_compare_ranges( FT_Bytes table1_start, + FT_ULong table1_length, + FT_Bytes table2_start, + FT_ULong table2_length ) + { + if ( table1_start == table2_start ) + { + if ( ( table1_length == 0 || table2_length == 0 ) ) + goto Out; + } + else if ( table1_start < table2_start ) + { + if ( ( table1_start + table1_length ) <= table2_start ) + goto Out; + } + else if ( table1_start > table2_start ) + { + if ( ( table1_start >= table2_start + table2_length ) ) + goto Out; + } + return 1; + + Out: + return 0; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ) + { + odtect->range[odtect->nRanges].start = start; + odtect->range[odtect->nRanges].length = length; + odtect->range[odtect->nRanges].name = (FT_String*)name; + odtect->nRanges++; + } + + + FT_LOCAL_DEF( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator gxvalid ) + { + FT_UInt i, j; + + + GXV_NAME_ENTER( "check overlap among multi ranges" ); + + for ( i = 0; i < odtect->nRanges; i++ ) + for ( j = 0; j < i; j++ ) + if ( 0 != gxv_compare_ranges( odtect->range[i].start, + odtect->range[i].length, + odtect->range[j].start, + odtect->range[j].length ) ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( odtect->range[i].name || odtect->range[j].name ) + GXV_TRACE(( "found overlap between range %d and range %d\n", + i, j )); + else + GXV_TRACE(( "found overlap between `%s' and `%s\'\n", + odtect->range[i].name, + odtect->range[j].name )); +#endif + FT_INVALID_OFFSET; + } + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.h b/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.h new file mode 100644 index 00000000..4dbac1db --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvcommn.h @@ -0,0 +1,581 @@ +/**************************************************************************** + * + * gxvcommn.h + * + * TrueTypeGX/AAT common tables validation (specification). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + + /* + * keywords in variable naming + * --------------------------- + * table: Of type FT_Bytes, pointing to the start of this table/subtable. + * limit: Of type FT_Bytes, pointing to the end of this table/subtable, + * including padding for alignment. + * offset: Of type FT_UInt, the number of octets from the start to target. + * length: Of type FT_UInt, the number of octets from the start to the + * end in this table/subtable, including padding for alignment. + * + * _MIN, _MAX: Should be added to the tail of macros, as INT_MIN, etc. + */ + + +#ifndef GXVCOMMN_H_ +#define GXVCOMMN_H_ + + +#include "gxvalid.h" +#include +#include + + +FT_BEGIN_HEADER + + + /* some variables are not evaluated or only used in trace */ + +#ifdef FT_DEBUG_LEVEL_TRACE +#define GXV_LOAD_TRACE_VARS +#else +#undef GXV_LOAD_TRACE_VARS +#endif + +#undef GXV_LOAD_UNUSED_VARS /* debug purpose */ + +#define IS_PARANOID_VALIDATION \ + ( gxvalid->root->level >= FT_VALIDATE_PARANOID ) +#define GXV_SET_ERR_IF_PARANOID( err ) \ + do { if ( IS_PARANOID_VALIDATION ) ( err ); } while ( 0 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_ValidatorRec_* GXV_Validator; + + +#define DUMMY_LIMIT 0 + + typedef void + (*GXV_Validate_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /* ====================== LookupTable Validator ======================== */ + + typedef union GXV_LookupValueDesc_ + { + FT_UShort u; + FT_Short s; + + } GXV_LookupValueDesc; + + typedef const GXV_LookupValueDesc* GXV_LookupValueCPtr; + + typedef enum GXV_LookupValue_SignSpec_ + { + GXV_LOOKUPVALUE_UNSIGNED = 0, + GXV_LOOKUPVALUE_SIGNED + + } GXV_LookupValue_SignSpec; + + + typedef void + (*GXV_Lookup_Value_Validate_Func)( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ); + + typedef GXV_LookupValueDesc + (*GXV_Lookup_Fmt4_Transit_Func)( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ); + + + /* ====================== StateTable Validator ========================= */ + + typedef enum GXV_GlyphOffset_Format_ + { + GXV_GLYPHOFFSET_NONE = -1, + GXV_GLYPHOFFSET_UCHAR = 2, + GXV_GLYPHOFFSET_CHAR, + GXV_GLYPHOFFSET_USHORT = 4, + GXV_GLYPHOFFSET_SHORT, + GXV_GLYPHOFFSET_ULONG = 8, + GXV_GLYPHOFFSET_LONG + + } GXV_GlyphOffset_Format; + + +#define GXV_GLYPHOFFSET_FMT( table ) \ + ( gxvalid->table.entry_glyphoffset_fmt ) + +#define GXV_GLYPHOFFSET_SIZE( table ) \ + ( gxvalid->table.entry_glyphoffset_fmt / 2 ) + + + /* ----------------------- 16bit StateTable ---------------------------- */ + + typedef union GXV_StateTable_GlyphOffsetDesc_ + { + FT_Byte uc; + FT_UShort u; /* same as GXV_LookupValueDesc */ + FT_ULong ul; + FT_Char c; + FT_Short s; /* same as GXV_LookupValueDesc */ + FT_Long l; + + } GXV_StateTable_GlyphOffsetDesc; + + typedef const GXV_StateTable_GlyphOffsetDesc* GXV_StateTable_GlyphOffsetCPtr; + + typedef void + (*GXV_StateTable_Subtable_Setup_Func)( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ); + + typedef void + (*GXV_StateTable_Entry_Validate_Func)( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes statetable_table, + FT_Bytes statetable_limit, + GXV_Validator gxvalid ); + + typedef void + (*GXV_StateTable_OptData_Load_Func)( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + typedef struct GXV_StateTable_ValidatorRec_ + { + GXV_GlyphOffset_Format entry_glyphoffset_fmt; + void* optdata; + + GXV_StateTable_Subtable_Setup_Func subtable_setup_func; + GXV_StateTable_Entry_Validate_Func entry_validate_func; + GXV_StateTable_OptData_Load_Func optdata_load_func; + + } GXV_StateTable_ValidatorRec, *GXV_StateTable_ValidatorRecData; + + + /* ---------------------- 32bit XStateTable ---------------------------- */ + + typedef GXV_StateTable_GlyphOffsetDesc GXV_XStateTable_GlyphOffsetDesc; + + typedef const GXV_XStateTable_GlyphOffsetDesc* GXV_XStateTable_GlyphOffsetCPtr; + + typedef void + (*GXV_XStateTable_Subtable_Setup_Func)( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ); + + typedef void + (*GXV_XStateTable_Entry_Validate_Func)( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes xstatetable_table, + FT_Bytes xstatetable_limit, + GXV_Validator gxvalid ); + + + typedef GXV_StateTable_OptData_Load_Func GXV_XStateTable_OptData_Load_Func; + + + typedef struct GXV_XStateTable_ValidatorRec_ + { + int entry_glyphoffset_fmt; + void* optdata; + + GXV_XStateTable_Subtable_Setup_Func subtable_setup_func; + GXV_XStateTable_Entry_Validate_Func entry_validate_func; + GXV_XStateTable_OptData_Load_Func optdata_load_func; + + FT_ULong nClasses; + FT_UShort maxClassID; + + } GXV_XStateTable_ValidatorRec, *GXV_XStateTable_ValidatorRecData; + + + /* ===================================================================== */ + + typedef struct GXV_ValidatorRec_ + { + FT_Validator root; + + FT_Face face; + void* table_data; + + FT_ULong subtable_length; + + GXV_LookupValue_SignSpec lookupval_sign; + GXV_Lookup_Value_Validate_Func lookupval_func; + GXV_Lookup_Fmt4_Transit_Func lookupfmt4_trans; + FT_Bytes lookuptbl_head; + + FT_UShort min_gid; + FT_UShort max_gid; + + GXV_StateTable_ValidatorRec statetable; + GXV_XStateTable_ValidatorRec xstatetable; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } GXV_ValidatorRec; + + +#define GXV_TABLE_DATA( tag, field ) \ + ( ( (GXV_ ## tag ## _Data)gxvalid->table_data )->field ) + +#undef FT_INVALID_ +#define FT_INVALID_( _error ) \ + ft_validator_error( gxvalid->root, FT_THROW( _error ) ) + +#define GXV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + _count > ( limit? limit : gxvalid->root->limit ) ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define GXV_INIT gxvalid->debug_indent = 0 + +#define GXV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + gxvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define GXV_EXIT gxvalid->debug_indent -= 2 + +#define GXV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define GXV_INIT do { } while ( 0 ) +#define GXV_NAME_ENTER( name ) do { } while ( 0 ) +#define GXV_EXIT do { } while ( 0 ) + +#define GXV_TRACE( s ) do { } while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** 32bit alignment checking *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_32BIT_ALIGNMENT_VALIDATE( a ) \ + FT_BEGIN_STMNT \ + { \ + if ( (a) & 3 ) \ + FT_INVALID_OFFSET; \ + } \ + FT_END_STMNT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Dumping Binary Data *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_TRACE_HEXDUMP( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + FT_TRACE1(("\\x%02x", *b)); \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_C( p, len ) \ + FT_BEGIN_STMNT \ + { \ + FT_Bytes b; \ + \ + \ + for ( b = p; b < (FT_Bytes)p + len; b++ ) \ + if ( 0x40 < *b && *b < 0x7E ) \ + FT_TRACE1(("%c", *b)); \ + else \ + FT_TRACE1(("\\x%02x", *b)); \ + } \ + FT_END_STMNT + +#define GXV_TRACE_HEXDUMP_SFNTNAME( n ) \ + GXV_TRACE_HEXDUMP( n.string, n.string_len ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUP TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_BinSrchHeader_validate( FT_Bytes p, + FT_Bytes limit, + FT_UShort* unitSize_p, + FT_UShort* nUnits_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_LookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Glyph ID *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( FT_Int ) + gxv_glyphid_validate( FT_UShort gid, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CONTROL POINT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_ctlPoint_validate( FT_UShort gid, + FT_UShort ctl_point, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SFNT NAME *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_sfntName_validate( FT_UShort name_index, + FT_UShort min_index, + FT_UShort max_index, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STATE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_StateTable_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_XStateTable_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_StateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_XStateTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY MACROS AND FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + gxv_array_getlimits_byte( FT_Bytes table, + FT_Bytes limit, + FT_Byte* min, + FT_Byte* max, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_array_getlimits_ushort( FT_Bytes table, + FT_Bytes limit, + FT_UShort* min, + FT_UShort* max, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_set_length_by_ushort_offset( FT_UShort* offset, + FT_UShort** length, + FT_UShort* buff, + FT_UInt nmemb, + FT_UShort limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_set_length_by_ulong_offset( FT_ULong* offset, + FT_ULong** length, + FT_ULong* buff, + FT_UInt nmemb, + FT_ULong limit, + GXV_Validator gxvalid); + + +#define GXV_SUBTABLE_OFFSET_CHECK( _offset ) \ + FT_BEGIN_STMNT \ + if ( (_offset) > gxvalid->subtable_length ) \ + FT_INVALID_OFFSET; \ + FT_END_STMNT + +#define GXV_SUBTABLE_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( ( p + (_count) - gxvalid->subtable_start ) > \ + gxvalid->subtable_length ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define GXV_STATETABLE_HEADER_SIZE ( 2 + 2 + 2 + 2 ) +#define GXV_STATEHEADER_SIZE GXV_STATETABLE_HEADER_SIZE + +#define GXV_XSTATETABLE_HEADER_SIZE ( 4 + 4 + 4 + 4 ) +#define GXV_XSTATEHEADER_SIZE GXV_XSTATETABLE_HEADER_SIZE + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Table overlapping *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_odtect_DataRec_ + { + FT_Bytes start; + FT_ULong length; + FT_String* name; + + } GXV_odtect_DataRec, *GXV_odtect_Data; + + typedef struct GXV_odtect_RangeRec_ + { + FT_UInt nRanges; + GXV_odtect_Data range; + + } GXV_odtect_RangeRec, *GXV_odtect_Range; + + + FT_LOCAL( void ) + gxv_odtect_add_range( FT_Bytes start, + FT_ULong length, + const FT_String* name, + GXV_odtect_Range odtect ); + + FT_LOCAL( void ) + gxv_odtect_validate( GXV_odtect_Range odtect, + GXV_Validator gxvalid ); + + +#define GXV_ODTECT( n, odtect ) \ + GXV_odtect_DataRec odtect ## _range[n]; \ + GXV_odtect_RangeRec odtect ## _rec = { 0, NULL }; \ + GXV_odtect_Range odtect = NULL + +#define GXV_ODTECT_INIT( odtect ) \ + FT_BEGIN_STMNT \ + odtect ## _rec.nRanges = 0; \ + odtect ## _rec.range = odtect ## _range; \ + odtect = & odtect ## _rec; \ + FT_END_STMNT + + + /* */ + +FT_END_HEADER + +#endif /* GXVCOMMN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxverror.h b/Dependencies/freetype/freetype/src/gxvalid/gxverror.h new file mode 100644 index 00000000..750f22fc --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxverror.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * gxverror.h + * + * TrueTypeGX/AAT validation module error codes (specification only). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + + /************************************************************************** + * + * This file is used to define the OpenType validation module error + * enumeration constants. + * + */ + +#ifndef GXVERROR_H_ +#define GXVERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX GXV_Err_ +#define FT_ERR_BASE FT_Mod_Err_GXvalid + +#include + +#endif /* GXVERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.c b/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.c new file mode 100644 index 00000000..57b38923 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.c @@ -0,0 +1,339 @@ +/**************************************************************************** + * + * gxvfeat.c + * + * TrueTypeGX/AAT feat table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" +#include "gxvfeat.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvfeat + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_feat_DataRec_ + { + FT_UInt reserved_size; + FT_UShort feature; + FT_UShort setting; + + } GXV_feat_DataRec, *GXV_feat_Data; + + +#define GXV_FEAT_DATA( field ) GXV_TABLE_DATA( feat, field ) + + + typedef enum GXV_FeatureFlagsMask_ + { + GXV_FEAT_MASK_EXCLUSIVE_SETTINGS = 0x8000U, + GXV_FEAT_MASK_DYNAMIC_DEFAULT = 0x4000, + GXV_FEAT_MASK_UNUSED = 0x3F00, + GXV_FEAT_MASK_DEFAULT_SETTING = 0x00FF + + } GXV_FeatureFlagsMask; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_feat_registry_validate( FT_UShort feature, + FT_UShort nSettings, + FT_Bool exclusive, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "feature in registry" ); + + GXV_TRACE(( " (feature = %u)\n", feature )); + + if ( feature >= gxv_feat_registry_length ) + { + GXV_TRACE(( "feature number %d is out of range %lu\n", + feature, gxv_feat_registry_length )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + goto Exit; + } + + if ( gxv_feat_registry[feature].existence == 0 ) + { + GXV_TRACE(( "feature number %d is in defined range but doesn't exist\n", + feature )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + goto Exit; + } + + if ( gxv_feat_registry[feature].apple_reserved ) + { + /* Don't use here. Apple is reserved. */ + GXV_TRACE(( "feature number %d is reserved by Apple\n", feature )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( nSettings != gxv_feat_registry[feature].nSettings ) + { + GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n", + feature, nSettings, + gxv_feat_registry[feature].nSettings )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + if ( exclusive != gxv_feat_registry[feature].exclusive ) + { + GXV_TRACE(( "exclusive flag %d differs from predefined value\n", + exclusive )); + if ( gxvalid->root->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + } + + Exit: + GXV_EXIT; + } + + + static void + gxv_feat_name_index_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Short nameIndex; + + + GXV_NAME_ENTER( "nameIndex" ); + + GXV_LIMIT_CHECK( 2 ); + nameIndex = FT_NEXT_SHORT ( p ); + GXV_TRACE(( " (nameIndex = %d)\n", nameIndex )); + + gxv_sfntName_validate( (FT_UShort)nameIndex, + 255, + 32768U, + gxvalid ); + + GXV_EXIT; + } + + + static void + gxv_feat_setting_validate( FT_Bytes table, + FT_Bytes limit, + FT_Bool exclusive, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort setting; + + + GXV_NAME_ENTER( "setting" ); + + GXV_LIMIT_CHECK( 2 ); + + setting = FT_NEXT_USHORT( p ); + + /* If we have exclusive setting, the setting should be odd. */ + if ( exclusive && ( setting & 1 ) == 0 ) + FT_INVALID_DATA; + + gxv_feat_name_index_validate( p, limit, gxvalid ); + + GXV_FEAT_DATA( setting ) = setting; + + GXV_EXIT; + } + + + static void + gxv_feat_name_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UInt reserved_size = GXV_FEAT_DATA( reserved_size ); + + FT_UShort feature; + FT_UShort nSettings; + FT_ULong settingTable; + FT_UShort featureFlags; + + FT_Bool exclusive; + FT_Int last_setting; + FT_UInt i; + + + GXV_NAME_ENTER( "name" ); + + /* feature + nSettings + settingTable + featureFlags */ + GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 ); + + feature = FT_NEXT_USHORT( p ); + GXV_FEAT_DATA( feature ) = feature; + + nSettings = FT_NEXT_USHORT( p ); + settingTable = FT_NEXT_ULONG ( p ); + featureFlags = FT_NEXT_USHORT( p ); + + if ( settingTable < reserved_size ) + FT_INVALID_OFFSET; + + if ( ( featureFlags & GXV_FEAT_MASK_UNUSED ) == 0 ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + + exclusive = FT_BOOL( featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS ); + if ( exclusive ) + { + FT_Byte dynamic_default; + + + if ( featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT ) + dynamic_default = (FT_Byte)( featureFlags & + GXV_FEAT_MASK_DEFAULT_SETTING ); + else + dynamic_default = 0; + + /* If exclusive, check whether default setting is in the range. */ + if ( !( dynamic_default < nSettings ) ) + FT_INVALID_FORMAT; + } + + gxv_feat_registry_validate( feature, nSettings, exclusive, gxvalid ); + + gxv_feat_name_index_validate( p, limit, gxvalid ); + + p = gxvalid->root->base + settingTable; + for ( last_setting = -1, i = 0; i < nSettings; i++ ) + { + gxv_feat_setting_validate( p, limit, exclusive, gxvalid ); + + if ( (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + + last_setting = (FT_Int)GXV_FEAT_DATA( setting ); + /* setting + nameIndex */ + p += ( 2 + 2 ); + } + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** feat TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_feat_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_feat_DataRec featrec; + GXV_feat_Data feat = &featrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_UInt featureNameCount; + + FT_UInt i; + FT_Int last_feature; + + + gxvalid->root = ftvalid; + gxvalid->table_data = feat; + gxvalid->face = face; + + FT_TRACE3(( "validating `feat' table\n" )); + GXV_INIT; + + feat->reserved_size = 0; + + /* version + featureNameCount + none_0 + none_1 */ + GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 ); + feat->reserved_size += 4 + 2 + 2 + 4; + + if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */ + FT_INVALID_FORMAT; + + featureNameCount = FT_NEXT_USHORT( p ); + GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); + + if ( !( IS_PARANOID_VALIDATION ) ) + p += 6; /* skip (none) and (none) */ + else + { + if ( FT_NEXT_USHORT( p ) != 0 ) + FT_INVALID_DATA; + + if ( FT_NEXT_ULONG( p ) != 0 ) + FT_INVALID_DATA; + } + + feat->reserved_size += featureNameCount * ( 2 + 2 + 4 + 2 + 2 ); + + for ( last_feature = -1, i = 0; i < featureNameCount; i++ ) + { + gxv_feat_name_validate( p, limit, gxvalid ); + + if ( (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_FORMAT ); + + last_feature = GXV_FEAT_DATA( feature ); + p += 2 + 2 + 4 + 2 + 2; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.h b/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.h new file mode 100644 index 00000000..dd8f1bfe --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvfeat.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * + * gxvfeat.h + * + * TrueTypeGX/AAT feat table validation (specification). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVFEAT_H_ +#define GXVFEAT_H_ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Registry predefined by Apple *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* TODO: More compact format */ + typedef struct GXV_Feature_RegistryRec_ + { + FT_Bool existence; + FT_Bool apple_reserved; + FT_Bool exclusive; + FT_Byte nSettings; + + } GX_Feature_RegistryRec; + + +#define gxv_feat_registry_length \ + ( sizeof ( gxv_feat_registry ) / \ + sizeof ( GX_Feature_RegistryRec ) ) + + + static GX_Feature_RegistryRec gxv_feat_registry[] = + { + /* Generated from gxvfgen.c */ + {1, 0, 0, 1}, /* All Typographic Features */ + {1, 0, 0, 8}, /* Ligatures */ + {1, 0, 1, 3}, /* Cursive Connection */ + {1, 0, 1, 6}, /* Letter Case */ + {1, 0, 0, 1}, /* Vertical Substitution */ + {1, 0, 0, 1}, /* Linguistic Rearrangement */ + {1, 0, 1, 2}, /* Number Spacing */ + {1, 1, 0, 0}, /* Apple Reserved 1 */ + {1, 0, 0, 5}, /* Smart Swashes */ + {1, 0, 1, 3}, /* Diacritics */ + {1, 0, 1, 4}, /* Vertical Position */ + {1, 0, 1, 3}, /* Fractions */ + {1, 1, 0, 0}, /* Apple Reserved 2 */ + {1, 0, 0, 1}, /* Overlapping Characters */ + {1, 0, 0, 6}, /* Typographic Extras */ + {1, 0, 0, 5}, /* Mathematical Extras */ + {1, 0, 1, 7}, /* Ornament Sets */ + {1, 0, 1, 1}, /* Character Alternatives */ + {1, 0, 1, 5}, /* Design Complexity */ + {1, 0, 1, 6}, /* Style Options */ + {1, 0, 1, 11}, /* Character Shape */ + {1, 0, 1, 2}, /* Number Case */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 10}, /* Transliteration */ + {1, 0, 1, 9}, /* Annotation */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {0, 0, 0, 0}, /* __EMPTY__ */ + {1, 0, 1, 4}, /* Text Spacing */ + {1, 0, 1, 2}, /* Kana Spacing */ + {1, 0, 1, 2}, /* Ideographic Spacing */ + {1, 0, 1, 4}, /* CJK Roman Spacing */ + }; + + +#endif /* GXVFEAT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvfgen.c b/Dependencies/freetype/freetype/src/gxvalid/gxvfgen.c new file mode 100644 index 00000000..27a4ed9a --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvfgen.c @@ -0,0 +1,484 @@ +/**************************************************************************** + * + * gxfgen.c + * + * Generate feature registry data for gxv `feat' validator. + * This program is derived from gxfeatreg.c in gxlayout. + * + * Copyright (C) 2004-2024 by + * Masatake YAMATO and Redhat K.K. + * + * This file may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxfeatreg.c + * + * Database of font features pre-defined by Apple Computer, Inc. + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html + * (body). + * + * Copyright 2003 by + * Masatake YAMATO and Redhat K.K. + * + * This file may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * Development of gxfeatreg.c is supported by + * Information-technology Promotion Agency, Japan. + * + */ + + +/**************************************************************************** + * + * This file is compiled as a stand-alone executable. + * This file is never compiled into `libfreetype2'. + * The output of this file is used in `gxvfeat.c'. + * ----------------------------------------------------------------------- + * Compile: gcc `pkg-config --cflags freetype2` gxvfgen.c -o gxvfgen + * Run: ./gxvfgen > tmp.c + * + */ + + /******************************************************************** + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + + /* + * If you add a new setting to a feature, check the number of settings + * in the feature. If the number is greater than the value defined as + * FEATREG_MAX_SETTING, update the value. + */ +#define FEATREG_MAX_SETTING 12 + + /******************************************************************** + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + + +#include +#include + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define APPLE_RESERVED "Apple Reserved" +#define APPLE_RESERVED_LENGTH 14 + + typedef struct GX_Feature_RegistryRec_ + { + const char* feat_name; + char exclusive; + char* setting_name[FEATREG_MAX_SETTING]; + + } GX_Feature_RegistryRec; + + +#define EMPTYFEAT {0, 0, {NULL}} + + + static GX_Feature_RegistryRec featreg_table[] = + { + { /* 0 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + }, { /* 1 */ + "Ligatures", + 0, + { + "Required Ligatures", + "Common Ligatures", + "Rare Ligatures", + "Logos", + "Rebus Pictures", + "Diphthong Ligatures", + "Squared Ligatures", + "Squared Ligatures, Abbreviated", + NULL + } + }, { /* 2 */ + "Cursive Connection", + 1, + { + "Unconnected", + "Partially Connected", + "Cursive", + NULL + } + }, { /* 3 */ + "Letter Case", + 1, + { + "Upper & Lower Case", + "All Caps", + "All Lower Case", + "Small Caps", + "Initial Caps", + "Initial Caps & Small Caps", + NULL + } + }, { /* 4 */ + "Vertical Substitution", + 0, + { + /* "Substitute Vertical Forms", */ + "Turns on the feature", + NULL + } + }, { /* 5 */ + "Linguistic Rearrangement", + 0, + { + /* "Linguistic Rearrangement", */ + "Turns on the feature", + NULL + } + }, { /* 6 */ + "Number Spacing", + 1, + { + "Monospaced Numbers", + "Proportional Numbers", + NULL + } + }, { /* 7 */ + APPLE_RESERVED " 1", + 0, + {NULL} + }, { /* 8 */ + "Smart Swashes", + 0, + { + "Word Initial Swashes", + "Word Final Swashes", + "Line Initial Swashes", + "Line Final Swashes", + "Non-Final Swashes", + NULL + } + }, { /* 9 */ + "Diacritics", + 1, + { + "Show Diacritics", + "Hide Diacritics", + "Decompose Diacritics", + NULL + } + }, { /* 10 */ + "Vertical Position", + 1, + { + /* "Normal Position", */ + "No Vertical Position", + "Superiors", + "Inferiors", + "Ordinals", + NULL + } + }, { /* 11 */ + "Fractions", + 1, + { + "No Fractions", + "Vertical Fractions", + "Diagonal Fractions", + NULL + } + }, { /* 12 */ + APPLE_RESERVED " 2", + 0, + {NULL} + }, { /* 13 */ + "Overlapping Characters", + 0, + { + /* "Prevent Overlap", */ + "Turns on the feature", + NULL + } + }, { /* 14 */ + "Typographic Extras", + 0, + { + "Hyphens to Em Dash", + "Hyphens to En Dash", + "Unslashed Zero", + "Form Interrobang", + "Smart Quotes", + "Periods to Ellipsis", + NULL + } + }, { /* 15 */ + "Mathematical Extras", + 0, + { + "Hyphens to Minus", + "Asterisk to Multiply", + "Slash to Divide", + "Inequality Ligatures", + "Exponents", + NULL + } + }, { /* 16 */ + "Ornament Sets", + 1, + { + "No Ornaments", + "Dingbats", + "Pi Characters", + "Fleurons", + "Decorative Borders", + "International Symbols", + "Math Symbols", + NULL + } + }, { /* 17 */ + "Character Alternatives", + 1, + { + "No Alternates", + /* TODO */ + NULL + } + }, { /* 18 */ + "Design Complexity", + 1, + { + "Design Level 1", + "Design Level 2", + "Design Level 3", + "Design Level 4", + "Design Level 5", + /* TODO */ + NULL + } + }, { /* 19 */ + "Style Options", + 1, + { + "No Style Options", + "Display Text", + "Engraved Text", + "Illuminated Caps", + "Tilling Caps", + "Tall Caps", + NULL + } + }, { /* 20 */ + "Character Shape", + 1, + { + "Traditional Characters", + "Simplified Characters", + "JIS 1978 Characters", + "JIS 1983 Characters", + "JIS 1990 Characters", + "Traditional Characters, Alternative Set 1", + "Traditional Characters, Alternative Set 2", + "Traditional Characters, Alternative Set 3", + "Traditional Characters, Alternative Set 4", + "Traditional Characters, Alternative Set 5", + "Expert Characters", + NULL /* count => 12 */ + } + }, { /* 21 */ + "Number Case", + 1, + { + "Lower Case Numbers", + "Upper Case Numbers", + NULL + } + }, { /* 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, /* Here after Newer */ { /* 23 */ + "Transliteration", + 1, + { + "No Transliteration", + "Hanja To Hangul", + "Hiragana to Katakana", + "Katakana to Hiragana", + "Kana to Romanization", + "Romanization to Hiragana", + "Romanization to Katakana", + "Hanja to Hangul, Alternative Set 1", + "Hanja to Hangul, Alternative Set 2", + "Hanja to Hangul, Alternative Set 3", + NULL + } + }, { /* 24 */ + "Annotation", + 1, + { + "No Annotation", + "Box Annotation", + "Rounded Box Annotation", + "Circle Annotation", + "Inverted Circle Annotation", + "Parenthesis Annotation", + "Period Annotation", + "Roman Numeral Annotation", + "Diamond Annotation", + NULL + } + }, { /* 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 27-30 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 31-35 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 36-40 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 40-45 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 46-50 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 51-55 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 56-60 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 61-65 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 66-70 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 71-75 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 76-80 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 81-85 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 86-90 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 91-95 */ + EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 96-98 */ + EMPTYFEAT, /* 99 */ { /* 100 => 22 */ + "Text Spacing", + 1, + { + "Proportional", + "Monospaced", + "Half-width", + "Normal", + NULL + } + }, { /* 101 => 25 */ + "Kana Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 102 => 26 */ + "Ideographic Spacing", + 1, + { + "Full Width", + "Proportional", + NULL + } + }, { /* 103 */ + "CJK Roman Spacing", + 1, + { + "Half-width", + "Proportional", + "Default Roman", + "Full-width Roman", + NULL + } + }, { /* 104 => 1 */ + "All Typographic Features", + 0, + { + "All Type Features", + NULL + } + } + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Generator *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + int + main( void ) + { + int i; + + + printf( " {\n" ); + printf( " /* Generated from %s */\n", __FILE__ ); + + for ( i = 0; + i < sizeof ( featreg_table ) / sizeof ( GX_Feature_RegistryRec ); + i++ ) + { + const char* feat_name; + int nSettings; + + + feat_name = featreg_table[i].feat_name; + for ( nSettings = 0; + featreg_table[i].setting_name[nSettings]; + nSettings++) + ; /* Do nothing */ + + printf( " {%1d, %1d, %1d, %2d}, /* %s */\n", + feat_name ? 1 : 0, + ( feat_name && + ( ft_strncmp( feat_name, + APPLE_RESERVED, APPLE_RESERVED_LENGTH ) == 0 ) + ) ? 1 : 0, + featreg_table[i].exclusive ? 1 : 0, + nSettings, + feat_name ? feat_name : "__EMPTY__" ); + } + + printf( " };\n" ); + + return 0; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvjust.c b/Dependencies/freetype/freetype/src/gxvalid/gxvjust.c new file mode 100644 index 00000000..1cf9e84a --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvjust.c @@ -0,0 +1,721 @@ +/**************************************************************************** + * + * gxvjust.c + * + * TrueTypeGX/AAT just table validation (body). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvjust + + /* + * referred `just' table format specification: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html + * last updated 2000. + * ---------------------------------------------- + * [JUST HEADER]: GXV_JUST_HEADER_SIZE + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (2000) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * ---------------------------------------------- + */ + + typedef struct GXV_just_DataRec_ + { + FT_UShort wdc_offset_max; + FT_UShort wdc_offset_min; + FT_UShort pc_offset_max; + FT_UShort pc_offset_min; + + } GXV_just_DataRec, *GXV_just_Data; + + +#define GXV_JUST_DATA( a ) GXV_TABLE_DATA( just, a ) + + + /* GX just table does not define their subset of GID */ + static void + gxv_just_check_max_gid( FT_UShort gid, + const FT_String* msg_tag, + GXV_Validator gxvalid ) + { + FT_UNUSED( msg_tag ); + + if ( gid < gxvalid->face->num_glyphs ) + return; + + GXV_TRACE(( "just table includes too large %s" + " GID=%d > %ld (in maxp)\n", + msg_tag, gid, gxvalid->face->num_glyphs )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + + static void + gxv_just_wdp_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong justClass; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Fixed beforeGrowLimit; + FT_Fixed beforeShrinkGrowLimit; + FT_Fixed afterGrowLimit; + FT_Fixed afterShrinkGrowLimit; + FT_UShort growFlags; + FT_UShort shrinkFlags; +#endif + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 ); + justClass = FT_NEXT_ULONG( p ); +#ifndef GXV_LOAD_UNUSED_VARS + p += 4 + 4 + 4 + 4 + 2 + 2; +#else + beforeGrowLimit = FT_NEXT_ULONG( p ); + beforeShrinkGrowLimit = FT_NEXT_ULONG( p ); + afterGrowLimit = FT_NEXT_ULONG( p ); + afterShrinkGrowLimit = FT_NEXT_ULONG( p ); + growFlags = FT_NEXT_USHORT( p ); + shrinkFlags = FT_NEXT_USHORT( p ); +#endif + + /* According to Apple spec, only 7bits in justClass is used */ + if ( ( justClass & 0xFFFFFF80UL ) != 0 ) + { + GXV_TRACE(( "just table includes non-zero value" + " in unused justClass higher bits" + " of WidthDeltaPair" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_wdc_entry_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong count, i; + + + GXV_LIMIT_CHECK( 4 ); + count = FT_NEXT_ULONG( p ); + for ( i = 0; i < count; i++ ) + { + GXV_TRACE(( "validating wdc pair %lu/%lu\n", i + 1, count )); + gxv_just_wdp_entry_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_widthDeltaClusters_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); + + + GXV_NAME_ENTER( "just justDeltaClusters" ); + + if ( limit <= wdc_end ) + FT_INVALID_OFFSET; + + while ( p <= wdc_end ) + { + gxv_just_wdc_entry_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_actSubrecord_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Fixed lowerLimit; + FT_Fixed upperLimit; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort order; +#endif + FT_UShort decomposedCount; + + FT_UInt i; + + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); + lowerLimit = FT_NEXT_LONG( p ); + upperLimit = FT_NEXT_LONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + order = FT_NEXT_USHORT( p ); +#else + p += 2; +#endif + decomposedCount = FT_NEXT_USHORT( p ); + + if ( lowerLimit >= upperLimit ) + { + GXV_TRACE(( "just table includes invalid range spec:" + " lowerLimit(%ld) > upperLimit(%ld)\n", + lowerLimit, upperLimit )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + for ( i = 0; i < decomposedCount; i++ ) + { + FT_UShort glyphs; + + + GXV_LIMIT_CHECK( 2 ); + glyphs = FT_NEXT_USHORT( p ); + gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid ); + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort addGlyph; + + + GXV_LIMIT_CHECK( 2 ); + addGlyph = FT_NEXT_USHORT( p ); + + gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Fixed substThreshhold; /* Apple misspelled "Threshhold" */ +#endif + FT_UShort addGlyph; + FT_UShort substGlyph; + + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + substThreshhold = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + addGlyph = FT_NEXT_USHORT( p ); + substGlyph = FT_NEXT_USHORT( p ); + + if ( addGlyph != 0xFFFF ) + gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid ); + + gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + static void + gxv_just_actSubrecord_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong variantsAxis; + FT_Fixed minimumLimit; + FT_Fixed noStretchValue; + FT_Fixed maximumLimit; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); + variantsAxis = FT_NEXT_ULONG( p ); + minimumLimit = FT_NEXT_LONG( p ); + noStretchValue = FT_NEXT_LONG( p ); + maximumLimit = FT_NEXT_LONG( p ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + if ( variantsAxis != 0x64756374L ) /* 'duct' */ + GXV_TRACE(( "variantsAxis 0x%08lx is non default value", + variantsAxis )); + + if ( minimumLimit > noStretchValue ) + GXV_TRACE(( "type4:minimumLimit 0x%08lx > noStretchValue 0x%08lx\n", + minimumLimit, noStretchValue )); + else if ( noStretchValue > maximumLimit ) + GXV_TRACE(( "type4:noStretchValue 0x%08lx > maximumLimit 0x%08lx\n", + noStretchValue, maximumLimit )); + else if ( !IS_PARANOID_VALIDATION ) + return; + + FT_INVALID_DATA; + } + + + static void + gxv_just_actSubrecord_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort flags; + FT_UShort glyph; + + + GXV_LIMIT_CHECK( 2 + 2 ); + flags = FT_NEXT_USHORT( p ); + glyph = FT_NEXT_USHORT( p ); + + if ( flags ) + GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n", + flags )); + gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + } + + + /* parse single actSubrecord */ + static void + gxv_just_actSubrecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort actionClass; + FT_UShort actionType; + FT_ULong actionLength; + + + GXV_NAME_ENTER( "just actSubrecord" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + actionClass = FT_NEXT_USHORT( p ); + actionType = FT_NEXT_USHORT( p ); + actionLength = FT_NEXT_ULONG( p ); + + /* actionClass is related with justClass using 7bit only */ + if ( ( actionClass & 0xFF80 ) != 0 ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + + if ( actionType == 0 ) + gxv_just_actSubrecord_type0_validate( p, limit, gxvalid ); + else if ( actionType == 1 ) + gxv_just_actSubrecord_type1_validate( p, limit, gxvalid ); + else if ( actionType == 2 ) + gxv_just_actSubrecord_type2_validate( p, limit, gxvalid ); + else if ( actionType == 3 ) + ; /* Stretch glyph action: no actionData */ + else if ( actionType == 4 ) + gxv_just_actSubrecord_type4_validate( p, limit, gxvalid ); + else if ( actionType == 5 ) + gxv_just_actSubrecord_type5_validate( p, limit, gxvalid ); + else + FT_INVALID_DATA; + + gxvalid->subtable_length = actionLength; + + GXV_EXIT; + } + + + static void + gxv_just_pcActionRecord_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong actionCount; + FT_ULong i; + + + GXV_LIMIT_CHECK( 4 ); + actionCount = FT_NEXT_ULONG( p ); + GXV_TRACE(( "actionCount = %lu\n", actionCount )); + + for ( i = 0; i < actionCount; i++ ) + { + gxv_just_actSubrecord_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_pcTable_LookupValue_entry_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_max ) = value_p->u; + if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) ) + GXV_JUST_DATA( pc_offset_min ) = value_p->u; + } + + + static void + gxv_just_pcLookupTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just pcLookupTable" ); + GXV_JUST_DATA( pc_offset_max ) = 0x0000; + GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_postcompTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "just postcompTable" ); + + gxv_just_pcLookupTable_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxv_just_pcActionRecord_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_just_classTable_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + /* TODO: validate markClass & currentClass */ + FT_UShort setMark; + FT_UShort dontAdvance; + FT_UShort markClass; + FT_UShort currentClass; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + FT_UNUSED( gxvalid ); + +#ifndef GXV_LOAD_UNUSED_VARS + FT_UNUSED( flags ); +#else + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markClass = (FT_UShort)( ( flags >> 7 ) & 0x7F ); + currentClass = (FT_UShort)( flags & 0x7F ); +#endif + } + + + static void + gxv_just_justClassTable_validate ( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort length; + FT_UShort coverage; + FT_ULong subFeatureFlags; + + + GXV_NAME_ENTER( "just justClassTable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + subFeatureFlags = FT_NEXT_ULONG( p ); + + GXV_TRACE(( " justClassTable: coverage = 0x%04x ", coverage )); + if ( ( coverage & 0x4000 ) == 0 ) + GXV_TRACE(( "ascending\n" )); + else + GXV_TRACE(( "descending\n" )); + + if ( subFeatureFlags ) + GXV_TRACE(( " justClassTable: nonzero value (0x%08lx)" + " in unused subFeatureFlags\n", subFeatureFlags )); + + gxvalid->statetable.optdata = NULL; + gxvalid->statetable.optdata_load_func = NULL; + gxvalid->statetable.subtable_setup_func = NULL; + gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_just_classTable_entry_validate; + + gxv_StateTable_validate( p, table + length, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + static void + gxv_just_wdcTable_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) ) + GXV_JUST_DATA( wdc_offset_max ) = value_p->u; + if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) ) + GXV_JUST_DATA( wdc_offset_min ) = value_p->u; + } + + + static void + gxv_just_justData_lookuptable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_JUST_DATA( wdc_offset_max ) = 0x0000; + GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + /* subtable_length is set by gxv_LookupTable_validate() */ + + GXV_EXIT; + } + + + /* + * gxv_just_justData_validate() parses and validates horizData, vertData. + */ + static void + gxv_just_justData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* + * following 3 offsets are measured from the start of `just' + * (which table points to), not justData + */ + FT_UShort justClassTableOffset; + FT_UShort wdcTableOffset; + FT_UShort pcTableOffset; + FT_Bytes p = table; + + GXV_ODTECT( 4, odtect ); + + + GXV_NAME_ENTER( "just justData" ); + + GXV_ODTECT_INIT( odtect ); + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + justClassTableOffset = FT_NEXT_USHORT( p ); + wdcTableOffset = FT_NEXT_USHORT( p ); + pcTableOffset = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset )); + GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset )); + GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset )); + + gxv_just_justData_lookuptable_validate( p, limit, gxvalid ); + gxv_odtect_add_range( p, gxvalid->subtable_length, + "just_LookupTable", odtect ); + + if ( wdcTableOffset ) + { + gxv_just_widthDeltaClusters_validate( + gxvalid->root->base + wdcTableOffset, limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset, + gxvalid->subtable_length, "just_wdcTable", odtect ); + } + + if ( pcTableOffset ) + { + gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset, + limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + pcTableOffset, + gxvalid->subtable_length, "just_pcTable", odtect ); + } + + if ( justClassTableOffset ) + { + gxv_just_justClassTable_validate( + gxvalid->root->base + justClassTableOffset, limit, gxvalid ); + gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset, + gxvalid->subtable_length, "just_justClassTable", + odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_just_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_just_DataRec justrec; + GXV_just_Data just = &justrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + + GXV_ODTECT( 3, odtect ); + + + GXV_ODTECT_INIT( odtect ); + + gxvalid->root = ftvalid; + gxvalid->table_data = just; + gxvalid->face = face; + + FT_TRACE3(( "validating `just' table\n" )); + GXV_INIT; + + limit = gxvalid->root->limit; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + gxv_odtect_add_range( table, (FT_ULong)( p - table ), + "just header", odtect ); + + + /* Version 1.0 (always:2000) */ + GXV_TRACE(( " (version = 0x%08lx)\n", version )); + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:2000) */ + GXV_TRACE(( " (format = 0x%04x)\n", format )); + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_TRACE(( " (horizOffset = %d)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = %d)\n", vertOffset )); + + + /* validate justData */ + if ( 0 < horizOffset ) + { + gxv_just_justData_validate( table + horizOffset, limit, gxvalid ); + gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_just_justData_validate( table + vertOffset, limit, gxvalid ); + gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvkern.c b/Dependencies/freetype/freetype/src/gxvalid/gxvkern.c new file mode 100644 index 00000000..cf8c51fb --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvkern.c @@ -0,0 +1,920 @@ +/**************************************************************************** + * + * gxvkern.c + * + * TrueTypeGX/AAT kern table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvkern + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef enum GXV_kern_Version_ + { + KERN_VERSION_CLASSIC = 0x0000, + KERN_VERSION_NEW = 0x0001 + + } GXV_kern_Version; + + + typedef enum GXV_kern_Dialect_ + { + KERN_DIALECT_UNKNOWN = 0, + KERN_DIALECT_MS = FT_VALIDATE_MS, + KERN_DIALECT_APPLE = FT_VALIDATE_APPLE, + KERN_DIALECT_ANY = FT_VALIDATE_CKERN + + } GXV_kern_Dialect; + + + typedef struct GXV_kern_DataRec_ + { + GXV_kern_Version version; + void *subtable_data; + GXV_kern_Dialect dialect_request; + + } GXV_kern_DataRec, *GXV_kern_Data; + + +#define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field ) + +#define KERN_IS_CLASSIC( gxvalid ) \ + ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) ) +#define KERN_IS_NEW( gxvalid ) \ + ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) ) + +#define KERN_DIALECT( gxvalid ) \ + GXV_KERN_DATA( dialect_request ) +#define KERN_ALLOWS_MS( gxvalid ) \ + ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_MS ) +#define KERN_ALLOWS_APPLE( gxvalid ) \ + ( KERN_DIALECT( gxvalid ) & KERN_DIALECT_APPLE ) + +#define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 4 ) +#define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( gxvalid ) ? 8 : 6 ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SUBTABLE VALIDATORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* ============================= format 0 ============================== */ + + static void + gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nPairs, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + FT_UShort last_gid_left = 0; + FT_UShort last_gid_right = 0; + + FT_UNUSED( limit ); + + + GXV_NAME_ENTER( "kern format 0 pairs" ); + + for ( i = 0; i < nPairs; i++ ) + { + FT_UShort gid_left; + FT_UShort gid_right; +#ifdef GXV_LOAD_UNUSED_VARS + FT_Short kernValue; +#endif + + + /* left */ + gid_left = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_left, gxvalid ); + + /* right */ + gid_right = FT_NEXT_USHORT( p ); + gxv_glyphid_validate( gid_right, gxvalid ); + + /* Pairs of left and right GIDs must be unique and sorted. */ + GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right )); + if ( gid_left == last_gid_left ) + { + if ( last_gid_right < gid_right ) + last_gid_right = gid_right; + else + FT_INVALID_DATA; + } + else if ( last_gid_left < gid_left ) + { + last_gid_left = gid_left; + last_gid_right = gid_right; + } + else + FT_INVALID_DATA; + + /* skip the kern value */ +#ifdef GXV_LOAD_UNUSED_VARS + kernValue = FT_NEXT_SHORT( p ); +#else + p += 2; +#endif + } + + GXV_EXIT; + } + + static void + gxv_kern_subtable_fmt0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + + FT_UShort nPairs; + FT_UShort unitSize; + + + GXV_NAME_ENTER( "kern subtable format 0" ); + + unitSize = 2 + 2 + 2; + nPairs = 0; + + /* nPairs, searchRange, entrySelector, rangeShift */ + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, gxvalid ); + p += 2 + 2 + 2 + 2; + + gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, gxvalid ); + + GXV_EXIT; + } + + + /* ============================= format 1 ============================== */ + + + typedef struct GXV_kern_fmt1_StateOptRec_ + { + FT_UShort valueTable; + FT_UShort valueTable_length; + + } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData; + + + static void + gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->valueTable = FT_NEXT_USHORT( p ); + } + + + /* + * passed tables_size covers whole StateTable, including kern fmt1 header + */ + static void + gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_kern_fmt1_StateOptRecData optdata = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->valueTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->valueTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + /* + * passed table & limit are of whole StateTable, not including subtables + */ + static void + gxv_kern_subtable_fmt1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort push; + FT_UShort dontAdvance; +#endif + FT_UShort valueOffset; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort kernAction; + FT_UShort kernValue; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + + +#ifdef GXV_LOAD_UNUSED_VARS + push = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + valueOffset = (FT_UShort)( flags & 0x3FFF ); + + { + GXV_kern_fmt1_StateOptRecData vt_rec = + (GXV_kern_fmt1_StateOptRecData)gxvalid->statetable.optdata; + FT_Bytes p; + + + if ( valueOffset < vt_rec->valueTable ) + FT_INVALID_OFFSET; + + p = table + valueOffset; + limit = table + vt_rec->valueTable + vt_rec->valueTable_length; + + GXV_LIMIT_CHECK( 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + kernAction = FT_NEXT_USHORT( p ); + kernValue = FT_NEXT_USHORT( p ); +#endif + } + } + + + static void + gxv_kern_subtable_fmt1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_kern_fmt1_StateOptRec vt_rec; + + + GXV_NAME_ENTER( "kern subtable format 1" ); + + gxvalid->statetable.optdata = + &vt_rec; + gxvalid->statetable.optdata_load_func = + gxv_kern_subtable_fmt1_valueTable_load; + gxvalid->statetable.subtable_setup_func = + gxv_kern_subtable_fmt1_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_kern_subtable_fmt1_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + + /* ================ Data for Class-Based Subtables 2, 3 ================ */ + + typedef enum GXV_kern_ClassSpec_ + { + GXV_KERN_CLS_L = 0, + GXV_KERN_CLS_R + + } GXV_kern_ClassSpec; + + + /* ============================= format 2 ============================== */ + + /* ---------------------- format 2 specific data ----------------------- */ + + typedef struct GXV_kern_subtable_fmt2_DataRec_ + { + FT_UShort rowWidth; + FT_UShort array; + FT_UShort offset_min[2]; + FT_UShort offset_max[2]; + const FT_String* class_tag[2]; + GXV_odtect_Range odtect; + + } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data; + + +#define GXV_KERN_FMT2_DATA( field ) \ + ( ( (GXV_kern_subtable_fmt2_DataRec *) \ + ( GXV_KERN_DATA( subtable_data ) ) )->field ) + + + /* -------------------------- utility functions ----------------------- */ + + static void + gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table, + FT_Bytes limit, + GXV_kern_ClassSpec spec, + GXV_Validator gxvalid ) + { + const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] ); + GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect ); + + FT_Bytes p = table; + FT_UShort firstGlyph; + FT_UShort nGlyphs; + + + GXV_NAME_ENTER( "kern format 2 classTable" ); + + GXV_LIMIT_CHECK( 2 + 2 ); + firstGlyph = FT_NEXT_USHORT( p ); + nGlyphs = FT_NEXT_USHORT( p ); + GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", + tag, firstGlyph, nGlyphs )); + + gxv_glyphid_validate( firstGlyph, gxvalid ); + gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), gxvalid ); + + gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ), + &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ), + &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ), + gxvalid ); + + gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect ); + + GXV_EXIT; + } + + + static void + gxv_kern_subtable_fmt2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + GXV_ODTECT( 3, odtect ); + GXV_kern_subtable_fmt2_DataRec fmt2_rec = + { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL }; + + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort leftOffsetTable; + FT_UShort rightOffsetTable; + + + GXV_NAME_ENTER( "kern subtable format 2" ); + + GXV_ODTECT_INIT( odtect ); + fmt2_rec.odtect = odtect; + GXV_KERN_DATA( subtable_data ) = &fmt2_rec; + + GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 ); + GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p ); + leftOffsetTable = FT_NEXT_USHORT( p ); + rightOffsetTable = FT_NEXT_USHORT( p ); + GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) )); + + + GXV_LIMIT_CHECK( leftOffsetTable ); + GXV_LIMIT_CHECK( rightOffsetTable ); + GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit, + GXV_KERN_CLS_L, gxvalid ); + + gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit, + GXV_KERN_CLS_R, gxvalid ); + + if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] ) + < GXV_KERN_FMT2_DATA( array ) ) + FT_INVALID_OFFSET; + + gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ), + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] ) + + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] ) + - GXV_KERN_FMT2_DATA( array ), + "array", odtect ); + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + /* ============================= format 3 ============================== */ + + static void + gxv_kern_subtable_fmt3_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE; + FT_UShort glyphCount; + FT_Byte kernValueCount; + FT_Byte leftClassCount; + FT_Byte rightClassCount; + FT_Byte flags; + + + GXV_NAME_ENTER( "kern subtable format 3" ); + + GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 ); + glyphCount = FT_NEXT_USHORT( p ); + kernValueCount = FT_NEXT_BYTE( p ); + leftClassCount = FT_NEXT_BYTE( p ); + rightClassCount = FT_NEXT_BYTE( p ); + flags = FT_NEXT_BYTE( p ); + + if ( gxvalid->face->num_glyphs != glyphCount ) + { + GXV_TRACE(( "maxGID=%ld, but glyphCount=%d\n", + gxvalid->face->num_glyphs, glyphCount )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + + if ( flags != 0 ) + GXV_TRACE(( "kern subtable fmt3 has nonzero value" + " (%d) in unused flag\n", flags )); + /* + * just skip kernValue[kernValueCount] + */ + GXV_LIMIT_CHECK( 2 * kernValueCount ); + p += 2 * kernValueCount; + + /* + * check leftClass[gid] < leftClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); + p += gxvalid->subtable_length; + + if ( leftClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check rightClass[gid] < rightClassCount + */ + { + FT_Byte min, max; + + + GXV_LIMIT_CHECK( glyphCount ); + gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, gxvalid ); + p += gxvalid->subtable_length; + + if ( rightClassCount < max ) + FT_INVALID_DATA; + } + + /* + * check kernIndex[i, j] < kernValueCount + */ + { + FT_UShort i, j; + + + for ( i = 0; i < leftClassCount; i++ ) + { + for ( j = 0; j < rightClassCount; j++ ) + { + GXV_LIMIT_CHECK( 1 ); + if ( kernValueCount < FT_NEXT_BYTE( p ) ) + FT_INVALID_OFFSET; + } + } + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static FT_Bool + gxv_kern_coverage_new_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* new Apple-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool kernVertical; + FT_Bool kernCrossStream; + FT_Bool kernVariation; +#endif + + FT_UNUSED( gxvalid ); + + + /* reserved bits = 0 */ + if ( coverage & 0x1FFC ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 ); + kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 ); + kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 ); +#endif + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "new Apple-dialect: " + "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n", + !kernVertical, kernCrossStream, kernVariation, *format )); + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return TRUE; + } + + + static FT_Bool + gxv_kern_coverage_classic_apple_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* classic Apple-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool horizontal; + FT_Bool cross_stream; +#endif + + + /* check expected flags, but don't check if MS-dialect is impossible */ + if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( gxvalid ) ) + return FALSE; + + /* reserved bits = 0 */ + if ( coverage & 0x02FC ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + horizontal = FT_BOOL( ( coverage >> 15 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 ); +#endif + + *format = (FT_UShort)( coverage & 0x0003 ); + + GXV_TRACE(( "classic Apple-dialect: " + "horizontal=%d, cross-stream=%d, format=%d\n", + horizontal, cross_stream, *format )); + + /* format 1 requires GX State Machine, too new for classic */ + if ( *format == 1 ) + return FALSE; + + GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" )); + + return TRUE; + } + + + static FT_Bool + gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + /* classic Microsoft-dialect */ +#ifdef GXV_LOAD_TRACE_VARS + FT_Bool horizontal; + FT_Bool minimum; + FT_Bool cross_stream; + FT_Bool override; +#endif + + FT_UNUSED( gxvalid ); + + + /* reserved bits = 0 */ + if ( coverage & 0xFDF0 ) + return FALSE; + +#ifdef GXV_LOAD_TRACE_VARS + horizontal = FT_BOOL( coverage & 1 ); + minimum = FT_BOOL( ( coverage >> 1 ) & 1 ); + cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 ); + override = FT_BOOL( ( coverage >> 3 ) & 1 ); +#endif + + *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 ); + + GXV_TRACE(( "classic Microsoft-dialect: " + "horizontal=%d, minimum=%d, cross-stream=%d, " + "override=%d, format=%d\n", + horizontal, minimum, cross_stream, override, *format )); + + if ( *format == 2 ) + GXV_TRACE(( + "kerning values in Microsoft format 2 subtable are ignored\n" )); + + return TRUE; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MAIN *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static GXV_kern_Dialect + gxv_kern_coverage_validate( FT_UShort coverage, + FT_UShort* format, + GXV_Validator gxvalid ) + { + GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN; + + + GXV_NAME_ENTER( "validating coverage" ); + + GXV_TRACE(( "interpret coverage 0x%04x by Apple style\n", coverage )); + + if ( KERN_IS_NEW( gxvalid ) ) + { + if ( gxv_kern_coverage_new_apple_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_APPLE( gxvalid ) ) + { + if ( gxv_kern_coverage_classic_apple_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_APPLE; + goto Exit; + } + } + + if ( KERN_IS_CLASSIC( gxvalid ) && KERN_ALLOWS_MS( gxvalid ) ) + { + if ( gxv_kern_coverage_classic_microsoft_validate( coverage, + format, + gxvalid ) ) + { + result = KERN_DIALECT_MS; + goto Exit; + } + } + + GXV_TRACE(( "cannot interpret coverage, broken kern subtable\n" )); + + Exit: + GXV_EXIT; + return result; + } + + + static void + gxv_kern_subtable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort version = 0; /* MS only: subtable version, unused */ +#endif + FT_ULong length; /* MS: 16bit, Apple: 32bit */ + FT_UShort coverage; +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort tupleIndex = 0; /* Apple only */ +#endif + FT_UShort u16[2]; + FT_UShort format = 255; /* subtable format */ + + + GXV_NAME_ENTER( "kern subtable" ); + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */ + u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */ + coverage = FT_NEXT_USHORT( p ); + + switch ( gxv_kern_coverage_validate( coverage, &format, gxvalid ) ) + { + case KERN_DIALECT_MS: +#ifdef GXV_LOAD_TRACE_VARS + version = u16[0]; +#endif + length = u16[1]; +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = 0; +#endif + GXV_TRACE(( "Subtable version = %d\n", version )); + GXV_TRACE(( "Subtable length = %lu\n", length )); + break; + + case KERN_DIALECT_APPLE: +#ifdef GXV_LOAD_TRACE_VARS + version = 0; +#endif + length = ( (FT_ULong)u16[0] << 16 ) + u16[1]; +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = 0; +#endif + GXV_TRACE(( "Subtable length = %lu\n", length )); + + if ( KERN_IS_NEW( gxvalid ) ) + { + GXV_LIMIT_CHECK( 2 ); +#ifdef GXV_LOAD_TRACE_VARS + tupleIndex = FT_NEXT_USHORT( p ); +#else + p += 2; +#endif + GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex )); + } + break; + + default: + length = u16[1]; + GXV_TRACE(( "cannot detect subtable dialect, " + "just skip %lu byte\n", length )); + goto Exit; + } + + /* formats 1, 2, 3 require the position of the start of this subtable */ + if ( format == 0 ) + gxv_kern_subtable_fmt0_validate( table, table + length, gxvalid ); + else if ( format == 1 ) + gxv_kern_subtable_fmt1_validate( table, table + length, gxvalid ); + else if ( format == 2 ) + gxv_kern_subtable_fmt2_validate( table, table + length, gxvalid ); + else if ( format == 3 ) + gxv_kern_subtable_fmt3_validate( table, table + length, gxvalid ); + else + FT_INVALID_DATA; + + Exit: + gxvalid->subtable_length = length; + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** kern TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_kern_validate_generic( FT_Bytes table, + FT_Face face, + FT_Bool classic_only, + GXV_kern_Dialect dialect_request, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_kern_DataRec kernrec; + GXV_kern_Data kern = &kernrec; + + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong nTables = 0; + FT_UInt i; + + + gxvalid->root = ftvalid; + gxvalid->table_data = kern; + gxvalid->face = face; + + FT_TRACE3(( "validating `kern' table\n" )); + GXV_INIT; + KERN_DIALECT( gxvalid ) = dialect_request; + + GXV_LIMIT_CHECK( 2 ); + GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p ); + GXV_TRACE(( "version 0x%04x (higher 16bit)\n", + GXV_KERN_DATA( version ) )); + + if ( 0x0001 < GXV_KERN_DATA( version ) ) + FT_INVALID_FORMAT; + else if ( KERN_IS_CLASSIC( gxvalid ) ) + { + GXV_LIMIT_CHECK( 2 ); + nTables = FT_NEXT_USHORT( p ); + } + else if ( KERN_IS_NEW( gxvalid ) ) + { + if ( classic_only ) + FT_INVALID_FORMAT; + + if ( 0x0000 != FT_NEXT_USHORT( p ) ) + FT_INVALID_FORMAT; + + GXV_LIMIT_CHECK( 4 ); + nTables = FT_NEXT_ULONG( p ); + } + + for ( i = 0; i < nTables; i++ ) + { + GXV_TRACE(( "validating subtable %d/%lu\n", i, nTables )); + /* p should be 32bit-aligned? */ + gxv_kern_subtable_validate( p, 0, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_kern_validate_classic( FT_Bytes table, + FT_Face face, + FT_Int dialect_flags, + FT_Validator ftvalid ) + { + GXV_kern_Dialect dialect_request; + + + dialect_request = (GXV_kern_Dialect)dialect_flags; + gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvlcar.c b/Dependencies/freetype/freetype/src/gxvalid/gxvlcar.c new file mode 100644 index 00000000..0b310f42 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvlcar.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * + * gxvlcar.c + * + * TrueTypeGX/AAT lcar table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvlcar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_lcar_DataRec_ + { + FT_UShort format; + + } GXV_lcar_DataRec, *GXV_lcar_Data; + + +#define GXV_LCAR_DATA( FIELD ) GXV_TABLE_DATA( lcar, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_lcar_partial_validate( FT_Short partial, + FT_UShort glyph, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "partial" ); + + if ( GXV_LCAR_DATA( format ) != 1 ) + goto Exit; + + gxv_ctlPoint_validate( glyph, (FT_UShort)partial, gxvalid ); + + Exit: + GXV_EXIT; + } + + + static void + gxv_lcar_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_Bytes p = gxvalid->root->base + value_p->u; + FT_Bytes limit = gxvalid->root->limit; + FT_UShort count; + FT_Short partial; + FT_UShort i; + + + GXV_NAME_ENTER( "element in lookupTable" ); + + GXV_LIMIT_CHECK( 2 ); + count = FT_NEXT_USHORT( p ); + + GXV_LIMIT_CHECK( 2 * count ); + for ( i = 0; i < count; i++ ) + { + partial = FT_NEXT_SHORT( p ); + gxv_lcar_partial_validate( partial, glyph, gxvalid ); + } + + GXV_EXIT; + } + + + /* + +------ lcar --------------------+ + | | + | +===============+ | + | | lookup header | | + | +===============+ | + | | BinSrchHeader | | + | +===============+ | + | | lastGlyph[0] | | + | +---------------+ | + | | firstGlyph[0] | | head of lcar sfnt table + | +---------------+ | + + | | offset[0] | -> | offset [byte] + | +===============+ | + + | | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + | +---------------+ | + | | firstGlyph[1] | | + | +---------------+ | + | | offset[1] | | + | +===============+ | + | | + | .... | + | | + | 16bit value array | + | +===============+ | + +------| value | <-------+ + | .... + | + | + | + | + | + +----> lcar values...handled by lcar callback function + */ + + static GXV_LookupValueDesc + gxv_lcar_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + p = gxvalid->root->base + offset; + limit = gxvalid->root->limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** lcar TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_lcar_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_lcar_DataRec lcarrec; + GXV_lcar_Data lcar = &lcarrec; + + FT_Fixed version; + + + gxvalid->root = ftvalid; + gxvalid->table_data = lcar; + gxvalid->face = face; + + FT_TRACE3(( "validating `lcar' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_LONG( p ); + GXV_LCAR_DATA( format ) = FT_NEXT_USHORT( p ); + + if ( version != 0x00010000UL) + FT_INVALID_FORMAT; + + if ( GXV_LCAR_DATA( format ) > 1 ) + FT_INVALID_FORMAT; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_lcar_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_lcar_LookupFmt4_transit; + gxv_LookupTable_validate( p, limit, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmod.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmod.c new file mode 100644 index 00000000..ce1e441e --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmod.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * gxvmod.c + * + * FreeType's TrueTypeGX/AAT validation module implementation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include +#include +#include +#include +#include + +#include "gxvmod.h" +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmodule + + + static FT_Error + gxv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + return FT_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_QALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + +#define GXV_TABLE_DECL( _sfnt ) \ + FT_Byte* volatile _sfnt = NULL; \ + FT_ULong len_ ## _sfnt = 0 + +#define GXV_TABLE_LOAD( _sfnt ) \ + FT_BEGIN_STMNT \ + if ( ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) && \ + ( gx_flags & FT_VALIDATE_ ## _sfnt ) ) \ + { \ + error = gxv_load_table( face, TTAG_ ## _sfnt, \ + &_sfnt, &len_ ## _sfnt ); \ + if ( error ) \ + goto Exit; \ + } \ + FT_END_STMNT + +#define GXV_TABLE_VALIDATE( _sfnt ) \ + FT_BEGIN_STMNT \ + if ( _sfnt ) \ + { \ + ft_validator_init( &valid, _sfnt, _sfnt + len_ ## _sfnt, \ + FT_VALIDATE_DEFAULT ); \ + if ( ft_setjmp( valid.jump_buffer ) == 0 ) \ + gxv_ ## _sfnt ## _validate( _sfnt, face, &valid ); \ + error = valid.error; \ + if ( error ) \ + goto Exit; \ + } \ + FT_END_STMNT + +#define GXV_TABLE_SET( _sfnt ) \ + if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) \ + tables[FT_VALIDATE_ ## _sfnt ## _INDEX] = (FT_Bytes)_sfnt + + + static FT_Error + gxv_validate( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_count ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Error error = FT_Err_Ok; + FT_ValidatorRec volatile valid; + + FT_UInt i; + + + GXV_TABLE_DECL( feat ); + GXV_TABLE_DECL( bsln ); + GXV_TABLE_DECL( trak ); + GXV_TABLE_DECL( just ); + GXV_TABLE_DECL( mort ); + GXV_TABLE_DECL( morx ); + GXV_TABLE_DECL( kern ); + GXV_TABLE_DECL( opbd ); + GXV_TABLE_DECL( prop ); + GXV_TABLE_DECL( lcar ); + + for ( i = 0; i < table_count; i++ ) + tables[i] = 0; + + /* load tables */ + GXV_TABLE_LOAD( feat ); + GXV_TABLE_LOAD( bsln ); + GXV_TABLE_LOAD( trak ); + GXV_TABLE_LOAD( just ); + GXV_TABLE_LOAD( mort ); + GXV_TABLE_LOAD( morx ); + GXV_TABLE_LOAD( kern ); + GXV_TABLE_LOAD( opbd ); + GXV_TABLE_LOAD( prop ); + GXV_TABLE_LOAD( lcar ); + + /* validate tables */ + GXV_TABLE_VALIDATE( feat ); + GXV_TABLE_VALIDATE( bsln ); + GXV_TABLE_VALIDATE( trak ); + GXV_TABLE_VALIDATE( just ); + GXV_TABLE_VALIDATE( mort ); + GXV_TABLE_VALIDATE( morx ); + GXV_TABLE_VALIDATE( kern ); + GXV_TABLE_VALIDATE( opbd ); + GXV_TABLE_VALIDATE( prop ); + GXV_TABLE_VALIDATE( lcar ); + + /* Set results */ + GXV_TABLE_SET( feat ); + GXV_TABLE_SET( mort ); + GXV_TABLE_SET( morx ); + GXV_TABLE_SET( bsln ); + GXV_TABLE_SET( just ); + GXV_TABLE_SET( kern ); + GXV_TABLE_SET( opbd ); + GXV_TABLE_SET( trak ); + GXV_TABLE_SET( prop ); + GXV_TABLE_SET( lcar ); + + Exit: + if ( error ) + { + FT_FREE( feat ); + FT_FREE( bsln ); + FT_FREE( trak ); + FT_FREE( just ); + FT_FREE( mort ); + FT_FREE( morx ); + FT_FREE( kern ); + FT_FREE( opbd ); + FT_FREE( prop ); + FT_FREE( lcar ); + } + + return error; + } + + + static FT_Error + classic_kern_validate( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes* ckern_table ) + { + FT_Memory volatile memory = FT_FACE_MEMORY( face ); + + FT_Byte* volatile ckern = NULL; + FT_ULong len_ckern = 0; + + /* without volatile on `error' GCC 4.1.1. emits: */ + /* warning: variable 'error' might be clobbered by 'longjmp' or 'vfork' */ + /* this warning seems spurious but --- */ + FT_Error volatile error; + FT_ValidatorRec volatile valid; + + + *ckern_table = NULL; + + error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern ); + if ( error ) + goto Exit; + + if ( ckern ) + { + ft_validator_init( &valid, ckern, ckern + len_ckern, + FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + gxv_kern_validate_classic( ckern, face, + ckern_flags & FT_VALIDATE_CKERN, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ckern_table = ckern; + + Exit: + if ( error ) + FT_FREE( ckern ); + + return error; + } + + + static + const FT_Service_GXvalidateRec gxvalid_interface = + { + gxv_validate /* validate */ + }; + + + static + const FT_Service_CKERNvalidateRec ckernvalid_interface = + { + classic_kern_validate /* validate */ + }; + + + static + const FT_ServiceDescRec gxvalid_services[] = + { + { FT_SERVICE_ID_GX_VALIDATE, &gxvalid_interface }, + { FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + gxvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( gxvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class gxv_module_class = + { + 0, + sizeof ( FT_ModuleRec ), + "gxvalid", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) gxvalid_get_service /* get_interface */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmod.h b/Dependencies/freetype/freetype/src/gxvalid/gxvmod.h new file mode 100644 index 00000000..6def5c54 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmod.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * gxvmod.h + * + * FreeType's TrueTypeGX/AAT validation module implementation + * (specification). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMOD_H_ +#define GXVMOD_H_ + +#include + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) gxv_module_class; + + +FT_END_HEADER + +#endif /* GXVMOD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort.c new file mode 100644 index 00000000..5ad9d81c --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort.c @@ -0,0 +1,301 @@ +/**************************************************************************** + * + * gxvmort.c + * + * TrueTypeGX/AAT mort table validation (body). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" +#include "gxvfeat.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static void + gxv_mort_feature_validate( GXV_mort_feature f, + GXV_Validator gxvalid ) + { + if ( f->featureType >= gxv_feat_registry_length ) + { + GXV_TRACE(( "featureType %d is out of registered range, " + "setting %d is unchecked\n", + f->featureType, f->featureSetting )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else if ( !gxv_feat_registry[f->featureType].existence ) + { + GXV_TRACE(( "featureType %d is within registered area " + "but undefined, setting %d is unchecked\n", + f->featureType, f->featureSetting )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else + { + FT_Byte nSettings_max; + + + /* nSettings in gxvfeat.c is halved for exclusive on/off settings */ + nSettings_max = gxv_feat_registry[f->featureType].nSettings; + if ( gxv_feat_registry[f->featureType].exclusive ) + nSettings_max = (FT_Byte)( 2 * nSettings_max ); + + GXV_TRACE(( "featureType %d is registered", f->featureType )); + GXV_TRACE(( "setting %d", f->featureSetting )); + + if ( f->featureSetting > nSettings_max ) + { + GXV_TRACE(( "out of defined range %d", nSettings_max )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + GXV_TRACE(( "\n" )); + } + + /* TODO: enableFlags must be unique value in specified chain? */ + } + + + /* + * nFeatureFlags is typed to FT_ULong to accept that in + * mort (typed FT_UShort) and morx (typed FT_ULong). + */ + FT_LOCAL_DEF( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_ULong nFeatureFlags, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_ULong i; + + GXV_mort_featureRec f = GXV_MORT_FEATURE_OFF; + + + GXV_NAME_ENTER( "mort feature list" ); + for ( i = 0; i < nFeatureFlags; i++ ) + { + GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 ); + f.featureType = FT_NEXT_USHORT( p ); + f.featureSetting = FT_NEXT_USHORT( p ); + f.enableFlags = FT_NEXT_ULONG( p ); + f.disableFlags = FT_NEXT_ULONG( p ); + + gxv_mort_feature_validate( &f, gxvalid ); + } + + if ( !IS_GXV_MORT_FEATURE_OFF( f ) ) + FT_INVALID_DATA; + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator gxvalid ) + { + FT_UNUSED( gxvalid ); + FT_UNUSED( coverage ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( coverage & 0x8000U ) + GXV_TRACE(( " this subtable is for vertical text only\n" )); + else + GXV_TRACE(( " this subtable is for horizontal text only\n" )); + + if ( coverage & 0x4000 ) + GXV_TRACE(( " this subtable is applied to glyph array " + "in descending order\n" )); + else + GXV_TRACE(( " this subtable is applied to glyph array " + "in ascending order\n" )); + + if ( coverage & 0x2000 ) + GXV_TRACE(( " this subtable is forcibly applied to " + "vertical/horizontal text\n" )); + + if ( coverage & 0x1FF8 ) + GXV_TRACE(( " coverage has non-zero bits in reserved area\n" )); +#endif + } + + + static void + gxv_mort_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_mort_subtable_type0_validate, /* 0 */ + gxv_mort_subtable_type1_validate, /* 1 */ + gxv_mort_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_mort_subtable_type4_validate, /* 4 */ + gxv_mort_subtable_type5_validate, /* 5 */ + + }; + + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + GXV_Validate_Func func; + + FT_UShort length; + FT_UShort coverage; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong subFeatureFlags; +#endif + FT_UInt type; + FT_UInt rest; + + + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); +#ifdef GXV_LOAD_UNUSED_VARS + subFeatureFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + + GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", + i + 1, nSubtables, length )); + type = coverage & 0x0007; + rest = length - ( 2 + 2 + 4 ); + + GXV_LIMIT_CHECK( rest ); + gxv_mort_coverage_validate( coverage, gxvalid ); + + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( !func ) + GXV_TRACE(( "morx type %d is reserved\n", type )); + + func( p, p + rest, gxvalid ); + + p += rest; + /* TODO: validate subFeatureFlags */ + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_mort_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong defaultFlags; +#endif + FT_ULong chainLength; + FT_UShort nFeatureFlags; + FT_UShort nSubtables; + + + GXV_NAME_ENTER( "mort chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 ); +#ifdef GXV_LOAD_UNUSED_VARS + defaultFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_USHORT( p ); + nSubtables = FT_NEXT_USHORT( p ); + + gxv_mort_featurearray_validate( p, table + chainLength, + nFeatureFlags, gxvalid ); + p += gxvalid->subtable_length; + gxv_mort_subtables_validate( p, table + chainLength, nSubtables, gxvalid ); + gxvalid->subtable_length = chainLength; + + /* TODO: validate defaultFlags */ + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + gxvalid->root = ftvalid; + gxvalid->face = face; + limit = gxvalid->root->limit; + + FT_TRACE3(( "validating `mort' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if (version != 0x00010000UL) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_mort_chain_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort.h b/Dependencies/freetype/freetype/src/gxvalid/gxvmort.h new file mode 100644 index 00000000..a3970e78 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * + * gxvmort.h + * + * TrueTypeGX/AAT common definition for mort table (specification). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMORT_H_ +#define GXVMORT_H_ + +#include "gxvalid.h" +#include "gxvcommn.h" + +#include + + +FT_BEGIN_HEADER + + + typedef struct GXV_mort_featureRec_ + { + FT_UShort featureType; + FT_UShort featureSetting; + FT_ULong enableFlags; + FT_ULong disableFlags; + + } GXV_mort_featureRec, *GXV_mort_feature; + +#define GXV_MORT_FEATURE_OFF {0, 1, 0x00000000UL, 0x00000000UL} + +#define IS_GXV_MORT_FEATURE_OFF( f ) \ + ( (f).featureType == 0 || \ + (f).featureSetting == 1 || \ + (f).enableFlags == 0x00000000UL || \ + (f).disableFlags == 0x00000000UL ) + + + FT_LOCAL( void ) + gxv_mort_featurearray_validate( FT_Bytes table, + FT_Bytes limit, + FT_ULong nFeatureFlags, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_coverage_validate( FT_UShort coverage, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + +FT_END_HEADER + +#endif /* GXVMORT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort0.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort0.c new file mode 100644 index 00000000..1a05a6d4 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort0.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * gxvmort0.c + * + * TrueTypeGX/AAT mort table validation + * body for type0 (Indic Script Rearrangement) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static const char* GXV_Mort_IndicScript_Msg[] = + { + "no change", + "Ax => xA", + "xD => Dx", + "AxD => DxA", + "ABx => xAB", + "ABx => xBA", + "xCD => CDx", + "xCD => DCx", + "AxCD => CDxA", + "AxCD => DCxA", + "ABxD => DxAB", + "ABxD => DxBA", + "ABxCD => CDxAB", + "ABxCD => CDxBA", + "ABxCD => DCxAB", + "ABxCD => DCxBA", + + }; + + + static void + gxv_mort_subtable_type0_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; + FT_UShort reserved; + FT_UShort verb = 0; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + FT_UNUSED( GXV_Mort_IndicScript_Msg[verb] ); /* for the non-debugging */ + FT_UNUSED( glyphOffset_p ); /* case */ + + + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); + + reserved = (FT_UShort)( flags & 0x1FF0 ); + verb = (FT_UShort)( flags & 0x000F ); + + GXV_TRACE(( " IndicScript MorphRule for glyphOffset 0x%04x", + glyphOffset_p->u )); + GXV_TRACE(( " markFirst=%01d", markFirst )); + GXV_TRACE(( " dontAdvance=%01d", dontAdvance )); + GXV_TRACE(( " markLast=%01d", markLast )); + GXV_TRACE(( " %02d", verb )); + GXV_TRACE(( " %s\n", GXV_Mort_IndicScript_Msg[verb] )); + + if ( markFirst > 0 && markLast > 0 ) + { + GXV_TRACE(( " [odd] a glyph is marked as the first and last" + " in Indic rearrangement\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + if ( markFirst > 0 && dontAdvance > 0 ) + { + GXV_TRACE(( " [odd] the first glyph is marked as dontAdvance" + " in Indic rearrangement\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + else + GXV_TRACE(( "\n" )); + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "mort chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + gxvalid->statetable.optdata = NULL; + gxvalid->statetable.optdata_load_func = NULL; + gxvalid->statetable.subtable_setup_func = NULL; + gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type0_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort1.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort1.c new file mode 100644 index 00000000..f99a8a49 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort1.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * + * gxvmort1.c + * + * TrueTypeGX/AAT mort table validation + * body for type1 (Contextual Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + typedef struct GXV_mort_subtable_type1_StateOptRec_ + { + FT_UShort substitutionTable; + FT_UShort substitutionTable_length; + + } GXV_mort_subtable_type1_StateOptRec, + *GXV_mort_subtable_type1_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_mort_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_mort_subtable_type1_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[4]; + FT_UShort *l[4]; + FT_UShort buff[5]; + + GXV_mort_subtable_type1_StateOptRecData optdata = + (GXV_mort_subtable_type1_StateOptRecData)gxvalid->statetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &( optdata->substitutionTable_length ); + + gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_mort_subtable_type1_offset_to_subst_validate( + FT_Short wordOffset, + const FT_String* tag, + FT_Byte state, + GXV_Validator gxvalid ) + { + FT_UShort substTable; + FT_UShort substTable_limit; + + FT_UNUSED( tag ); + FT_UNUSED( state ); + + + substTable = + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable; + substTable_limit = + (FT_UShort)( substTable + + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable_length ); + + gxvalid->min_gid = (FT_UShort)( ( substTable - wordOffset * 2 ) / 2 ); + gxvalid->max_gid = (FT_UShort)( ( substTable_limit - wordOffset * 2 ) / 2 ); + gxvalid->max_gid = (FT_UShort)( FT_MAX( gxvalid->max_gid, + gxvalid->face->num_glyphs ) ); + + /* XXX: check range? */ + + /* TODO: min_gid & max_gid comparison with ClassTable contents */ + } + + + static void + gxv_mort_subtable_type1_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setMark; + FT_UShort dontAdvance; +#endif + FT_UShort reserved; + FT_Short markOffset; + FT_Short currentOffset; + + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = (FT_UShort)( flags >> 15 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + reserved = (FT_UShort)( flags & 0x3FFF ); + + markOffset = (FT_Short)( glyphOffset_p->ul >> 16 ); + currentOffset = (FT_Short)( glyphOffset_p->ul ); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + gxv_mort_subtable_type1_offset_to_subst_validate( markOffset, + "markOffset", + state, + gxvalid ); + + gxv_mort_subtable_type1_offset_to_subst_validate( currentOffset, + "currentOffset", + state, + gxvalid ); + } + + + static void + gxv_mort_subtable_type1_substTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort num_gids = (FT_UShort)( + ((GXV_mort_subtable_type1_StateOptRec *) + (gxvalid->statetable.optdata))->substitutionTable_length / 2 ); + FT_UShort i; + + + GXV_NAME_ENTER( "validating contents of substitutionTable" ); + for ( i = 0; i < num_gids; i++ ) + { + FT_UShort dst_gid; + + + GXV_LIMIT_CHECK( 2 ); + dst_gid = FT_NEXT_USHORT( p ); + + if ( dst_gid >= 0xFFFFU ) + continue; + + if ( dst_gid < gxvalid->min_gid || gxvalid->max_gid < dst_gid ) + { + GXV_TRACE(( "substTable include a strange gid[%d]=%d >" + " out of define range (%d..%d)\n", + i, dst_gid, gxvalid->min_gid, gxvalid->max_gid )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + + GXV_EXIT; + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, and entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "mort chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE ); + + gxvalid->statetable.optdata = + &st_rec; + gxvalid->statetable.optdata_load_func = + gxv_mort_subtable_type1_substitutionTable_load; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type1_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->statetable.entry_validate_func = + + gxv_mort_subtable_type1_entry_validate; + gxv_StateTable_validate( p, limit, gxvalid ); + + gxv_mort_subtable_type1_substTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort2.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort2.c new file mode 100644 index 00000000..18c9be67 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort2.c @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * gxvmort2.c + * + * TrueTypeGX/AAT mort table validation + * body for type2 (Ligature Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + typedef struct GXV_mort_subtable_type2_StateOptRec_ + { + FT_UShort ligActionTable; + FT_UShort componentTable; + FT_UShort ligatureTable; + FT_UShort ligActionTable_length; + FT_UShort componentTable_length; + FT_UShort ligatureTable_length; + + } GXV_mort_subtable_type2_StateOptRec, + *GXV_mort_subtable_type2_StateOptRecData; + +#define GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 ) + + + static void + gxv_mort_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_LIMIT_CHECK( 2 + 2 + 2 ); + optdata->ligActionTable = FT_NEXT_USHORT( p ); + optdata->componentTable = FT_NEXT_USHORT( p ); + optdata->ligatureTable = FT_NEXT_USHORT( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%04x\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%04x\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%04x\n", + optdata->ligatureTable )); + } + + + static void + gxv_mort_subtable_type2_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort *classTable_length_p, + FT_UShort *stateArray_length_p, + FT_UShort *entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_UShort o[6]; + FT_UShort *l[6]; + FT_UShort buff[7]; + + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, gxvalid ); + + GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%04x length=0x%04x\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + + static void + gxv_mort_subtable_type2_ligActionOffset_validate( + FT_Bytes table, + FT_UShort ligActionOffset, + GXV_Validator gxvalid ) + { + /* access ligActionTable */ + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = table + ligActionOffset; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset ); + if ( p < lat_base ) + { + GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%ld byte rewind)\n", + ligActionOffset, lat_base - p )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%ld byte overrun)\n", + ligActionOffset, p - lat_limit )); + + /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort last; + FT_UShort store; +#endif + FT_ULong offset; + + + lig_action = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); +#endif + + /* Apple spec defines this offset as a word offset */ + offset = lig_action & 0x3FFFFFFFUL; + if ( offset * 2 < optdata->ligatureTable ) + { + GXV_TRACE(( "too short offset 0x%08lx:" + " 2 x offset < ligatureTable (%lu byte rewind)\n", + offset, optdata->ligatureTable - offset * 2 )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } else if ( offset * 2 > + optdata->ligatureTable + optdata->ligatureTable_length ) + { + GXV_TRACE(( "too long offset 0x%08lx:" + " 2 x offset > ligatureTable + ligatureTable_length" + " (%lu byte overrun)\n", + offset, + optdata->ligatureTable + optdata->ligatureTable_length + - offset * 2 )); + + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + } + } + + + static void + gxv_mort_subtable_type2_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setComponent; + FT_UShort dontAdvance; +#endif + FT_UShort offset; + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + + offset = (FT_UShort)( flags & 0x3FFFU ); + + if ( 0 < offset ) + gxv_mort_subtable_type2_ligActionOffset_validate( table, offset, + gxvalid ); + } + + + static void + gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator gxvalid ) + { + GXV_mort_subtable_type2_StateOptRecData optdata = + (GXV_mort_subtable_type2_StateOptRecData)gxvalid->statetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" ); + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + + if ( gxvalid->face->num_glyphs < lig_gid ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE ); + + gxvalid->statetable.optdata = + &lig_rec; + gxvalid->statetable.optdata_load_func = + gxv_mort_subtable_type2_opttable_load; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type2_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_NONE; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type2_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + p += gxvalid->subtable_length; + gxv_mort_subtable_type2_ligatureTable_validate( table, gxvalid ); + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort4.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort4.c new file mode 100644 index 00000000..bc190fad --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort4.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * gxvmort4.c + * + * TrueTypeGX/AAT mort table validation + * body for type4 (Non-Contextual Glyph Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + static void + gxv_mort_subtable_type4_lookupval_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); + + gxv_glyphid_validate( value_p->u, gxvalid ); + } + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 16bit value array | + +===============+ | + | value | <-------+ + .... + */ + + static GXV_LookupValueDesc + gxv_mort_subtable_type4_lookupfmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( "mort chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_mort_subtable_type4_lookupval_validate; + gxvalid->lookupfmt4_trans = gxv_mort_subtable_type4_lookupfmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmort5.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmort5.c new file mode 100644 index 00000000..8211a294 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmort5.c @@ -0,0 +1,234 @@ +/**************************************************************************** + * + * gxvmort5.c + * + * TrueTypeGX/AAT mort table validation + * body for type5 (Contextual Glyph Insertion) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmort.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmort + + + /* + * mort subtable type5 (Contextual Glyph Insertion) + * has the format of StateTable with insertion-glyph-list, + * but without name. The offset is given by glyphOffset in + * entryTable. There is no table location declaration + * like xxxTable. + */ + + typedef struct GXV_mort_subtable_type5_StateOptRec_ + { + FT_UShort classTable; + FT_UShort stateArray; + FT_UShort entryTable; + +#define GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE GXV_STATETABLE_HEADER_SIZE + + FT_UShort* classTable_length_p; + FT_UShort* stateArray_length_p; + FT_UShort* entryTable_length_p; + + } GXV_mort_subtable_type5_StateOptRec, + *GXV_mort_subtable_type5_StateOptRecData; + + + static void + gxv_mort_subtable_type5_subtable_setup( FT_UShort table_size, + FT_UShort classTable, + FT_UShort stateArray, + FT_UShort entryTable, + FT_UShort* classTable_length_p, + FT_UShort* stateArray_length_p, + FT_UShort* entryTable_length_p, + GXV_Validator gxvalid ) + { + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)gxvalid->statetable.optdata; + + + gxv_StateTable_subtable_setup( table_size, + classTable, + stateArray, + entryTable, + classTable_length_p, + stateArray_length_p, + entryTable_length_p, + gxvalid ); + + optdata->classTable = classTable; + optdata->stateArray = stateArray; + optdata->entryTable = entryTable; + + optdata->classTable_length_p = classTable_length_p; + optdata->stateArray_length_p = stateArray_length_p; + optdata->entryTable_length_p = entryTable_length_p; + } + + + static void + gxv_mort_subtable_type5_InsertList_validate( FT_UShort offset, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + /* + * We don't know the range of insertion-glyph-list. + * Set range by whole of state table. + */ + FT_Bytes p = table + offset; + + GXV_mort_subtable_type5_StateOptRecData optdata = + (GXV_mort_subtable_type5_StateOptRecData)gxvalid->statetable.optdata; + + if ( optdata->classTable < offset && + offset < optdata->classTable + *(optdata->classTable_length_p) ) + GXV_TRACE(( " offset runs into ClassTable" )); + if ( optdata->stateArray < offset && + offset < optdata->stateArray + *(optdata->stateArray_length_p) ) + GXV_TRACE(( " offset runs into StateArray" )); + if ( optdata->entryTable < offset && + offset < optdata->entryTable + *(optdata->entryTable_length_p) ) + GXV_TRACE(( " offset runs into EntryTable" )); + +#ifndef GXV_LOAD_TRACE_VARS + GXV_LIMIT_CHECK( count * 2 ); +#else + while ( p < table + offset + ( count * 2 ) ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + GXV_TRACE(( "\n" )); +#endif + } + + + static void + gxv_mort_subtable_type5_entry_validate( + FT_Byte state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; +#endif + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_UShort currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); +#endif + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_UShort)( glyphOffset->ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset->ul ); + + if ( 0 != currentInsertList && 0 != currentInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, + limit, + gxvalid ); + } + + if ( 0 != markedInsertList && 0 != markedInsertCount ) + { + gxv_mort_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, + limit, + gxvalid ); + } + } + + + FT_LOCAL_DEF( void ) + gxv_mort_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_mort_subtable_type5_StateOptRec et_rec; + GXV_mort_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "mort chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE ); + + gxvalid->statetable.optdata = + et; + gxvalid->statetable.optdata_load_func = + NULL; + gxvalid->statetable.subtable_setup_func = + gxv_mort_subtable_type5_subtable_setup; + gxvalid->statetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->statetable.entry_validate_func = + gxv_mort_subtable_type5_entry_validate; + + gxv_StateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.c new file mode 100644 index 00000000..4e7a0d40 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.c @@ -0,0 +1,199 @@ +/**************************************************************************** + * + * gxvmorx.c + * + * TrueTypeGX/AAT morx table validation (body). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + static void + gxv_morx_subtables_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nSubtables, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_Validate_Func fmt_funcs_table[] = + { + gxv_morx_subtable_type0_validate, /* 0 */ + gxv_morx_subtable_type1_validate, /* 1 */ + gxv_morx_subtable_type2_validate, /* 2 */ + NULL, /* 3 */ + gxv_morx_subtable_type4_validate, /* 4 */ + gxv_morx_subtable_type5_validate, /* 5 */ + + }; + + FT_UShort i; + + + GXV_NAME_ENTER( "subtables in a chain" ); + + for ( i = 0; i < nSubtables; i++ ) + { + GXV_Validate_Func func; + + FT_ULong length; + FT_ULong coverage; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong subFeatureFlags; +#endif + FT_ULong type; + FT_ULong rest; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + length = FT_NEXT_ULONG( p ); + coverage = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + subFeatureFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + + GXV_TRACE(( "validating chain subtable %d/%d (%lu bytes)\n", + i + 1, nSubtables, length )); + + type = coverage & 0x0007; + rest = length - ( 4 + 4 + 4 ); + GXV_LIMIT_CHECK( rest ); + + /* morx coverage consists of mort_coverage & 16bit padding */ + gxv_mort_coverage_validate( (FT_UShort)( ( coverage >> 16 ) | coverage ), + gxvalid ); + if ( type > 5 ) + FT_INVALID_FORMAT; + + func = fmt_funcs_table[type]; + if ( !func ) + GXV_TRACE(( "morx type %lu is reserved\n", type )); + + func( p, p + rest, gxvalid ); + + /* TODO: subFeatureFlags should be unique in a table? */ + p += rest; + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + + GXV_EXIT; + } + + + static void + gxv_morx_chain_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; +#ifdef GXV_LOAD_UNUSED_VARS + FT_ULong defaultFlags; +#endif + FT_ULong chainLength; + FT_ULong nFeatureFlags; + FT_ULong nSubtables; + + + GXV_NAME_ENTER( "morx chain header" ); + + GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); +#ifdef GXV_LOAD_UNUSED_VARS + defaultFlags = FT_NEXT_ULONG( p ); +#else + p += 4; +#endif + chainLength = FT_NEXT_ULONG( p ); + nFeatureFlags = FT_NEXT_ULONG( p ); + nSubtables = FT_NEXT_ULONG( p ); + + /* feature-array of morx is same with that of mort */ + gxv_mort_featurearray_validate( p, limit, nFeatureFlags, gxvalid ); + p += gxvalid->subtable_length; + + if ( nSubtables >= 0x10000L ) + FT_INVALID_DATA; + + gxv_morx_subtables_validate( p, table + chainLength, + (FT_UShort)nSubtables, gxvalid ); + + gxvalid->subtable_length = chainLength; + + /* TODO: defaultFlags should be compared with the flags in tables */ + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + FT_ULong version; + FT_ULong nChains; + FT_ULong i; + + + gxvalid->root = ftvalid; + gxvalid->face = face; + + FT_TRACE3(( "validating `morx' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 4 ); + version = FT_NEXT_ULONG( p ); + nChains = FT_NEXT_ULONG( p ); + + if ( version != 0x00020000UL ) + FT_INVALID_FORMAT; + + for ( i = 0; i < nChains; i++ ) + { + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); + GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); + gxv_morx_chain_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.h b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.h new file mode 100644 index 00000000..7e20b5f9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * + * gxvmorx.h + * + * TrueTypeGX/AAT common definition for morx table (specification). + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#ifndef GXVMORX_H_ +#define GXVMORX_H_ + + +#include "gxvalid.h" +#include "gxvcommn.h" +#include "gxvmort.h" + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + FT_LOCAL( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ); + + +FT_END_HEADER + +#endif /* GXVMORX_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx0.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx0.c new file mode 100644 index 00000000..bff850ba --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx0.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * + * gxvmorx0.c + * + * TrueTypeGX/AAT morx table validation + * body for type0 (Indic Script Rearrangement) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + static void + gxv_morx_subtable_type0_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_XStateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort markFirst; + FT_UShort dontAdvance; + FT_UShort markLast; +#endif + FT_UShort reserved; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort verb; +#endif + + FT_UNUSED( state ); + FT_UNUSED( glyphOffset_p ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + markFirst = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + markLast = (FT_UShort)( ( flags >> 13 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x1FF0 ); +#ifdef GXV_LOAD_UNUSED_VARS + verb = (FT_UShort)( flags & 0x000F ); +#endif + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + FT_INVALID_DATA; + } + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type0_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + + GXV_NAME_ENTER( + "morx chain subtable type0 (Indic-Script Rearrangement)" ); + + GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = NULL; + gxvalid->xstatetable.optdata_load_func = NULL; + gxvalid->xstatetable.subtable_setup_func = NULL; + gxvalid->xstatetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type0_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx1.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx1.c new file mode 100644 index 00000000..d8ded3bc --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx1.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * + * gxvmorx1.c + * + * TrueTypeGX/AAT morx table validation + * body for type1 (Contextual Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + typedef struct GXV_morx_subtable_type1_StateOptRec_ + { + FT_ULong substitutionTable; + FT_ULong substitutionTable_length; + FT_UShort substitutionTable_num_lookupTables; + + } GXV_morx_subtable_type1_StateOptRec, + *GXV_morx_subtable_type1_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 2 ) + + + static void + gxv_morx_subtable_type1_substitutionTable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 2 ); + optdata->substitutionTable = FT_NEXT_USHORT( p ); + } + + + static void + gxv_morx_subtable_type1_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[4]; + FT_ULong *l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->substitutionTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->substitutionTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_morx_subtable_type1_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_TRACE_VARS + FT_UShort setMark; + FT_UShort dontAdvance; +#endif + FT_UShort reserved; + FT_Short markIndex; + FT_Short currentIndex; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_UNUSED( state ); + FT_UNUSED( table ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_TRACE_VARS + setMark = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x3FFF ); + + markIndex = (FT_Short)( glyphOffset_p->ul >> 16 ); + currentIndex = (FT_Short)( glyphOffset_p->ul ); + + GXV_TRACE(( " setMark=%01d dontAdvance=%01d\n", + setMark, dontAdvance )); + + if ( 0 < reserved ) + { + GXV_TRACE(( " non-zero bits found in reserved range\n" )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); + } + + GXV_TRACE(( "markIndex = %d, currentIndex = %d\n", + markIndex, currentIndex )); + + if ( optdata->substitutionTable_num_lookupTables < markIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_UShort)( markIndex + 1 ); + + if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 ) + optdata->substitutionTable_num_lookupTables = + (FT_UShort)( currentIndex + 1 ); + } + + + static void + gxv_morx_subtable_type1_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + FT_UNUSED( glyph ); /* for the non-debugging case */ + + GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value_p->u )); + + if ( value_p->u > gxvalid->face->num_glyphs ) + FT_INVALID_GLYPH_ID; + } + + + static GXV_LookupValueDesc + gxv_morx_subtable_type1_LookupFmt4_transit( + FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /* + * TODO: length should be limit? + **/ + static void + gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort i; + + GXV_morx_subtable_type1_StateOptRecData optdata = + (GXV_morx_subtable_type1_StateOptRecData)gxvalid->xstatetable.optdata; + + + /* TODO: calculate offset/length for each lookupTables */ + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_morx_subtable_type1_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit; + + for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ ) + { + FT_ULong offset; + + + GXV_LIMIT_CHECK( 4 ); + offset = FT_NEXT_ULONG( p ); + + gxv_LookupTable_validate( table + offset, limit, gxvalid ); + } + + /* TODO: overlapping of lookupTables in substitutionTable */ + } + + + /* + * subtable for Contextual glyph substitution is a modified StateTable. + * In addition to classTable, stateArray, entryTable, the field + * `substitutionTable' is added. + */ + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type1_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type1_StateOptRec st_rec; + + + GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE ); + + st_rec.substitutionTable_num_lookupTables = 0; + + gxvalid->xstatetable.optdata = + &st_rec; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type1_substitutionTable_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type1_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type1_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + gxv_morx_subtable_type1_substitutionTable_validate( + table + st_rec.substitutionTable, + table + st_rec.substitutionTable + st_rec.substitutionTable_length, + gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx2.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx2.c new file mode 100644 index 00000000..faa09e90 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx2.c @@ -0,0 +1,331 @@ +/**************************************************************************** + * + * gxvmorx2.c + * + * TrueTypeGX/AAT morx table validation + * body for type2 (Ligature Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + typedef struct GXV_morx_subtable_type2_StateOptRec_ + { + FT_ULong ligActionTable; + FT_ULong componentTable; + FT_ULong ligatureTable; + FT_ULong ligActionTable_length; + FT_ULong componentTable_length; + FT_ULong ligatureTable_length; + + } GXV_morx_subtable_type2_StateOptRec, + *GXV_morx_subtable_type2_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \ + ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 ) + + + static void + gxv_morx_subtable_type2_opttable_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 + 4 + 4 ); + optdata->ligActionTable = FT_NEXT_ULONG( p ); + optdata->componentTable = FT_NEXT_ULONG( p ); + optdata->ligatureTable = FT_NEXT_ULONG( p ); + + GXV_TRACE(( "offset to ligActionTable=0x%08lx\n", + optdata->ligActionTable )); + GXV_TRACE(( "offset to componentTable=0x%08lx\n", + optdata->componentTable )); + GXV_TRACE(( "offset to ligatureTable=0x%08lx\n", + optdata->ligatureTable )); + } + + + static void + gxv_morx_subtable_type2_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[6]; + FT_ULong* l[6]; + FT_ULong buff[7]; + + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_NAME_ENTER( "subtable boundaries setup" ); + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->ligActionTable; + o[4] = optdata->componentTable; + o[5] = optdata->ligatureTable; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->ligActionTable_length); + l[4] = &(optdata->componentTable_length); + l[5] = &(optdata->ligatureTable_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, gxvalid ); + + GXV_TRACE(( "classTable: offset=0x%08lx length=0x%08lx\n", + classTable, *classTable_length_p )); + GXV_TRACE(( "stateArray: offset=0x%08lx length=0x%08lx\n", + stateArray, *stateArray_length_p )); + GXV_TRACE(( "entryTable: offset=0x%08lx length=0x%08lx\n", + entryTable, *entryTable_length_p )); + GXV_TRACE(( "ligActionTable: offset=0x%08lx length=0x%08lx\n", + optdata->ligActionTable, + optdata->ligActionTable_length )); + GXV_TRACE(( "componentTable: offset=0x%08lx length=0x%08lx\n", + optdata->componentTable, + optdata->componentTable_length )); + GXV_TRACE(( "ligatureTable: offset=0x%08lx length=0x%08lx\n", + optdata->ligatureTable, + optdata->ligatureTable_length )); + + GXV_EXIT; + } + + +#define GXV_MORX_LIGACTION_ENTRY_SIZE 4 + + + static void + gxv_morx_subtable_type2_ligActionIndex_validate( + FT_Bytes table, + FT_UShort ligActionIndex, + GXV_Validator gxvalid ) + { + /* access ligActionTable */ + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_Bytes lat_base = table + optdata->ligActionTable; + FT_Bytes p = lat_base + + ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE; + FT_Bytes lat_limit = lat_base + optdata->ligActionTable; + + + if ( p < lat_base ) + { + GXV_TRACE(( "p < lat_base (%ld byte rewind)\n", lat_base - p )); + FT_INVALID_OFFSET; + } + else if ( lat_limit < p ) + { + GXV_TRACE(( "lat_limit < p (%ld byte overrun)\n", p - lat_limit )); + FT_INVALID_OFFSET; + } + + { + /* validate entry in ligActionTable */ + FT_ULong lig_action; +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort last; + FT_UShort store; +#endif + FT_ULong offset; + FT_Long gid_limit; + + + lig_action = FT_NEXT_ULONG( p ); +#ifdef GXV_LOAD_UNUSED_VARS + last = (FT_UShort)( ( lig_action >> 31 ) & 1 ); + store = (FT_UShort)( ( lig_action >> 30 ) & 1 ); +#endif + + offset = lig_action & 0x3FFFFFFFUL; + + /* this offset is 30-bit signed value to add to GID */ + /* it is different from the location offset in mort */ + if ( ( offset & 0x3FFF0000UL ) == 0x3FFF0000UL ) + { /* negative offset */ + gid_limit = gxvalid->face->num_glyphs - + (FT_Long)( offset & 0x0000FFFFUL ); + if ( gid_limit > 0 ) + return; + + GXV_TRACE(( "ligature action table includes" + " too negative offset moving all GID" + " below defined range: 0x%04lx\n", + offset & 0xFFFFU )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + else if ( ( offset & 0x3FFF0000UL ) == 0x00000000UL ) + { /* positive offset */ + if ( (FT_Long)offset < gxvalid->face->num_glyphs ) + return; + + GXV_TRACE(( "ligature action table includes" + " too large offset moving all GID" + " over defined range: 0x%04lx\n", + offset & 0xFFFFU )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + + GXV_TRACE(( "ligature action table includes" + " invalid offset to add to 16-bit GID:" + " 0x%08lx\n", offset )); + GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); + } + } + + + static void + gxv_morx_subtable_type2_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_UShort setComponent; + FT_UShort dontAdvance; + FT_UShort performAction; +#endif + FT_UShort reserved; + FT_UShort ligActionIndex; + + FT_UNUSED( state ); + FT_UNUSED( limit ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setComponent = (FT_UShort)( ( flags >> 15 ) & 1 ); + dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 ); + performAction = (FT_UShort)( ( flags >> 13 ) & 1 ); +#endif + + reserved = (FT_UShort)( flags & 0x1FFF ); + ligActionIndex = glyphOffset_p->u; + + if ( reserved > 0 ) + GXV_TRACE(( " reserved 14bit is non-zero\n" )); + + if ( 0 < ligActionIndex ) + gxv_morx_subtable_type2_ligActionIndex_validate( + table, ligActionIndex, gxvalid ); + } + + + static void + gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes table, + GXV_Validator gxvalid ) + { + GXV_morx_subtable_type2_StateOptRecData optdata = + (GXV_morx_subtable_type2_StateOptRecData)gxvalid->xstatetable.optdata; + + FT_Bytes p = table + optdata->ligatureTable; + FT_Bytes limit = table + optdata->ligatureTable + + optdata->ligatureTable_length; + + + GXV_NAME_ENTER( "morx chain subtable type2 - substitutionTable" ); + + if ( 0 != optdata->ligatureTable ) + { + /* Apple does not give specification of ligatureTable format */ + while ( p < limit ) + { + FT_UShort lig_gid; + + + GXV_LIMIT_CHECK( 2 ); + lig_gid = FT_NEXT_USHORT( p ); + if ( lig_gid < gxvalid->face->num_glyphs ) + GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); + } + } + + GXV_EXIT; + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type2_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type2_StateOptRec lig_rec; + + + GXV_NAME_ENTER( "morx chain subtable type2 (Ligature Substitution)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = + &lig_rec; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type2_opttable_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type2_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_USHORT; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type2_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + +#if 0 + p += gxvalid->subtable_length; +#endif + gxv_morx_subtable_type2_ligatureTable_validate( table, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx4.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx4.c new file mode 100644 index 00000000..40468b84 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx4.c @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * gxvmorx4.c + * + * TrueTypeGX/AAT morx table validation + * body for "morx" type4 (Non-Contextual Glyph Substitution) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type4_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + GXV_NAME_ENTER( "morx chain subtable type4 " + "(Non-Contextual Glyph Substitution)" ); + + gxv_mort_subtable_type4_validate( table, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvmorx5.c b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx5.c new file mode 100644 index 00000000..a3dbdd43 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvmorx5.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * + * gxvmorx5.c + * + * TrueTypeGX/AAT morx table validation + * body for type5 (Contextual Glyph Insertion) subtable. + * + * Copyright (C) 2005-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvmorx.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvmorx + + + /* + * `morx' subtable type5 (Contextual Glyph Insertion) + * has format of a StateTable with insertion-glyph-list + * without name. However, the 32bit offset from the head + * of subtable to the i-g-l is given after `entryTable', + * without variable name specification (the existence of + * this offset to the table is different from mort type5). + */ + + + typedef struct GXV_morx_subtable_type5_StateOptRec_ + { + FT_ULong insertionGlyphList; + FT_ULong insertionGlyphList_length; + + } GXV_morx_subtable_type5_StateOptRec, + *GXV_morx_subtable_type5_StateOptRecData; + + +#define GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE \ + ( GXV_STATETABLE_HEADER_SIZE + 4 ) + + + static void + gxv_morx_subtable_type5_insertionGlyphList_load( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)gxvalid->xstatetable.optdata; + + + GXV_LIMIT_CHECK( 4 ); + optdata->insertionGlyphList = FT_NEXT_ULONG( p ); + } + + + static void + gxv_morx_subtable_type5_subtable_setup( FT_ULong table_size, + FT_ULong classTable, + FT_ULong stateArray, + FT_ULong entryTable, + FT_ULong* classTable_length_p, + FT_ULong* stateArray_length_p, + FT_ULong* entryTable_length_p, + GXV_Validator gxvalid ) + { + FT_ULong o[4]; + FT_ULong* l[4]; + FT_ULong buff[5]; + + GXV_morx_subtable_type5_StateOptRecData optdata = + (GXV_morx_subtable_type5_StateOptRecData)gxvalid->xstatetable.optdata; + + + o[0] = classTable; + o[1] = stateArray; + o[2] = entryTable; + o[3] = optdata->insertionGlyphList; + l[0] = classTable_length_p; + l[1] = stateArray_length_p; + l[2] = entryTable_length_p; + l[3] = &(optdata->insertionGlyphList_length); + + gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, gxvalid ); + } + + + static void + gxv_morx_subtable_type5_InsertList_validate( FT_UShort table_index, + FT_UShort count, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table + table_index * 2; + + +#ifndef GXV_LOAD_TRACE_VARS + GXV_LIMIT_CHECK( count * 2 ); +#else + while ( p < table + count * 2 + table_index * 2 ) + { + FT_UShort insert_glyphID; + + + GXV_LIMIT_CHECK( 2 ); + insert_glyphID = FT_NEXT_USHORT( p ); + GXV_TRACE(( " 0x%04x", insert_glyphID )); + } + + GXV_TRACE(( "\n" )); +#endif + } + + + static void + gxv_morx_subtable_type5_entry_validate( + FT_UShort state, + FT_UShort flags, + GXV_StateTable_GlyphOffsetCPtr glyphOffset_p, + FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { +#ifdef GXV_LOAD_UNUSED_VARS + FT_Bool setMark; + FT_Bool dontAdvance; + FT_Bool currentIsKashidaLike; + FT_Bool markedIsKashidaLike; + FT_Bool currentInsertBefore; + FT_Bool markedInsertBefore; +#endif + FT_Byte currentInsertCount; + FT_Byte markedInsertCount; + FT_Byte currentInsertList; + FT_UShort markedInsertList; + + FT_UNUSED( state ); + + +#ifdef GXV_LOAD_UNUSED_VARS + setMark = FT_BOOL( ( flags >> 15 ) & 1 ); + dontAdvance = FT_BOOL( ( flags >> 14 ) & 1 ); + currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 ); + markedIsKashidaLike = FT_BOOL( ( flags >> 12 ) & 1 ); + currentInsertBefore = FT_BOOL( ( flags >> 11 ) & 1 ); + markedInsertBefore = FT_BOOL( ( flags >> 10 ) & 1 ); +#endif + + currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F ); + markedInsertCount = (FT_Byte)( flags & 0x001F ); + + currentInsertList = (FT_Byte) ( glyphOffset_p->ul >> 16 ); + markedInsertList = (FT_UShort)( glyphOffset_p->ul ); + + if ( currentInsertList && 0 != currentInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( currentInsertList, + currentInsertCount, + table, limit, + gxvalid ); + + if ( markedInsertList && 0 != markedInsertCount ) + gxv_morx_subtable_type5_InsertList_validate( markedInsertList, + markedInsertCount, + table, limit, + gxvalid ); + } + + + FT_LOCAL_DEF( void ) + gxv_morx_subtable_type5_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + GXV_morx_subtable_type5_StateOptRec et_rec; + GXV_morx_subtable_type5_StateOptRecData et = &et_rec; + + + GXV_NAME_ENTER( "morx chain subtable type5 (Glyph Insertion)" ); + + GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE ); + + gxvalid->xstatetable.optdata = + et; + gxvalid->xstatetable.optdata_load_func = + gxv_morx_subtable_type5_insertionGlyphList_load; + gxvalid->xstatetable.subtable_setup_func = + gxv_morx_subtable_type5_subtable_setup; + gxvalid->xstatetable.entry_glyphoffset_fmt = + GXV_GLYPHOFFSET_ULONG; + gxvalid->xstatetable.entry_validate_func = + gxv_morx_subtable_type5_entry_validate; + + gxv_XStateTable_validate( p, limit, gxvalid ); + + GXV_EXIT; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvopbd.c b/Dependencies/freetype/freetype/src/gxvalid/gxvopbd.c new file mode 100644 index 00000000..98b5bb87 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvopbd.c @@ -0,0 +1,218 @@ +/**************************************************************************** + * + * gxvopbd.c + * + * TrueTypeGX/AAT opbd table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvopbd + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct GXV_opbd_DataRec_ + { + FT_UShort format; + FT_UShort valueOffset_min; + + } GXV_opbd_DataRec, *GXV_opbd_Data; + + +#define GXV_OPBD_DATA( FIELD ) GXV_TABLE_DATA( opbd, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_opbd_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + /* offset in LookupTable is measured from the head of opbd table */ + FT_Bytes p = gxvalid->root->base + value_p->u; + FT_Bytes limit = gxvalid->root->limit; + FT_Short delta_value; + int i; + + + if ( value_p->u < GXV_OPBD_DATA( valueOffset_min ) ) + GXV_OPBD_DATA( valueOffset_min ) = value_p->u; + + for ( i = 0; i < 4; i++ ) + { + GXV_LIMIT_CHECK( 2 ); + delta_value = FT_NEXT_SHORT( p ); + + if ( GXV_OPBD_DATA( format ) ) /* format 1, value is ctrl pt. */ + { + if ( delta_value == -1 ) + continue; + + gxv_ctlPoint_validate( glyph, (FT_UShort)delta_value, gxvalid ); + } + else /* format 0, value is distance */ + continue; + } + } + + + /* + opbd ---------------------+ + | + +===============+ | + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of opbd sfnt table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 4 * sizeof(FT_Short) [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + .... | + | + 48bit value array | + +===============+ | + | value | <-------+ + | | + | | + | | + +---------------+ + .... */ + + static GXV_LookupValueDesc + gxv_opbd_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + GXV_LookupValueDesc value; + + FT_UNUSED( lookuptbl_limit ); + FT_UNUSED( gxvalid ); + + /* XXX: check range? */ + value.u = (FT_UShort)( base_value_p->u + + relative_gindex * 4 * sizeof ( FT_Short ) ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** opbd TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_opbd_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_opbd_DataRec opbdrec; + GXV_opbd_Data opbd = &opbdrec; + FT_Bytes p = table; + FT_Bytes limit = 0; + + FT_ULong version; + + + gxvalid->root = ftvalid; + gxvalid->table_data = opbd; + gxvalid->face = face; + + FT_TRACE3(( "validating `opbd' table\n" )); + GXV_INIT; + GXV_OPBD_DATA( valueOffset_min ) = 0xFFFFU; + + + GXV_LIMIT_CHECK( 4 + 2 ); + version = FT_NEXT_ULONG( p ); + GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p ); + + + /* only 0x00010000 is defined (1996) */ + GXV_TRACE(( "(version=0x%08lx)\n", version )); + if ( 0x00010000UL != version ) + FT_INVALID_FORMAT; + + /* only values 0 and 1 are defined (1996) */ + GXV_TRACE(( "(format=0x%04x)\n", GXV_OPBD_DATA( format ) )); + if ( 0x0001 < GXV_OPBD_DATA( format ) ) + FT_INVALID_FORMAT; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_opbd_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_opbd_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + p += gxvalid->subtable_length; + + if ( p > table + GXV_OPBD_DATA( valueOffset_min ) ) + { + GXV_TRACE(( + "found overlap between LookupTable and opbd_value array\n" )); + FT_INVALID_OFFSET; + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvprop.c b/Dependencies/freetype/freetype/src/gxvalid/gxvprop.c new file mode 100644 index 00000000..e485fa66 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvprop.c @@ -0,0 +1,330 @@ +/**************************************************************************** + * + * gxvprop.c + * + * TrueTypeGX/AAT prop table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvprop + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define GXV_PROP_HEADER_SIZE ( 4 + 2 + 2 ) +#define GXV_PROP_SIZE_MIN GXV_PROP_HEADER_SIZE + + typedef struct GXV_prop_DataRec_ + { + FT_Fixed version; + + } GXV_prop_DataRec, *GXV_prop_Data; + +#define GXV_PROP_DATA( field ) GXV_TABLE_DATA( prop, field ) + +#define GXV_PROP_FLOATER 0x8000U +#define GXV_PROP_USE_COMPLEMENTARY_BRACKET 0x1000U +#define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00U +#define GXV_PROP_ATTACHING_TO_RIGHT 0x0080U +#define GXV_PROP_RESERVED 0x0060U +#define GXV_PROP_DIRECTIONALITY_CLASS 0x001FU + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_prop_zero_advance_validate( FT_UShort gid, + GXV_Validator gxvalid ) + { + FT_Face face; + FT_Error error; + FT_GlyphSlot glyph; + + + GXV_NAME_ENTER( "zero advance" ); + + face = gxvalid->face; + + error = FT_Load_Glyph( face, + gid, + FT_LOAD_IGNORE_TRANSFORM ); + if ( error ) + FT_INVALID_GLYPH_ID; + + glyph = face->glyph; + + if ( glyph->advance.x != (FT_Pos)0 || + glyph->advance.y != (FT_Pos)0 ) + { + GXV_TRACE(( " found non-zero advance in zero-advance glyph\n" )); + FT_INVALID_DATA; + } + + GXV_EXIT; + } + + + /* Pass 0 as GLYPH to check the default property */ + static void + gxv_prop_property_validate( FT_UShort property, + FT_UShort glyph, + GXV_Validator gxvalid ) + { + if ( glyph != 0 && ( property & GXV_PROP_FLOATER ) ) + gxv_prop_zero_advance_validate( glyph, gxvalid ); + + if ( property & GXV_PROP_USE_COMPLEMENTARY_BRACKET ) + { + FT_UShort offset; + char complement; + + + offset = (FT_UShort)( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ); + if ( offset == 0 ) + { + GXV_TRACE(( " found zero offset to property\n" )); + FT_INVALID_OFFSET; + } + + complement = (char)( offset >> 8 ); + if ( complement & 0x08 ) + { + /* Top bit is set: negative */ + + /* Calculate the absolute offset */ + complement = (char)( ( complement & 0x07 ) + 1 ); + + /* The gid for complement must be greater than 0 */ + if ( glyph <= complement ) + { + GXV_TRACE(( " found non-positive glyph complement\n" )); + FT_INVALID_DATA; + } + } + else + { + /* The gid for complement must be the face. */ + gxv_glyphid_validate( (FT_UShort)( glyph + complement ), gxvalid ); + } + } + else + { + if ( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET ) + GXV_TRACE(( "glyph %d cannot have complementary bracketing\n", + glyph )); + } + + /* this is introduced in version 2.0 */ + if ( property & GXV_PROP_ATTACHING_TO_RIGHT ) + { + if ( GXV_PROP_DATA( version ) == 0x00010000UL ) + { + GXV_TRACE(( " found older version (1.0) in new version table\n" )); + FT_INVALID_DATA; + } + } + + if ( property & GXV_PROP_RESERVED ) + { + GXV_TRACE(( " found non-zero bits in reserved bits\n" )); + FT_INVALID_DATA; + } + + if ( ( property & GXV_PROP_DIRECTIONALITY_CLASS ) > 11 ) + { + /* TODO: Too restricted. Use the validation level. */ + if ( GXV_PROP_DATA( version ) == 0x00010000UL || + GXV_PROP_DATA( version ) == 0x00020000UL ) + { + GXV_TRACE(( " found too old version in directionality class\n" )); + FT_INVALID_DATA; + } + } + } + + + static void + gxv_prop_LookupValue_validate( FT_UShort glyph, + GXV_LookupValueCPtr value_p, + GXV_Validator gxvalid ) + { + gxv_prop_property_validate( value_p->u, glyph, gxvalid ); + } + + + /* + +===============+ --------+ + | lookup header | | + +===============+ | + | BinSrchHeader | | + +===============+ | + | lastGlyph[0] | | + +---------------+ | + | firstGlyph[0] | | head of lookup table + +---------------+ | + + | offset[0] | -> | offset [byte] + +===============+ | + + | lastGlyph[1] | | (glyphID - firstGlyph) * 2 [byte] + +---------------+ | + | firstGlyph[1] | | + +---------------+ | + | offset[1] | | + +===============+ | + | + ... | + | + 16bit value array | + +===============+ | + | value | <-------+ + ... + */ + + static GXV_LookupValueDesc + gxv_prop_LookupFmt4_transit( FT_UShort relative_gindex, + GXV_LookupValueCPtr base_value_p, + FT_Bytes lookuptbl_limit, + GXV_Validator gxvalid ) + { + FT_Bytes p; + FT_Bytes limit; + FT_UShort offset; + GXV_LookupValueDesc value; + + /* XXX: check range? */ + offset = (FT_UShort)( base_value_p->u + + relative_gindex * sizeof ( FT_UShort ) ); + p = gxvalid->lookuptbl_head + offset; + limit = lookuptbl_limit; + + GXV_LIMIT_CHECK ( 2 ); + value.u = FT_NEXT_USHORT( p ); + + return value; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** prop TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_prop_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + + GXV_prop_DataRec proprec; + GXV_prop_Data prop = &proprec; + + FT_Fixed version; + FT_UShort format; + FT_UShort defaultProp; + + + gxvalid->root = ftvalid; + gxvalid->table_data = prop; + gxvalid->face = face; + + FT_TRACE3(( "validating `prop' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 ); + version = FT_NEXT_LONG( p ); + format = FT_NEXT_USHORT( p ); + defaultProp = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " version 0x%08lx\n", version )); + GXV_TRACE(( " format 0x%04x\n", format )); + GXV_TRACE(( " defaultProp 0x%04x\n", defaultProp )); + + /* only versions 1.0, 2.0, 3.0 are defined (1996) */ + if ( version != 0x00010000UL && + version != 0x00020000UL && + version != 0x00030000UL ) + { + GXV_TRACE(( " found unknown version\n" )); + FT_INVALID_FORMAT; + } + + + /* only formats 0x0000, 0x0001 are defined (1996) */ + if ( format > 1 ) + { + GXV_TRACE(( " found unknown format\n" )); + FT_INVALID_FORMAT; + } + + gxv_prop_property_validate( defaultProp, 0, gxvalid ); + + if ( format == 0 ) + { + FT_TRACE3(( "(format 0, no per-glyph properties, " + "remaining %ld bytes are skipped)", limit - p )); + goto Exit; + } + + /* format == 1 */ + GXV_PROP_DATA( version ) = version; + + gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED; + gxvalid->lookupval_func = gxv_prop_LookupValue_validate; + gxvalid->lookupfmt4_trans = gxv_prop_LookupFmt4_transit; + + gxv_LookupTable_validate( p, limit, gxvalid ); + + Exit: + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gxvalid/gxvtrak.c b/Dependencies/freetype/freetype/src/gxvalid/gxvtrak.c new file mode 100644 index 00000000..a402823a --- /dev/null +++ b/Dependencies/freetype/freetype/src/gxvalid/gxvtrak.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * gxvtrak.c + * + * TrueTypeGX/AAT trak table validation (body). + * + * Copyright (C) 2004-2024 by + * suzuki toshiya, Masatake YAMATO, Red Hat K.K., + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +/**************************************************************************** + * + * gxvalid is derived from both gxlayout module and otvalid module. + * Development of gxlayout is supported by the Information-technology + * Promotion Agency(IPA), Japan. + * + */ + + +#include "gxvalid.h" +#include "gxvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT gxvtrak + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Data and Types *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + * referred track table format specification: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html + * last update was 1996. + * ---------------------------------------------- + * [MINIMUM HEADER]: GXV_TRAK_SIZE_MIN + * version (fixed: 32bit) = 0x00010000 + * format (uint16: 16bit) = 0 is only defined (1996) + * horizOffset (uint16: 16bit) + * vertOffset (uint16: 16bit) + * reserved (uint16: 16bit) = 0 + * ---------------------------------------------- + * [VARIABLE BODY]: + * horizData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + * vertData + * header ( 2 + 2 + 4 + * trackTable + nTracks * ( 4 + 2 + 2 ) + * sizeTable + nSizes * 4 ) + * ---------------------------------------------- + */ + typedef struct GXV_trak_DataRec_ + { + FT_UShort trackValueOffset_min; + FT_UShort trackValueOffset_max; + + } GXV_trak_DataRec, *GXV_trak_Data; + + +#define GXV_TRAK_DATA( FIELD ) GXV_TABLE_DATA( trak, FIELD ) + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + gxv_trak_trackTable_validate( FT_Bytes table, + FT_Bytes limit, + FT_UShort nTracks, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + + FT_Fixed track, t; + FT_UShort nameIndex; + FT_UShort offset; + FT_UShort i, j; + + + GXV_NAME_ENTER( "trackTable" ); + + GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU; + GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000; + + GXV_LIMIT_CHECK( nTracks * ( 4 + 2 + 2 ) ); + + for ( i = 0; i < nTracks; i++ ) + { + p = table + i * ( 4 + 2 + 2 ); + track = FT_NEXT_LONG( p ); + nameIndex = FT_NEXT_USHORT( p ); + offset = FT_NEXT_USHORT( p ); + + if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) ) + GXV_TRAK_DATA( trackValueOffset_min ) = offset; + if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) ) + GXV_TRAK_DATA( trackValueOffset_max ) = offset; + + gxv_sfntName_validate( nameIndex, 256, 32767, gxvalid ); + + for ( j = i; j < nTracks; j++ ) + { + p = table + j * ( 4 + 2 + 2 ); + t = FT_NEXT_LONG( p ); + if ( t == track ) + GXV_TRACE(( "duplicated entries found for track value 0x%lx\n", + track )); + } + } + + gxvalid->subtable_length = (FT_ULong)( p - table ); + GXV_EXIT; + } + + + static void + gxv_trak_trackData_validate( FT_Bytes table, + FT_Bytes limit, + GXV_Validator gxvalid ) + { + FT_Bytes p = table; + FT_UShort nTracks; + FT_UShort nSizes; + FT_ULong sizeTableOffset; + + GXV_ODTECT( 4, odtect ); + + + GXV_ODTECT_INIT( odtect ); + GXV_NAME_ENTER( "trackData" ); + + /* read the header of trackData */ + GXV_LIMIT_CHECK( 2 + 2 + 4 ); + nTracks = FT_NEXT_USHORT( p ); + nSizes = FT_NEXT_USHORT( p ); + sizeTableOffset = FT_NEXT_ULONG( p ); + + gxv_odtect_add_range( table, (FT_ULong)( p - table ), + "trackData header", odtect ); + + /* validate trackTable */ + gxv_trak_trackTable_validate( p, limit, nTracks, gxvalid ); + gxv_odtect_add_range( p, gxvalid->subtable_length, + "trackTable", odtect ); + + /* sizeTable is array of FT_Fixed, don't check contents */ + p = gxvalid->root->base + sizeTableOffset; + GXV_LIMIT_CHECK( nSizes * 4 ); + gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect ); + + /* validate trackValueOffet */ + p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_min ); + if ( limit - p < nTracks * nSizes * 2 ) + GXV_TRACE(( "too short trackValue array\n" )); + + p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_max ); + GXV_LIMIT_CHECK( nSizes * 2 ); + + gxv_odtect_add_range( gxvalid->root->base + + GXV_TRAK_DATA( trackValueOffset_min ), + GXV_TRAK_DATA( trackValueOffset_max ) + - GXV_TRAK_DATA( trackValueOffset_min ) + + nSizes * 2, + "trackValue array", odtect ); + + gxv_odtect_validate( odtect, gxvalid ); + + GXV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** trak TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + gxv_trak_validate( FT_Bytes table, + FT_Face face, + FT_Validator ftvalid ) + { + FT_Bytes p = table; + FT_Bytes limit = 0; + + GXV_ValidatorRec gxvalidrec; + GXV_Validator gxvalid = &gxvalidrec; + GXV_trak_DataRec trakrec; + GXV_trak_Data trak = &trakrec; + + FT_ULong version; + FT_UShort format; + FT_UShort horizOffset; + FT_UShort vertOffset; + FT_UShort reserved; + + + GXV_ODTECT( 3, odtect ); + + GXV_ODTECT_INIT( odtect ); + gxvalid->root = ftvalid; + gxvalid->table_data = trak; + gxvalid->face = face; + + limit = gxvalid->root->limit; + + FT_TRACE3(( "validating `trak' table\n" )); + GXV_INIT; + + GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 ); + version = FT_NEXT_ULONG( p ); + format = FT_NEXT_USHORT( p ); + horizOffset = FT_NEXT_USHORT( p ); + vertOffset = FT_NEXT_USHORT( p ); + reserved = FT_NEXT_USHORT( p ); + + GXV_TRACE(( " (version = 0x%08lx)\n", version )); + GXV_TRACE(( " (format = 0x%04x)\n", format )); + GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset )); + GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset )); + GXV_TRACE(( " (reserved = 0x%04x)\n", reserved )); + + /* Version 1.0 (always:1996) */ + if ( version != 0x00010000UL ) + FT_INVALID_FORMAT; + + /* format 0 (always:1996) */ + if ( format != 0x0000 ) + FT_INVALID_FORMAT; + + GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset ); + GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset ); + + /* Reserved Fixed Value (always) */ + if ( reserved != 0x0000 ) + FT_INVALID_DATA; + + /* validate trackData */ + if ( 0 < horizOffset ) + { + gxv_trak_trackData_validate( table + horizOffset, limit, gxvalid ); + gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length, + "horizJustData", odtect ); + } + + if ( 0 < vertOffset ) + { + gxv_trak_trackData_validate( table + vertOffset, limit, gxvalid ); + gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length, + "vertJustData", odtect ); + } + + gxv_odtect_validate( odtect, gxvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gzip/README.freetype b/Dependencies/freetype/freetype/src/gzip/README.freetype new file mode 100644 index 00000000..29304308 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/README.freetype @@ -0,0 +1,22 @@ +Name: zlib +Short Name: zlib +URL: http://zlib.net/ +Version: 1.3 +License: see `zlib.h` + +Description: +"A massively spiffy yet delicately unobtrusive compression library." + +'zlib' is a free, general-purpose, legally unencumbered lossless +data-compression library. 'zlib' implements the "deflate" compression +algorithm described by RFC 1951, which combines the LZ77 (Lempel-Ziv) +algorithm with Huffman coding. zlib also implements the zlib (RFC 1950) and +gzip (RFC 1952) wrapper formats. + +Local Modifications: +The files in this directory have been prepared as follows. + + - Take the unmodified source code files from the zlib distribution that are + included by `ftgzip.c`. + - Copy `zconf.h` to `ftzconf.h` (which stays unmodified otherwise). + - Apply the diff file(s) in the `patches` folder. diff --git a/Dependencies/freetype/freetype/src/gzip/adler32.c b/Dependencies/freetype/freetype/src/gzip/adler32.c new file mode 100644 index 00000000..260185b6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/adler32.c @@ -0,0 +1,168 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { + return adler32_z(adler, buf, len); +} + +#ifndef Z_FREETYPE + +/* ========================================================================= */ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); +} + +#endif /* !Z_FREETYPE */ diff --git a/Dependencies/freetype/freetype/src/gzip/crc32.c b/Dependencies/freetype/freetype/src/gzip/crc32.c new file mode 100644 index 00000000..27487dcc --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/crc32.c @@ -0,0 +1,1061 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ + + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif + +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap(z_word_t word) { +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + +#ifndef Z_FREETYPE + +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#endif /* !Z_FREETYPE */ + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ +local z_crc_t FAR crc_table[256]; +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid(z_crc_t [][256], z_word_t [][256], int, int); +#endif +#ifdef MAKECRCH + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); +#endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(once_t *state, void (*init)(void)) { + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set(int volatile *flag) { + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(once_t *state, void (*init)(void)) { + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. + */ + +local void make_crc_table(void) { + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif + } + + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + +#ifdef MAKECRCH + { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif + FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); + } + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main(void) { + make_crc_table(); + return 0; +} + +#endif /* MAKECRCH */ + +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } +} +#endif + +#endif /* DYNAMIC_CRC_TABLE */ + +#ifndef Z_FREETYPE + +/* ========================================================================= + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. + */ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +#endif /* !Z_FREETYPE */ + +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 + +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; + } + + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#else + +#ifdef W + +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +local z_crc_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} + +local z_word_t crc_word_big(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + +#ifdef W + + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { + return crc32_z(crc, buf, len); +} + +#ifndef Z_FREETYPE + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + return crc32_combine_gen64((z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); +} + +#endif /* !Z_FREETYPE */ diff --git a/Dependencies/freetype/freetype/src/gzip/crc32.h b/Dependencies/freetype/freetype/src/gzip/crc32.h new file mode 100644 index 00000000..137df68d --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/crc32.h @@ -0,0 +1,9446 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +local const z_word_t FAR crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#if N == 1 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif + +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + +#endif + +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif + +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif + +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif + +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif + +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; diff --git a/Dependencies/freetype/freetype/src/gzip/ftgzip.c b/Dependencies/freetype/freetype/src/gzip/ftgzip.c new file mode 100644 index 00000000..f77377ef --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/ftgzip.c @@ -0,0 +1,805 @@ +/**************************************************************************** + * + * ftgzip.c + * + * FreeType support for .gz compressed files. + * + * This optional component relies on zlib. It should mainly be used to + * parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Gzip_Err_ +#define FT_ERR_BASE FT_Mod_Err_Gzip + +#include + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + +#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB + +#include + +#else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + /* In this case, we include our own modified sources of the ZLib */ + /* within the `gzip' component. The modifications were necessary */ + /* to #include all files without conflicts, as well as preventing */ + /* the definition of `extern' functions that may cause linking */ + /* conflicts when a program is linked with both FreeType and the */ + /* original ZLib. */ + +#ifndef USE_ZLIB_ZCALLOC +#define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutil.c */ +#endif + + /* Note that our `zlib.h' includes `ftzconf.h' instead of `zconf.h'; */ + /* the main reason is that even a global `zlib.h' includes `zconf.h' */ + /* with */ + /* */ + /* #include "zconf.h" */ + /* */ + /* instead of the expected */ + /* */ + /* #include */ + /* */ + /* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */ + /* include the wrong `zconf.h' file, leading to errors. */ + +#define ZEXPORT + /* prevent zlib functions from being visible outside their object files */ +#define ZEXTERN static + +#define HAVE_MEMCPY 1 +#define Z_SOLO 1 +#define Z_FREETYPE 1 + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `conversion from XXX to YYY, */ + /* possible loss of data' in order to compile cleanly with */ + /* the maximum level of warnings: zlib is non-FreeType */ + /* code. */ +#pragma warning( push ) +#pragma warning( disable : 4244 ) +#endif /* _MSC_VER */ + +#if defined( __GNUC__ ) +#pragma GCC diagnostic push +#ifndef __cplusplus +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include "zutil.c" +#include "inffast.c" +#include "inflate.c" +#include "inftrees.c" +#include "adler32.c" +#include "crc32.c" + +#if defined( __GNUC__ ) +#pragma GCC diagnostic pop +#endif + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */ + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + static voidpf + ft_gzip_alloc( voidpf opaque, + uInt items, + uInt size ) + { + FT_Memory memory = (FT_Memory)opaque; + FT_ULong sz = (FT_ULong)size * items; + FT_Error error; + FT_Pointer p = NULL; + + + /* allocate and zero out */ + FT_MEM_ALLOC( p, sz ); + return p; + } + + + static void + ft_gzip_free( voidpf opaque, + voidpf address ) + { + FT_Memory memory = (FT_Memory)opaque; + + + FT_MEM_FREE( address ); + } + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** Z L I B F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_GZIP_BUFFER_SIZE 4096 + + typedef struct FT_GZipFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + z_stream zstream; /* zlib input stream */ + + FT_ULong start; /* starting position, after .gz header */ + FT_Byte input[FT_GZIP_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_GZIP_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_GZipFileRec, *FT_GZipFile; + + + /* gzip flag byte */ +#define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */ +#define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */ + + + /* check and skip .gz header - we don't support `transparent' compression */ + static FT_Error + ft_gzip_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the method, and head[3] the flags */ + if ( head[0] != 0x1F || + head[1] != 0x8B || + head[2] != Z_DEFLATED || + (head[3] & FT_GZIP_RESERVED) ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* skip time, xflags and os code */ + (void)FT_STREAM_SKIP( 6 ); + + /* skip the extra field */ + if ( head[3] & FT_GZIP_EXTRA_FIELD ) + { + FT_UInt len; + + + if ( FT_READ_USHORT_LE( len ) || + FT_STREAM_SKIP( len ) ) + goto Exit; + } + + /* skip original file name */ + if ( head[3] & FT_GZIP_ORIG_NAME ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip .gz comment */ + if ( head[3] & FT_GZIP_COMMENT ) + for (;;) + { + FT_UInt c; + + + if ( FT_READ_BYTE( c ) ) + goto Exit; + + if ( c == 0 ) + break; + } + + /* skip CRC */ + if ( head[3] & FT_GZIP_HEAD_CRC ) + if ( FT_STREAM_SKIP( 2 ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + ft_gzip_file_init( FT_GZipFile zip, + FT_Stream stream, + FT_Stream source ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = FT_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .gz header */ + { + stream = source; + + error = ft_gzip_check_header( stream ); + if ( error ) + goto Exit; + + zip->start = FT_STREAM_POS(); + } + + /* initialize zlib -- there is no zlib header in the compressed stream */ + zstream->zalloc = ft_gzip_alloc; + zstream->zfree = ft_gzip_free; + zstream->opaque = stream->memory; + + zstream->avail_in = 0; + zstream->next_in = zip->buffer; + + if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK || + !zstream->next_in ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static void + ft_gzip_file_done( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + + + inflateEnd( zstream ); + + /* clear the rest */ + zstream->zalloc = NULL; + zstream->zfree = NULL; + zstream->opaque = NULL; + zstream->next_in = NULL; + zstream->next_out = NULL; + zstream->avail_in = 0; + zstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_gzip_file_reset( FT_GZipFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( zip->start ) ) + { + z_stream* zstream = &zip->zstream; + + + inflateReset( zstream ); + + zstream->avail_in = 0; + zstream->next_in = zip->input; + zstream->avail_out = 0; + zstream->next_out = zip->buffer; + + zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_gzip_file_fill_input( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_GZIP_BUFFER_SIZE ); + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + } + else + { + size = stream->size - stream->pos; + if ( size > FT_GZIP_BUFFER_SIZE ) + size = FT_GZIP_BUFFER_SIZE; + + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + zstream->next_in = zip->input; + zstream->avail_in = size; + + return FT_Err_Ok; + } + + + static FT_Error + ft_gzip_file_fill_output( FT_GZipFile zip ) + { + z_stream* zstream = &zip->zstream; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + zstream->next_out = zip->cursor; + zstream->avail_out = FT_GZIP_BUFFER_SIZE; + + while ( zstream->avail_out > 0 ) + { + int err; + + + if ( zstream->avail_in == 0 ) + { + error = ft_gzip_file_fill_input( zip ); + if ( error ) + break; + } + + err = inflate( zstream, Z_NO_FLUSH ); + + if ( err == Z_STREAM_END ) + { + zip->limit = zstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else if ( err != Z_OK ) + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */ + static FT_Error + ft_gzip_file_skip_output( FT_GZipFile zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + for (;;) + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_gzip_file_io( FT_GZipFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if we're seeking backwards. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos ) + { + error = ft_gzip_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_gzip_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** G Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_gzip_stream_close( FT_Stream stream ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize gzip file descriptor */ + ft_gzip_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + + if ( !stream->read ) + FT_FREE( stream->base ); + } + + + static unsigned long + ft_gzip_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_GZipFile zip = (FT_GZipFile)stream->descriptor.pointer; + + + return ft_gzip_file_io( zip, offset, buffer, count ); + } + + + static FT_ULong + ft_gzip_get_uncompressed_size( FT_Stream stream ) + { + FT_Error error; + FT_ULong old_pos; + FT_ULong result = 0; + + + old_pos = stream->pos; + if ( !FT_Stream_Seek( stream, stream->size - 4 ) ) + { + result = FT_Stream_ReadULongLE( stream, &error ); + if ( error ) + result = 0; + + (void)FT_Stream_Seek( stream, old_pos ); + } + + return result; + } + + + /* documentation is in ftgzip.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_GZipFile zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * check the header right now; this prevents allocating un-necessary + * objects when we don't need them + */ + error = ft_gzip_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_gzip_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + /* + * We use the following trick to try to dramatically improve the + * performance while dealing with small files. If the original stream + * size is less than a certain threshold, we try to load the whole font + * file into memory. This saves us from using the 32KB buffer needed + * to inflate the file, plus the two 4KB intermediate input/output + * buffers used in the `FT_GZipFile' structure. + */ + { + FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); + + + if ( zip_size != 0 && zip_size < 40 * 1024 ) + { + FT_Byte* zip_buff = NULL; + + + if ( !FT_QALLOC( zip_buff, zip_size ) ) + { + FT_ULong count; + + + count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); + if ( count == zip_size ) + { + ft_gzip_file_done( zip ); + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + + stream->size = zip_size; + stream->pos = 0; + stream->base = zip_buff; + stream->read = NULL; + stream->close = ft_gzip_stream_close; + + goto Exit; + } + + ft_gzip_file_io( zip, 0, NULL, 0 ); + FT_FREE( zip_buff ); + } + error = FT_Err_Ok; + } + + if ( zip_size ) + stream->size = zip_size; + else + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + } + + stream->pos = 0; + stream->base = NULL; + stream->read = ft_gzip_stream_io; + stream->close = ft_gzip_stream_close; + + Exit: + return error; + } + + + /* documentation is in ftgzip.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ) + { + z_stream stream; + int err; + + + /* check for `input' delayed to `inflate' */ + + if ( !memory || !output_len || !output ) + return FT_THROW( Invalid_Argument ); + + /* this function is modeled after zlib's `uncompress' function */ + + stream.next_in = (Bytef*)input; + stream.avail_in = (uInt)input_len; + + stream.next_out = output; + stream.avail_out = (uInt)*output_len; + + stream.zalloc = ft_gzip_alloc; + stream.zfree = ft_gzip_free; + stream.opaque = memory; + + err = inflateInit2( &stream, MAX_WBITS|32 ); + + if ( err != Z_OK ) + return FT_THROW( Invalid_Argument ); + + err = inflate( &stream, Z_FINISH ); + if ( err != Z_STREAM_END ) + { + inflateEnd( &stream ); + if ( err == Z_OK ) + err = Z_BUF_ERROR; + } + else + { + *output_len = stream.total_out; + + err = inflateEnd( &stream ); + } + + if ( err == Z_MEM_ERROR ) + return FT_THROW( Out_Of_Memory ); + + if ( err == Z_BUF_ERROR ) + return FT_THROW( Array_Too_Large ); + + if ( err == Z_DATA_ERROR ) + return FT_THROW( Invalid_Table ); + + if ( err == Z_NEED_DICT ) + return FT_THROW( Invalid_Table ); + + return FT_Err_Ok; + } + + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Gzip_Uncompress( FT_Memory memory, + FT_Byte* output, + FT_ULong* output_len, + const FT_Byte* input, + FT_ULong input_len ) + { + FT_UNUSED( memory ); + FT_UNUSED( output ); + FT_UNUSED( output_len ); + FT_UNUSED( input ); + FT_UNUSED( input_len ); + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/gzip/ftzconf.h b/Dependencies/freetype/freetype/src/gzip/ftzconf.h new file mode 100644 index 00000000..fb76ffe3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/ftzconf.h @@ -0,0 +1,551 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/Dependencies/freetype/freetype/src/gzip/gzguts.h b/Dependencies/freetype/freetype/src/gzip/gzguts.h new file mode 100644 index 00000000..f9a250b8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/gzguts.h @@ -0,0 +1,218 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc(uInt size); + extern void free(voidpf ptr); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY__ 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax(void); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/Dependencies/freetype/freetype/src/gzip/inffast.c b/Dependencies/freetype/freetype/src/gzip/inffast.c new file mode 100644 index 00000000..9354676e --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inffast.c @@ -0,0 +1,320 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/Dependencies/freetype/freetype/src/gzip/inffast.h b/Dependencies/freetype/freetype/src/gzip/inffast.h new file mode 100644 index 00000000..a38c5be4 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/Dependencies/freetype/freetype/src/gzip/inffixed.h b/Dependencies/freetype/freetype/src/gzip/inffixed.h new file mode 100644 index 00000000..d6283277 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/Dependencies/freetype/freetype/src/gzip/inflate.c b/Dependencies/freetype/freetype/src/gzip/inflate.c new file mode 100644 index 00000000..f7ed5d18 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inflate.c @@ -0,0 +1,1534 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +local int inflateStateCheck(z_streamp strm) { + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +#ifndef Z_FREETYPE + +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +#endif /* !Z_FREETYPE */ + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed(void) +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(z_streamp strm, int flush) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +#ifndef Z_FREETYPE + +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(z_streamp strm) { + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(z_streamp strm, int check) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} + +#endif /* !Z_FREETYPE */ diff --git a/Dependencies/freetype/freetype/src/gzip/inflate.h b/Dependencies/freetype/freetype/src/gzip/inflate.h new file mode 100644 index 00000000..8a0e437a --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inflate.h @@ -0,0 +1,131 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef INFLATE_H +#define INFLATE_H + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; + +#endif /* !INFLATE_H */ diff --git a/Dependencies/freetype/freetype/src/gzip/inftrees.c b/Dependencies/freetype/freetype/src/gzip/inftrees.c new file mode 100644 index 00000000..1fd65559 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inftrees.c @@ -0,0 +1,299 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2023 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +static const char inflate_copyright[] = + " inflate 1.3 Copyright 1995-2023 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/Dependencies/freetype/freetype/src/gzip/inftrees.h b/Dependencies/freetype/freetype/src/gzip/inftrees.h new file mode 100644 index 00000000..47f726c3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/inftrees.h @@ -0,0 +1,67 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef INFTREES_H +#define INFTREES_H + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +static int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); + +#endif /* !INFTREES_H */ diff --git a/Dependencies/freetype/freetype/src/gzip/patches/freetype-zlib.diff b/Dependencies/freetype/freetype/src/gzip/patches/freetype-zlib.diff new file mode 100644 index 00000000..9486bd02 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/patches/freetype-zlib.diff @@ -0,0 +1,451 @@ +[zlib] Fix zlib sources for compilation with FreeType + +We must ensure that they do not issue compiler errors or warnings when they +are compiled as part of `src/gzip/ftgzip.c`. + +* src/gzip/gzguts.h (COPY): Rename to... +(COPY__): ... this since `COPY` and `COPY_` conflict with enum values, +which have the same name in `zlib.h`. + +* src/gzip/inflate.c, src/gzip/adler32.c, src/gzip/crc32.c, +src/gzip/zutil.c: Omit unused function declarations and definitions when +`Z_FREETYPE` is defined. + +* src/gzip/inffast.h (inflate_fast): Declare as static. + +* src/gzip/inftrees.c (inflate_copyright): Declare as static. + +* src/gzip/zlib.h: Include `ftzconf.h` instead of `zconf.h` to avoid +conflicts with system-installed headers. +Omit unused function declarations when `Z_FREETYPE` is defined. +(inflateInit2)[Z_FREETYPE]: Provide proper declaration. + +* src/gzip/zutil.h: Use `ft_memxxx` functions instead of `memxxx`. +Omit unused function declarations when `Z_FREETYPE` is defined. + +* src/gzip/inflate.h, src/gzip/inftrees.h: Add header guard macros to +prevent compiler errors. + +* src/gzip/inftrees.h: Add header guard macros to prevent compiler errors. +(inflate_table): Declare as static. + +diff --git b/src/gzip/adler32.c a/src/gzip/adler32.c +index 04b81d29b..260185b67 100644 +--- b/src/gzip/adler32.c ++++ a/src/gzip/adler32.c +@@ -129,6 +129,8 @@ uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { + return adler32_z(adler, buf, len); + } + ++#ifndef Z_FREETYPE ++ + /* ========================================================================= */ + local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { + unsigned long sum1; +@@ -162,3 +164,5 @@ uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { + uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); + } ++ ++#endif /* !Z_FREETYPE */ +diff --git b/src/gzip/crc32.c a/src/gzip/crc32.c +index 6c38f5c04..27487dcc2 100644 +--- b/src/gzip/crc32.c ++++ a/src/gzip/crc32.c +@@ -148,6 +148,8 @@ local z_word_t byte_swap(z_word_t word) { + /* CRC polynomial. */ + #define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + ++#ifndef Z_FREETYPE ++ + /* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. +@@ -186,6 +188,8 @@ local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + return p; + } + ++#endif /* !Z_FREETYPE */ ++ + #ifdef DYNAMIC_CRC_TABLE + /* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table +@@ -542,6 +546,8 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { + + #endif /* DYNAMIC_CRC_TABLE */ + ++#ifndef Z_FREETYPE ++ + /* ========================================================================= + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. +@@ -553,6 +559,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table(void) { + return (const z_crc_t FAR *)crc_table; + } + ++#endif /* !Z_FREETYPE */ ++ + /* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for +@@ -1017,6 +1025,8 @@ unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + return crc32_z(crc, buf, len); + } + ++#ifndef Z_FREETYPE ++ + /* ========================================================================= */ + uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { + #ifdef DYNAMIC_CRC_TABLE +@@ -1047,3 +1057,5 @@ uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); + } ++ ++#endif /* !Z_FREETYPE */ +diff --git b/src/gzip/gzguts.h a/src/gzip/gzguts.h +index f9375047e..f9a250b85 100644 +--- b/src/gzip/gzguts.h ++++ a/src/gzip/gzguts.h +@@ -162,7 +162,7 @@ + + /* values for gz_state how */ + #define LOOK 0 /* look for a gzip header */ +-#define COPY 1 /* copy input directly */ ++#define COPY__ 1 /* copy input directly */ + #define GZIP 2 /* decompress a gzip stream */ + + /* internal gzip file state data structure */ +diff --git b/src/gzip/inffast.h a/src/gzip/inffast.h +index 49c6d156c..a38c5be45 100644 +--- b/src/gzip/inffast.h ++++ a/src/gzip/inffast.h +@@ -8,4 +8,4 @@ + subject to change. Applications should only use zlib.h. + */ + +-void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); ++static void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); +diff --git b/src/gzip/inflate.c a/src/gzip/inflate.c +index b0757a9b2..f7ed5d181 100644 +--- b/src/gzip/inflate.c ++++ a/src/gzip/inflate.c +@@ -215,6 +215,8 @@ int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + return ret; + } + ++#ifndef Z_FREETYPE ++ + int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +@@ -239,6 +241,8 @@ int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { + return Z_OK; + } + ++#endif /* !Z_FREETYPE */ ++ + /* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. +@@ -1275,6 +1279,8 @@ int ZEXPORT inflateEnd(z_streamp strm) { + return Z_OK; + } + ++#ifndef Z_FREETYPE ++ + int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + struct inflate_state FAR *state; +@@ -1524,3 +1530,5 @@ unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); + } ++ ++#endif /* !Z_FREETYPE */ +diff --git b/src/gzip/inflate.h a/src/gzip/inflate.h +index f127b6b1f..8a0e437ae 100644 +--- b/src/gzip/inflate.h ++++ a/src/gzip/inflate.h +@@ -3,6 +3,9 @@ + * For conditions of distribution and use, see copyright notice in zlib.h + */ + ++#ifndef INFLATE_H ++#define INFLATE_H ++ + /* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. +@@ -124,3 +127,5 @@ struct inflate_state { + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ + }; ++ ++#endif /* !INFLATE_H */ +diff --git b/src/gzip/inftrees.c a/src/gzip/inftrees.c +index 8a208c2da..1fd655593 100644 +--- b/src/gzip/inftrees.c ++++ a/src/gzip/inftrees.c +@@ -8,7 +8,7 @@ + + #define MAXBITS 15 + +-const char inflate_copyright[] = ++static const char inflate_copyright[] = + " inflate 1.3 Copyright 1995-2023 Mark Adler "; + /* + If you use the zlib library in a product, an acknowledgment is welcome +diff --git b/src/gzip/inftrees.h a/src/gzip/inftrees.h +index a10712d8c..47f726c36 100644 +--- b/src/gzip/inftrees.h ++++ a/src/gzip/inftrees.h +@@ -3,6 +3,9 @@ + * For conditions of distribution and use, see copyright notice in zlib.h + */ + ++#ifndef INFTREES_H ++#define INFTREES_H ++ + /* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. +@@ -57,6 +60,8 @@ typedef enum { + DISTS + } codetype; + +-int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, ++static int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); ++ ++#endif /* !INFTREES_H */ +diff --git b/src/gzip/zlib.h a/src/gzip/zlib.h +index 6b7244f99..5c7a884c9 100644 +--- b/src/gzip/zlib.h ++++ a/src/gzip/zlib.h +@@ -31,7 +31,7 @@ + #ifndef ZLIB_H + #define ZLIB_H + +-#include "zconf.h" ++#include "ftzconf.h" + + #ifdef __cplusplus + extern "C" { +@@ -211,6 +211,8 @@ typedef gz_header FAR *gz_headerp; + + #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + ++#ifndef Z_FREETYPE ++ + #define zlib_version zlibVersion() + /* for compatibility with versions < 1.0.2 */ + +@@ -373,6 +375,7 @@ ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); + deallocated). + */ + ++#endif /* !Z_FREETYPE */ + + /* + ZEXTERN int ZEXPORT inflateInit(z_streamp strm); +@@ -535,6 +538,8 @@ ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); + The following functions are needed only in some special applications. + */ + ++#ifndef Z_FREETYPE ++ + /* + ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, +@@ -958,6 +963,8 @@ ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + destination. + */ + ++#endif /* !Z_FREETYPE */ ++ + ZEXTERN int ZEXPORT inflateReset(z_streamp strm); + /* + This function is equivalent to inflateEnd followed by inflateInit, +@@ -983,6 +990,8 @@ ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + the windowBits parameter is invalid. + */ + ++#ifndef Z_FREETYPE ++ + ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); +@@ -1072,6 +1081,8 @@ ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + stream state was inconsistent. + */ + ++#endif /* !Z_FREETYPE */ ++ + /* + ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); +@@ -1098,6 +1109,8 @@ typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); + typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); + ++#ifndef Z_FREETYPE ++ + ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); +@@ -1217,6 +1230,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void); + 27-31: 0 (reserved) + */ + ++#endif /* !Z_FREETYPE */ ++ + #ifndef Z_SOLO + + /* utility functions */ +@@ -1768,6 +1783,8 @@ ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + crc32_combine_op(). + */ + ++#ifndef Z_FREETYPE ++ + ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); + /* + Give the same result as crc32_combine(), using op in place of len2. op is +@@ -1825,6 +1842,17 @@ ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + ZLIB_VERSION, (int)sizeof(z_stream)) + #endif + ++#else /* Z_FREETYPE */ ++ ++ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, ++ const char *version, int stream_size); ++ ++# define inflateInit2(strm, windowBits) \ ++ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ ++ (int)sizeof(z_stream)) ++ ++#endif /* Z_FREETYPE */ ++ + #ifndef Z_SOLO + + /* gzgetc() macro and its supporting function and exposed data structure. Note +@@ -1904,20 +1932,25 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ + + #else /* Z_SOLO */ + ++#ifndef Z_FREETYPE + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); ++#endif + + #endif /* !Z_SOLO */ + + /* undocumented functions */ ++#ifndef Z_FREETYPE + ZEXTERN const char * ZEXPORT zError(int); + ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); + ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); + ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); + ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); + ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); ++#endif /* !Z_FREETYPE */ + ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); ++#ifndef Z_FREETYPE + ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); + #if defined(_WIN32) && !defined(Z_SOLO) + ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, +@@ -1930,6 +1963,7 @@ ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + va_list va); + # endif + #endif ++#endif /* !Z_FREETYPE */ + + #ifdef __cplusplus + } +diff --git b/src/gzip/zutil.c a/src/gzip/zutil.c +index b1c5d2d3c..f76def425 100644 +--- b/src/gzip/zutil.c ++++ a/src/gzip/zutil.c +@@ -10,6 +10,8 @@ + # include "gzguts.h" + #endif + ++#ifndef Z_FREETYPE ++ + z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ +@@ -132,6 +134,8 @@ const char * ZEXPORT zError(int err) { + return ERR_MSG(err); + } + ++#endif /* !Z_FREETYPE */ ++ + #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. +@@ -149,6 +153,7 @@ void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { + } while (--len != 0); + } + ++#ifndef Z_FREETYPE + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { + uInt j; + +@@ -164,6 +169,7 @@ void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); + } ++#endif /* !Z_FREETYPE */ + #endif + + #ifndef Z_SOLO +diff --git b/src/gzip/zutil.h a/src/gzip/zutil.h +index 902a304cc..a2c046a1f 100644 +--- b/src/gzip/zutil.h ++++ a/src/gzip/zutil.h +@@ -53,8 +53,10 @@ typedef unsigned long ulg; + # endif + #endif + ++#ifndef Z_FREETYPE + extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + /* (size given to avoid silly warnings with Visual C++) */ ++#endif + + #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +@@ -188,6 +190,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + #pragma warn -8066 + #endif + ++#ifndef Z_FREETYPE ++ + /* provide prototypes for these when building zlib without LFS */ + #if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) +@@ -196,6 +200,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); + #endif + ++#endif /* !Z_FREETYPE */ ++ + /* common defaults */ + + #ifndef OS_CODE +@@ -227,9 +233,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ + # define zmemcmp _fmemcmp + # define zmemzero(dest, len) _fmemset(dest, 0, len) + # else +-# define zmemcpy memcpy +-# define zmemcmp memcmp +-# define zmemzero(dest, len) memset(dest, 0, len) ++# define zmemcpy ft_memcpy ++# define zmemcmp ft_memcmp ++# define zmemzero(dest, len) ft_memset(dest, 0, len) + # endif + #else + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); diff --git a/Dependencies/freetype/freetype/src/gzip/zlib.h b/Dependencies/freetype/freetype/src/gzip/zlib.h new file mode 100644 index 00000000..5c7a884c --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/zlib.h @@ -0,0 +1,1972 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.3, August 18th, 2023 + + Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "ftzconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.3" +#define ZLIB_VERNUM 0x1300 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 0 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#ifndef Z_FREETYPE + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion(void); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + +#endif /* !Z_FREETYPE */ + +/* +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +#ifndef Z_FREETYPE + +/* +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +#endif /* !Z_FREETYPE */ + +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +#ifndef Z_FREETYPE + +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +#endif /* !Z_FREETYPE */ + +/* +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); + +#ifndef Z_FREETYPE + +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#endif /* !Z_FREETYPE */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc(gzFile file); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind(gzFile file); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof(gzFile file); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect(gzFile file); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). +*/ + +#ifndef Z_FREETYPE + +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#else /* Z_FREETYPE */ + +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); + +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) + +#endif /* Z_FREETYPE */ + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); +#endif + +#else /* Z_SOLO */ + +#ifndef Z_FREETYPE + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); +#endif + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +#ifndef Z_FREETYPE +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +#endif /* !Z_FREETYPE */ +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +#ifndef Z_FREETYPE +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); +# endif +#endif +#endif /* !Z_FREETYPE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/Dependencies/freetype/freetype/src/gzip/zutil.c b/Dependencies/freetype/freetype/src/gzip/zutil.c new file mode 100644 index 00000000..f76def42 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/zutil.c @@ -0,0 +1,305 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +#ifndef Z_FREETYPE + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion(void) { + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags(void) { + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error(char *m) { + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(int err) { + return ERR_MSG(err); +} + +#endif /* !Z_FREETYPE */ + +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +#ifndef Z_FREETYPE +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif /* !Z_FREETYPE */ +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/Dependencies/freetype/freetype/src/gzip/zutil.h b/Dependencies/freetype/freetype/src/gzip/zutil.h new file mode 100644 index 00000000..a2c046a1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/gzip/zutil.h @@ -0,0 +1,281 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +#ifndef Z_FREETYPE +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ +#endif + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +#ifndef Z_FREETYPE + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +#endif + +#endif /* !Z_FREETYPE */ + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy ft_memcpy +# define zmemcmp ft_memcmp +# define zmemzero(dest, len) ft_memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error(char *m); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/Dependencies/freetype/freetype/src/lzw/ftlzw.c b/Dependencies/freetype/freetype/src/lzw/ftlzw.c new file mode 100644 index 00000000..e1acf22e --- /dev/null +++ b/Dependencies/freetype/freetype/src/lzw/ftlzw.c @@ -0,0 +1,415 @@ +/**************************************************************************** + * + * ftlzw.c + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2004-2024 by + * Albert Chin-A-Young. + * + * based on code in `src/gzip/ftgzip.c' + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX LZW_Err_ +#define FT_ERR_BASE FT_Mod_Err_LZW + +#include + + +#ifdef FT_CONFIG_OPTION_USE_LZW + +#include "ftzopen.h" + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_LZW_BUFFER_SIZE 4096 + + typedef struct FT_LZWFileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + FT_LzwStateRec lzw; /* lzw decompressor state */ + + FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + + } FT_LZWFileRec, *FT_LZWFile; + + + /* check and skip .Z header */ + static FT_Error + ft_lzw_check_header( FT_Stream stream ) + { + FT_Error error; + FT_Byte head[2]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 2 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers */ + if ( head[0] != 0x1F || + head[1] != 0x9D ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static FT_Error + ft_lzw_file_init( FT_LZWFile zip, + FT_Stream stream, + FT_Stream source ) + { + FT_LzwState lzw = &zip->lzw; + FT_Error error; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + + /* check and skip .Z header */ + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + + /* initialize internal lzw variable */ + ft_lzwstate_init( lzw, source ); + + Exit: + return error; + } + + + static void + ft_lzw_file_done( FT_LZWFile zip ) + { + /* clear the rest */ + ft_lzwstate_done( &zip->lzw ); + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_lzw_file_reset( FT_LZWFile zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + ft_lzwstate_reset( &zip->lzw ); + + zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + } + + return error; + } + + + static FT_Error + ft_lzw_file_fill_output( FT_LZWFile zip ) + { + FT_LzwState lzw = &zip->lzw; + FT_ULong count; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + + count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE ); + + zip->limit = zip->cursor + count; + + if ( count == 0 ) + error = FT_THROW( Invalid_Stream_Operation ); + + return error; + } + + + /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */ + static FT_Error + ft_lzw_file_skip_output( FT_LZWFile zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + /* first, we skip what we can from the output buffer */ + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + } + + /* next, we skip as many bytes remaining as possible */ + while ( count > 0 ) + { + FT_ULong delta = FT_LZW_BUFFER_SIZE; + FT_ULong numread; + + + if ( delta > count ) + delta = count; + + numread = ft_lzwstate_io( &zip->lzw, NULL, delta ); + if ( numread < delta ) + { + /* not enough bytes */ + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + + zip->pos += delta; + count -= delta; + } + + return error; + } + + + static FT_ULong + ft_lzw_file_io( FT_LZWFile zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* seeking backwards. */ + if ( pos < zip->pos ) + { + /* If the new position is within the output buffer, simply */ + /* decrement pointers, otherwise we reset the stream completely! */ + if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) ) + { + zip->cursor -= zip->pos - pos; + zip->pos = pos; + } + else + { + error = ft_lzw_file_reset( zip ); + if ( error ) + goto Exit; + } + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer + result, zip->cursor, delta ); + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_lzw_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** L Z W E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_lzw_stream_close( FT_Stream stream ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize lzw file descriptor */ + ft_lzw_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static unsigned long + ft_lzw_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer; + + + return ft_lzw_file_io( zip, offset, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_LZWFile zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * Check the header right now; this prevents allocation of a huge + * LZWFile object (400 KByte of heap memory) if not necessary. + * + * Did I mention that you should never use .Z compressed font + * files? + */ + error = ft_lzw_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_lzw_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = NULL; + stream->read = ft_lzw_stream_io; + stream->close = ft_lzw_stream_close; + + Exit: + return error; + } + + +#include "ftzopen.c" + + +#else /* !FT_CONFIG_OPTION_USE_LZW */ + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + + +#endif /* !FT_CONFIG_OPTION_USE_LZW */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/lzw/ftzopen.c b/Dependencies/freetype/freetype/src/lzw/ftzopen.c new file mode 100644 index 00000000..e4233246 --- /dev/null +++ b/Dependencies/freetype/freetype/src/lzw/ftzopen.c @@ -0,0 +1,429 @@ +/**************************************************************************** + * + * ftzopen.c + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2005-2024 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include "ftzopen.h" +#include +#include +#include + + + static int + ft_lzwstate_refill( FT_LzwState state ) + { + FT_ULong count; + + + if ( state->in_eof ) + return -1; + + count = FT_Stream_TryRead( state->source, + state->buf_tab, + state->num_bits ); /* WHY? */ + + state->buf_size = (FT_UInt)count; + state->buf_total += count; + state->in_eof = FT_BOOL( count < state->num_bits ); + state->buf_offset = 0; + + state->buf_size <<= 3; + if ( state->buf_size > state->num_bits ) + state->buf_size -= state->num_bits - 1; + else + return -1; /* not enough data */ + + if ( count == 0 ) /* end of file */ + return -1; + + return 0; + } + + + static FT_Int32 + ft_lzwstate_get_code( FT_LzwState state ) + { + FT_UInt num_bits = state->num_bits; + FT_UInt offset = state->buf_offset; + FT_Byte* p; + FT_Int result; + + + if ( state->buf_clear || + offset >= state->buf_size || + state->free_ent >= state->free_bits ) + { + if ( state->free_ent >= state->free_bits ) + { + state->num_bits = ++num_bits; + if ( num_bits > LZW_MAX_BITS ) + return -1; + + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << num_bits ) - 256 ) + : state->max_free + 1; + } + + if ( state->buf_clear ) + { + state->num_bits = num_bits = LZW_INIT_BITS; + state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 ); + state->buf_clear = 0; + } + + if ( ft_lzwstate_refill( state ) < 0 ) + return -1; + + offset = 0; + } + + state->buf_offset = offset + num_bits; + + p = &state->buf_tab[offset >> 3]; + offset &= 7; + result = *p++ >> offset; + offset = 8 - offset; + num_bits -= offset; + + if ( num_bits >= 8 ) + { + result |= *p++ << offset; + offset += 8; + num_bits -= 8; + } + if ( num_bits > 0 ) + result |= ( *p & LZW_MASK( num_bits ) ) << offset; + + return result; + } + + + /* grow the character stack */ + static int + ft_lzwstate_stack_grow( FT_LzwState state ) + { + if ( state->stack_top >= state->stack_size ) + { + FT_Memory memory = state->memory; + FT_Error error; + FT_Offset old_size = state->stack_size; + FT_Offset new_size = old_size; + + new_size = new_size + ( new_size >> 1 ) + 4; + + /* if relocating to heap */ + if ( state->stack == state->stack_0 ) + { + state->stack = NULL; + old_size = 0; + } + + /* requirement of the character stack larger than 1< ( 1 << LZW_MAX_BITS ) ) + { + new_size = 1 << LZW_MAX_BITS; + if ( new_size == old_size ) + return -1; + } + + if ( FT_QREALLOC( state->stack, old_size, new_size ) ) + return -1; + + /* if relocating to heap */ + if ( old_size == 0 ) + FT_MEM_COPY( state->stack, state->stack_0, FT_LZW_DEFAULT_STACK_SIZE ); + + state->stack_size = new_size; + } + return 0; + } + + + /* grow the prefix/suffix arrays */ + static int + ft_lzwstate_prefix_grow( FT_LzwState state ) + { + FT_UInt old_size = state->prefix_size; + FT_UInt new_size = old_size; + FT_Memory memory = state->memory; + FT_Error error; + + + if ( new_size == 0 ) /* first allocation -> 9 bits */ + new_size = 512; + else + new_size += new_size >> 2; /* don't grow too fast */ + + /* + * Note that the `suffix' array is located in the same memory block + * pointed to by `prefix'. + * + * I know that sizeof(FT_Byte) == 1 by definition, but it is clearer + * to write it literally. + * + */ + if ( FT_REALLOC_MULT( state->prefix, old_size, new_size, + sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ) ) + return -1; + + /* now adjust `suffix' and move the data accordingly */ + state->suffix = (FT_Byte*)( state->prefix + new_size ); + + FT_MEM_MOVE( state->suffix, + state->prefix + old_size, + old_size * sizeof ( FT_Byte ) ); + + state->prefix_size = new_size; + return 0; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_reset( FT_LzwState state ) + { + state->in_eof = 0; + state->buf_offset = 0; + state->buf_size = 0; + state->buf_clear = 0; + state->buf_total = 0; + state->stack_top = 0; + state->num_bits = LZW_INIT_BITS; + state->phase = FT_LZW_PHASE_START; + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ) + { + FT_ZERO( state ); + + state->source = source; + state->memory = source->memory; + + state->prefix = NULL; + state->suffix = NULL; + state->prefix_size = 0; + + state->stack = state->stack_0; + state->stack_size = sizeof ( state->stack_0 ); + + ft_lzwstate_reset( state ); + } + + + FT_LOCAL_DEF( void ) + ft_lzwstate_done( FT_LzwState state ) + { + FT_Memory memory = state->memory; + + + ft_lzwstate_reset( state ); + + if ( state->stack != state->stack_0 ) + FT_FREE( state->stack ); + + FT_FREE( state->prefix ); + state->suffix = NULL; + + FT_ZERO( state ); + } + + +#define FTLZW_STACK_PUSH( c ) \ + FT_BEGIN_STMNT \ + if ( state->stack_top >= state->stack_size && \ + ft_lzwstate_stack_grow( state ) < 0 ) \ + goto Eof; \ + \ + state->stack[state->stack_top++] = (FT_Byte)(c); \ + FT_END_STMNT + + + FT_LOCAL_DEF( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ) + { + FT_ULong result = 0; + + FT_UInt old_char = state->old_char; + FT_UInt old_code = state->old_code; + FT_UInt in_code = state->in_code; + + + if ( out_size == 0 ) + goto Exit; + + switch ( state->phase ) + { + case FT_LZW_PHASE_START: + { + FT_Byte max_bits; + FT_Int32 c; + + + /* skip magic bytes, and read max_bits + block_flag */ + if ( FT_Stream_Seek( state->source, 2 ) != 0 || + FT_Stream_TryRead( state->source, &max_bits, 1 ) != 1 ) + goto Eof; + + state->max_bits = max_bits & LZW_BIT_MASK; + state->block_mode = max_bits & LZW_BLOCK_MASK; + state->max_free = (FT_UInt)( ( 1UL << state->max_bits ) - 256 ); + + if ( state->max_bits > LZW_MAX_BITS ) + goto Eof; + + state->num_bits = LZW_INIT_BITS; + state->free_ent = ( state->block_mode ? LZW_FIRST + : LZW_CLEAR ) - 256; + in_code = 0; + + state->free_bits = state->num_bits < state->max_bits + ? (FT_UInt)( ( 1UL << state->num_bits ) - 256 ) + : state->max_free + 1; + + c = ft_lzwstate_get_code( state ); + if ( c < 0 || c > 255 ) + goto Eof; + + old_code = old_char = (FT_UInt)c; + + if ( buffer ) + buffer[result] = (FT_Byte)old_char; + + if ( ++result >= out_size ) + goto Exit; + + state->phase = FT_LZW_PHASE_CODE; + } + FALL_THROUGH; + + case FT_LZW_PHASE_CODE: + { + FT_Int32 c; + FT_UInt code; + + + NextCode: + c = ft_lzwstate_get_code( state ); + if ( c < 0 ) + goto Eof; + + code = (FT_UInt)c; + + if ( code == LZW_CLEAR && state->block_mode ) + { + /* why not LZW_FIRST-256 ? */ + state->free_ent = ( LZW_FIRST - 1 ) - 256; + state->buf_clear = 1; + + /* not quite right, but at least more predictable */ + old_code = 0; + old_char = 0; + + goto NextCode; + } + + in_code = code; /* save code for later */ + + if ( code >= 256U ) + { + /* special case for KwKwKwK */ + if ( code - 256U >= state->free_ent ) + { + /* corrupted LZW stream */ + if ( code - 256U > state->free_ent ) + goto Eof; + + FTLZW_STACK_PUSH( old_char ); + code = old_code; + } + + while ( code >= 256U ) + { + if ( !state->prefix ) + goto Eof; + + FTLZW_STACK_PUSH( state->suffix[code - 256] ); + code = state->prefix[code - 256]; + } + } + + old_char = code; + FTLZW_STACK_PUSH( old_char ); + + state->phase = FT_LZW_PHASE_STACK; + } + FALL_THROUGH; + + case FT_LZW_PHASE_STACK: + { + while ( state->stack_top > 0 ) + { + state->stack_top--; + + if ( buffer ) + buffer[result] = state->stack[state->stack_top]; + + if ( ++result == out_size ) + goto Exit; + } + + /* now create new entry */ + if ( state->free_ent < state->max_free ) + { + if ( state->free_ent >= state->prefix_size && + ft_lzwstate_prefix_grow( state ) < 0 ) + goto Eof; + + FT_ASSERT( state->free_ent < state->prefix_size ); + + state->prefix[state->free_ent] = (FT_UShort)old_code; + state->suffix[state->free_ent] = (FT_Byte) old_char; + + state->free_ent += 1; + } + + old_code = in_code; + + state->phase = FT_LZW_PHASE_CODE; + goto NextCode; + } + + default: /* state == EOF */ + ; + } + + Exit: + state->old_code = old_code; + state->old_char = old_char; + state->in_code = in_code; + + return result; + + Eof: + state->phase = FT_LZW_PHASE_EOF; + goto Exit; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/lzw/ftzopen.h b/Dependencies/freetype/freetype/src/lzw/ftzopen.h new file mode 100644 index 00000000..69152182 --- /dev/null +++ b/Dependencies/freetype/freetype/src/lzw/ftzopen.h @@ -0,0 +1,174 @@ +/**************************************************************************** + * + * ftzopen.h + * + * FreeType support for .Z compressed files. + * + * This optional component relies on NetBSD's zopen(). It should mainly + * be used to parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2005-2024 by + * David Turner. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTZOPEN_H_ +#define FTZOPEN_H_ + +#include + +FT_BEGIN_HEADER + + /* + * This is a complete re-implementation of the LZW file reader, + * since the old one was incredibly badly written, using + * 400 KByte of heap memory before decompressing anything. + * + */ + +#define FT_LZW_IN_BUFF_SIZE 64 +#define FT_LZW_DEFAULT_STACK_SIZE 64 + +#define LZW_INIT_BITS 9 +#define LZW_MAX_BITS 16 + +#define LZW_CLEAR 256 +#define LZW_FIRST 257 + +#define LZW_BIT_MASK 0x1F +#define LZW_BLOCK_MASK 0x80 +#define LZW_MASK( n ) ( ( 1U << (n) ) - 1U ) + + + typedef enum FT_LzwPhase_ + { + FT_LZW_PHASE_START = 0, + FT_LZW_PHASE_CODE, + FT_LZW_PHASE_STACK, + FT_LZW_PHASE_EOF + + } FT_LzwPhase; + + + /* + * state of LZW decompressor + * + * small technical note + * -------------------- + * + * We use a few tricks in this implementation that are explained here to + * ease debugging and maintenance. + * + * - First of all, the `prefix' and `suffix' arrays contain the suffix + * and prefix for codes over 256; this means that + * + * prefix_of(code) == state->prefix[code-256] + * suffix_of(code) == state->suffix[code-256] + * + * Each prefix is a 16-bit code, and each suffix an 8-bit byte. + * + * Both arrays are stored in a single memory block, pointed to by + * `state->prefix'. This means that the following equality is always + * true: + * + * state->suffix == (FT_Byte*)(state->prefix + state->prefix_size) + * + * Of course, state->prefix_size is the number of prefix/suffix slots + * in the arrays, corresponding to codes 256..255+prefix_size. + * + * - `free_ent' is the index of the next free entry in the `prefix' + * and `suffix' arrays. This means that the corresponding `next free + * code' is really `256+free_ent'. + * + * Moreover, `max_free' is the maximum value that `free_ent' can reach. + * + * `max_free' corresponds to `(1 << max_bits) - 256'. Note that this + * value is always <= 0xFF00, which means that both `free_ent' and + * `max_free' can be stored in an FT_UInt variable, even on 16-bit + * machines. + * + * If `free_ent == max_free', you cannot add new codes to the + * prefix/suffix table. + * + * - `num_bits' is the current number of code bits, starting at 9 and + * growing each time `free_ent' reaches the value of `free_bits'. The + * latter is computed as follows + * + * if num_bits < max_bits: + * free_bits = (1 << num_bits)-256 + * else: + * free_bits = max_free + 1 + * + * Since the value of `max_free + 1' can never be reached by + * `free_ent', `num_bits' cannot grow larger than `max_bits'. + */ + + typedef struct FT_LzwStateRec_ + { + FT_LzwPhase phase; + FT_Int in_eof; + + FT_Byte buf_tab[16]; + FT_UInt buf_offset; + FT_UInt buf_size; + FT_Bool buf_clear; + FT_Offset buf_total; + + FT_UInt max_bits; /* max code bits, from file header */ + FT_Int block_mode; /* block mode flag, from file header */ + FT_UInt max_free; /* (1 << max_bits) - 256 */ + + FT_UInt num_bits; /* current code bit number */ + FT_UInt free_ent; /* index of next free entry */ + FT_UInt free_bits; /* if reached by free_ent, increment num_bits */ + FT_UInt old_code; + FT_UInt old_char; + FT_UInt in_code; + + FT_UShort* prefix; /* always dynamically allocated / reallocated */ + FT_Byte* suffix; /* suffix = (FT_Byte*)(prefix + prefix_size) */ + FT_UInt prefix_size; /* number of slots in `prefix' or `suffix' */ + + FT_Byte* stack; /* character stack */ + FT_UInt stack_top; + FT_Offset stack_size; + FT_Byte stack_0[FT_LZW_DEFAULT_STACK_SIZE]; /* minimize heap alloc */ + + FT_Stream source; /* source stream */ + FT_Memory memory; + + } FT_LzwStateRec, *FT_LzwState; + + + FT_LOCAL( void ) + ft_lzwstate_init( FT_LzwState state, + FT_Stream source ); + + FT_LOCAL( void ) + ft_lzwstate_done( FT_LzwState state ); + + + FT_LOCAL( void ) + ft_lzwstate_reset( FT_LzwState state ); + + + FT_LOCAL( FT_ULong ) + ft_lzwstate_io( FT_LzwState state, + FT_Byte* buffer, + FT_ULong out_size ); + +/* */ + +FT_END_HEADER + +#endif /* FTZOPEN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvalid.c b/Dependencies/freetype/freetype/src/otvalid/otvalid.c new file mode 100644 index 00000000..c96967ce --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvalid.c @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * otvalid.c + * + * FreeType validator for OpenType tables (body only). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "otvbase.c" +#include "otvcommn.c" +#include "otvgdef.c" +#include "otvgpos.c" +#include "otvgsub.c" +#include "otvjstf.c" +#include "otvmath.c" +#include "otvmod.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvalid.h b/Dependencies/freetype/freetype/src/otvalid/otvalid.h new file mode 100644 index 00000000..0f46a7a1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvalid.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * otvalid.h + * + * OpenType table validation (specification only). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVALID_H_ +#define OTVALID_H_ + + +#include + +#include "otverror.h" /* must come before `ftvalid.h' */ + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_MATH_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ); + + +FT_END_HEADER + +#endif /* OTVALID_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvbase.c b/Dependencies/freetype/freetype/src/otvalid/otvbase.c new file mode 100644 index 00000000..61012624 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvbase.c @@ -0,0 +1,345 @@ +/**************************************************************************** + * + * otvbase.c + * + * OpenType BASE table validation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvbase + + + static void + otv_BaseCoord_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordFormat; + + + OTV_NAME_ENTER( "BaseCoord" ); + + OTV_LIMIT_CHECK( 4 ); + BaseCoordFormat = FT_NEXT_USHORT( p ); + p += 2; /* skip Coordinate */ + + OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); + + switch ( BaseCoordFormat ) + { + case 1: /* BaseCoordFormat1 */ + break; + + case 2: /* BaseCoordFormat2 */ + OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ + break; + + case 3: /* BaseCoordFormat3 */ + OTV_LIMIT_CHECK( 2 ); + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static void + otv_BaseTagList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseTagCount; + + + OTV_NAME_ENTER( "BaseTagList" ); + + OTV_LIMIT_CHECK( 2 ); + + BaseTagCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); + + OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ + + OTV_EXIT; + } + + + static void + otv_BaseValues_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordCount; + + + OTV_NAME_ENTER( "BaseValues" ); + + OTV_LIMIT_CHECK( 4 ); + + p += 2; /* skip DefaultIndex */ + BaseCoordCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); + + OTV_LIMIT_CHECK( BaseCoordCount * 2 ); + + /* BaseCoord */ + for ( ; BaseCoordCount > 0; BaseCoordCount-- ) + otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + static void + otv_MinMax_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt FeatMinMaxCount; + + OTV_OPTIONAL_TABLE( MinCoord ); + OTV_OPTIONAL_TABLE( MaxCoord ); + + + OTV_NAME_ENTER( "MinMax" ); + + OTV_LIMIT_CHECK( 6 ); + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + FeatMinMaxCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); + + table_size = FeatMinMaxCount * 8 + 6; + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, otvalid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, otvalid ); + + OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); + + /* FeatMinMaxRecord */ + for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) + { + p += 4; /* skip FeatureTableTag */ + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, otvalid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScript_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt BaseLangSysCount; + + OTV_OPTIONAL_TABLE( BaseValues ); + OTV_OPTIONAL_TABLE( DefaultMinMax ); + + + OTV_NAME_ENTER( "BaseScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( BaseValues ); + OTV_OPTIONAL_OFFSET( DefaultMinMax ); + BaseLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); + + table_size = BaseLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( BaseValues ); + if ( BaseValues ) + otv_BaseValues_validate( table + BaseValues, otvalid ); + + OTV_SIZE_CHECK( DefaultMinMax ); + if ( DefaultMinMax ) + otv_MinMax_validate( table + DefaultMinMax, otvalid ); + + OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); + + /* BaseLangSysRecord */ + for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) + { + p += 4; /* skip BaseLangSysTag */ + + otv_MinMax_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScriptList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BaseScriptCount; + + + OTV_NAME_ENTER( "BaseScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + BaseScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); + + OTV_LIMIT_CHECK( BaseScriptCount * 6 ); + + /* BaseScriptRecord */ + for ( ; BaseScriptCount > 0; BaseScriptCount-- ) + { + p += 4; /* skip BaseScriptTag */ + + /* BaseScript */ + otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_Axis_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( BaseTagList ); + + + OTV_NAME_ENTER( "Axis" ); + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( BaseTagList ); + + table_size = 4; + + OTV_SIZE_CHECK( BaseTagList ); + if ( BaseTagList ) + otv_BaseTagList_validate( table + BaseTagList, otvalid ); + + /* BaseScriptList */ + otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + + OTV_OPTIONAL_TABLE( HorizAxis ); + OTV_OPTIONAL_TABLE( VertAxis ); + + OTV_OPTIONAL_TABLE32( itemVarStore ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating BASE table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 8; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 4 ); + break; + + case 1: + OTV_LIMIT_CHECK( 8 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_OPTIONAL_OFFSET( HorizAxis ); + OTV_SIZE_CHECK( HorizAxis ); + if ( HorizAxis ) + otv_Axis_validate( table + HorizAxis, otvalid ); + + OTV_OPTIONAL_OFFSET( VertAxis ); + OTV_SIZE_CHECK( VertAxis ); + if ( VertAxis ) + otv_Axis_validate( table + VertAxis, otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( itemVarStore ); + OTV_SIZE_CHECK32( itemVarStore ); + if ( itemVarStore ) + OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvcommn.c b/Dependencies/freetype/freetype/src/otvalid/otvcommn.c new file mode 100644 index 00000000..f06354b7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvcommn.c @@ -0,0 +1,1099 @@ +/**************************************************************************** + * + * otvcommn.c + * + * OpenType common tables validation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int expected_count ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat; + FT_UInt total = 0; + + + OTV_NAME_ENTER( "Coverage" ); + + OTV_LIMIT_CHECK( 4 ); + CoverageFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", CoverageFormat )); + + switch ( CoverageFormat ) + { + case 1: /* CoverageFormat1 */ + { + FT_UInt GlyphCount; + FT_UInt i; + + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ + + for ( i = 0; i < GlyphCount; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + + total = GlyphCount; + } + break; + + case 2: /* CoverageFormat2 */ + { + FT_UInt n, RangeCount; + FT_UInt Start, End, StartCoverageIndex, last = 0; + + + RangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); + + OTV_LIMIT_CHECK( RangeCount * 6 ); + + /* RangeRecord */ + for ( n = 0; n < RangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + StartCoverageIndex = FT_NEXT_USHORT( p ); + + if ( Start > End || StartCoverageIndex != total ) + FT_INVALID_DATA; + + if ( End >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + + if ( n > 0 && Start <= last ) + FT_INVALID_DATA; + + total += End - Start + 1; + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* Generally, a coverage table offset has an associated count field. */ + /* The number of glyphs in the table should match this field. If */ + /* there is no associated count, a value of -1 tells us not to check. */ + if ( expected_count != -1 && (FT_UInt)expected_count != total ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ) + { + FT_Bytes p = table; + + + p += 4; /* skip CoverageFormat and Glyph/RangeCount */ + + return FT_NEXT_USHORT( p ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + if ( !count ) + return result; + + switch ( CoverageFormat ) + { + case 1: + p += ( count - 1 ) * 2; + result = FT_NEXT_USHORT( p ); + break; + + case 2: + p += ( count - 1 ) * 6 + 2; + result = FT_NEXT_USHORT( p ); + break; + + default: + ; + } + + return result; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + return count; + + case 2: + { + FT_UInt Start, End; + + + for ( ; count > 0; count-- ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip StartCoverageIndex */ + + result += End - Start + 1; + } + } + break; + + default: + ; + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt ClassFormat; + + + OTV_NAME_ENTER( "ClassDef" ); + + OTV_LIMIT_CHECK( 4 ); + ClassFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", ClassFormat )); + + switch ( ClassFormat ) + { + case 1: /* ClassDefFormat1 */ + { + FT_UInt StartGlyph; + FT_UInt GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + + StartGlyph = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ + + if ( StartGlyph + GlyphCount - 1 >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + break; + + case 2: /* ClassDefFormat2 */ + { + FT_UInt n, ClassRangeCount; + FT_UInt Start, End, last = 0; + + + ClassRangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); + + OTV_LIMIT_CHECK( ClassRangeCount * 6 ); + + /* ClassRangeRecord */ + for ( n = 0; n < ClassRangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip Class */ + + if ( Start > End || ( n > 0 && Start <= last ) ) + FT_INVALID_DATA; + + if ( End >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to class definition */ + /* tables since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt StartSize, EndSize, DeltaFormat, count; + + + OTV_NAME_ENTER( "Device" ); + + OTV_LIMIT_CHECK( 6 ); + StartSize = FT_NEXT_USHORT( p ); + EndSize = FT_NEXT_USHORT( p ); + DeltaFormat = FT_NEXT_USHORT( p ); + + if ( DeltaFormat == 0x8000U ) + { + /* VariationIndex, nothing to do */ + } + else + { + if ( DeltaFormat < 1 || DeltaFormat > 3 ) + FT_INVALID_FORMAT; + + if ( EndSize < StartSize ) + FT_INVALID_DATA; + + count = EndSize - StartSize + 1; + OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 ); /* DeltaValue */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_count */ + /* uses otvalid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupType, LookupFlag, SubTableCount; + OTV_Validate_Func validate; + + + OTV_NAME_ENTER( "Lookup" ); + + OTV_LIMIT_CHECK( 6 ); + LookupType = FT_NEXT_USHORT( p ); + LookupFlag = FT_NEXT_USHORT( p ); + SubTableCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (type %d)\n", LookupType )); + + if ( LookupType == 0 || LookupType > otvalid->type_count ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[LookupType - 1]; + + OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); + + OTV_LIMIT_CHECK( SubTableCount * 2 ); + + /* SubTable */ + for ( ; SubTableCount > 0; SubTableCount-- ) + validate( table + FT_NEXT_USHORT( p ), otvalid ); + + if ( LookupFlag & 0x10 ) + OTV_LIMIT_CHECK( 2 ); /* MarkFilteringSet */ + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "LookupList" ); + + OTV_LIMIT_CHECK( 2 ); + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + otvalid->lookup_count = LookupCount; + + /* Lookup */ + for ( ; LookupCount > 0; LookupCount-- ) + otv_Lookup_validate( table + FT_NEXT_USHORT( p ), otvalid ); + + OTV_EXIT; + } + + + static FT_UInt + otv_LookupList_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "Feature" ); + + OTV_LIMIT_CHECK( 4 ); + p += 2; /* skip FeatureParams (unused) */ + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + /* LookupListIndex */ + for ( ; LookupCount > 0; LookupCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + static FT_UInt + otv_Feature_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /* sets otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "FeatureList" ); + + OTV_LIMIT_CHECK( 2 ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + otvalid->lookup_count = otv_LookupList_get_count( lookups ); + + /* FeatureRecord */ + for ( ; FeatureCount > 0; FeatureCount-- ) + { + p += 4; /* skip FeatureTag */ + + /* Feature */ + otv_Feature_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* uses otvalid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt ReqFeatureIndex; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "LangSys" ); + + OTV_LIMIT_CHECK( 6 ); + p += 2; /* skip LookupOrder (unused) */ + ReqFeatureIndex = FT_NEXT_USHORT( p ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= otvalid->extra1 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + /* FeatureIndex */ + for ( ; FeatureCount > 0; FeatureCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_UInt DefaultLangSys, LangSysCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "Script" ); + + OTV_LIMIT_CHECK( 4 ); + DefaultLangSys = FT_NEXT_USHORT( p ); + LangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); + + if ( DefaultLangSys != 0 ) + otv_LangSys_validate( table + DefaultLangSys, otvalid ); + + OTV_LIMIT_CHECK( LangSysCount * 6 ); + + /* LangSysRecord */ + for ( ; LangSysCount > 0; LangSysCount-- ) + { + p += 4; /* skip LangSysTag */ + + /* LangSys */ + otv_LangSys_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator otvalid ) + { + FT_UInt ScriptCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "ScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + ScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); + + OTV_LIMIT_CHECK( ScriptCount * 6 ); + + otvalid->extra1 = otv_Feature_get_count( features ); + + /* ScriptRecord */ + for ( ; ScriptCount > 0; ScriptCount-- ) + { + p += 4; /* skip ScriptTag */ + + otv_Script_validate( table + FT_NEXT_USHORT( p ), otvalid ); /* Script */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + u: uint16 + ux: unit16 [x] + + s: struct + sx: struct [x] + sxy: struct [x], using external y count + + x: uint16 x + + C: Coverage + + O: Offset + On: Offset (NULL) + Ox: Offset [x] + Onx: Offset (NULL) [x] + */ + + FT_LOCAL_DEF( void ) + otv_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count, Coverage; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)Count ); + + OTV_LIMIT_CHECK( Count * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->extra1 (if > 0: array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + if ( otvalid->extra1 ) + { + for ( ; Count > 0; Count-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `ux' in the function's name is not really correct since only x-1 */ + /* elements are tested */ + + /* uses otvalid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count1, Count2; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Count1 = FT_NEXT_USHORT( p ); + Count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count1 = %d)\n", Count1 )); + OTV_TRACE(( " (Count2 = %d)\n", Count2 )); + + if ( Count1 == 0 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 ); + p += ( Count1 - 1 ) * 2; + + for ( ; Count2 > 0; Count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= Count1 ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `uy' in the function's name is not really correct since only y-1 */ + /* elements are tested */ + + /* uses otvalid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BacktrackCount, InputCount, LookaheadCount; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + BacktrackCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); + + OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); + p += BacktrackCount * 2; + + InputCount = FT_NEXT_USHORT( p ); + if ( InputCount == 0 ) + FT_INVALID_DATA; + + OTV_TRACE(( " (InputCount = %d)\n", InputCount )); + + OTV_LIMIT_CHECK( InputCount * 2 ); + p += ( InputCount - 1 ) * 2; + + LookaheadCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); + + OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); + p += LookaheadCount * 2; + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 4 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage, ClassDef, ClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ClassDef = FT_NEXT_USHORT( p ); + ClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ClassDef_validate( table + ClassDef, otvalid ); + + OTV_LIMIT_CHECK( ClassSetCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = otvalid->lookup_count; + + for ( ; ClassSetCount > 0; ClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, otvalid ); + } + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt GlyphCount, Count, count1; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + GlyphCount = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); + + for ( count1 = GlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= GlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage; + FT_UInt BacktrackClassDef, InputClassDef, LookaheadClassDef; + FT_UInt ChainClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 10 ); + Coverage = FT_NEXT_USHORT( p ); + BacktrackClassDef = FT_NEXT_USHORT( p ); + InputClassDef = FT_NEXT_USHORT( p ); + LookaheadClassDef = FT_NEXT_USHORT( p ); + ChainClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + + otv_ClassDef_validate( table + BacktrackClassDef, otvalid ); + otv_ClassDef_validate( table + InputClassDef, otvalid ); + otv_ClassDef_validate( table + LookaheadClassDef, otvalid ); + + OTV_LIMIT_CHECK( ChainClassSetCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = otvalid->lookup_count; + + for ( ; ChainClassSetCount > 0; ChainClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, otvalid ); + } + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /* uses otvalid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount; + FT_UInt count1, count2; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + InputGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); + + OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); + + for ( count1 = InputGlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", count2 )); + + OTV_LIMIT_CHECK( count2 * 4 ); + + for ( ; count2 > 0; count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputGlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= otvalid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ) + { + FT_Bytes p = table + 8; + + + return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ) + { + FT_Bytes p, lookup; + FT_UInt count; + + + if ( !table ) + return 0; + + /* LookupList */ + p = table + 8; + table += FT_NEXT_USHORT( p ); + + /* LookupCount */ + p = table; + count = FT_NEXT_USHORT( p ); + + for ( ; count > 0; count-- ) + { + FT_Bytes oldp; + + + /* Lookup */ + lookup = table + FT_NEXT_USHORT( p ); + + oldp = p; + + /* LookupFlag */ + p = lookup + 2; + if ( FT_NEXT_USHORT( p ) & 0xFF00U ) + return 1; + + p = oldp; + } + + return 0; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvcommn.h b/Dependencies/freetype/freetype/src/otvalid/otvcommn.h new file mode 100644 index 00000000..7db1a575 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvcommn.h @@ -0,0 +1,468 @@ +/**************************************************************************** + * + * otvcommn.h + * + * OpenType common tables validation (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVCOMMN_H_ +#define OTVCOMMN_H_ + + +#include "otvalid.h" +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct OTV_ValidatorRec_* OTV_Validator; + + typedef void (*OTV_Validate_Func)( FT_Bytes table, + OTV_Validator otvalid ); + + typedef struct OTV_ValidatorRec_ + { + FT_Validator root; + FT_UInt type_count; + OTV_Validate_Func* type_funcs; + + FT_UInt lookup_count; + FT_UInt glyph_count; + + FT_UInt nesting_level; + + OTV_Validate_Func func[3]; + + FT_UInt extra1; /* for passing parameters */ + FT_UInt extra2; + FT_Bytes extra3; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } OTV_ValidatorRec; + + +#undef FT_INVALID_ +#define FT_INVALID_( _error ) \ + ft_validator_error( otvalid->root, FT_THROW( _error ) ) + +#define OTV_OPTIONAL_TABLE( _table ) FT_UShort _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_TABLE32( _table ) FT_ULong _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_OFFSET( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_USHORT( p ); \ + FT_END_STMNT + +#define OTV_OPTIONAL_OFFSET32( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_ULONG( p ); \ + FT_END_STMNT + +#define OTV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + (_count) > otvalid->root->limit ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define OTV_SIZE_CHECK( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( otvalid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ + \ + _size = pp[0] = pp[1] = 0; \ + } \ + } \ + FT_END_STMNT + +#define OTV_SIZE_CHECK32( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( otvalid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ + \ + _size = pp[0] = pp[1] = pp[2] = pp[3] = 0; \ + } \ + } \ + FT_END_STMNT + + +#define OTV_NAME_(x) #x +#define OTV_NAME(x) OTV_NAME_(x) + +#define OTV_FUNC_(x) x##Func +#define OTV_FUNC(x) OTV_FUNC_(x) + +#ifdef FT_DEBUG_LEVEL_TRACE + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + otvalid->debug_function_name[1] = OTV_NAME( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->func[2] = OTV_FUNC( z ); \ + otvalid->debug_function_name[0] = OTV_NAME( x ); \ + otvalid->debug_function_name[1] = OTV_NAME( y ); \ + otvalid->debug_function_name[2] = OTV_NAME( z ); \ + FT_END_STMNT + +#define OTV_INIT otvalid->debug_indent = 0 + +#define OTV_ENTER \ + FT_BEGIN_STMNT \ + otvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", \ + otvalid->debug_function_name[otvalid->nesting_level] )); \ + FT_END_STMNT + +#define OTV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + otvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define OTV_EXIT otvalid->debug_indent -= 2 + +#define OTV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define OTV_NEST1( x ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + FT_END_STMNT + +#define OTV_NEST2( x, y ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + FT_END_STMNT + +#define OTV_NEST3( x, y, z ) \ + FT_BEGIN_STMNT \ + otvalid->nesting_level = 0; \ + otvalid->func[0] = OTV_FUNC( x ); \ + otvalid->func[1] = OTV_FUNC( y ); \ + otvalid->func[2] = OTV_FUNC( z ); \ + FT_END_STMNT + +#define OTV_INIT do { } while ( 0 ) +#define OTV_ENTER do { } while ( 0 ) +#define OTV_NAME_ENTER( name ) do { } while ( 0 ) +#define OTV_EXIT do { } while ( 0 ) + +#define OTV_TRACE( s ) do { } while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define OTV_RUN otvalid->func[0] + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int expected_count ); + + /* return first covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ); + + /* return last covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ); + + /* return number of covered glyphs */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator otvalid ); + + FT_LOCAL( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator otvalid ); + + /* lookups must already be validated */ + FT_LOCAL( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator otvalid ); + + /* features must already be validated */ + FT_LOCAL( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator otvalid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define ChainPosClassSetFunc otv_x_Ox +#define ChainPosRuleSetFunc otv_x_Ox +#define ChainSubClassSetFunc otv_x_Ox +#define ChainSubRuleSetFunc otv_x_Ox +#define JstfLangSysFunc otv_x_Ox +#define JstfMaxFunc otv_x_Ox +#define LigGlyphFunc otv_x_Ox +#define LigatureArrayFunc otv_x_Ox +#define LigatureSetFunc otv_x_Ox +#define PosClassSetFunc otv_x_Ox +#define PosRuleSetFunc otv_x_Ox +#define SubClassSetFunc otv_x_Ox +#define SubRuleSetFunc otv_x_Ox + + FT_LOCAL( void ) + otv_x_Ox ( FT_Bytes table, + OTV_Validator otvalid ); + +#define AlternateSubstFormat1Func otv_u_C_x_Ox +#define ChainContextPosFormat1Func otv_u_C_x_Ox +#define ChainContextSubstFormat1Func otv_u_C_x_Ox +#define ContextPosFormat1Func otv_u_C_x_Ox +#define ContextSubstFormat1Func otv_u_C_x_Ox +#define LigatureSubstFormat1Func otv_u_C_x_Ox +#define MultipleSubstFormat1Func otv_u_C_x_Ox + + FT_LOCAL( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator otvalid ); + +#define AlternateSetFunc otv_x_ux +#define AttachPointFunc otv_x_ux +#define ExtenderGlyphFunc otv_x_ux +#define JstfGPOSModListFunc otv_x_ux +#define JstfGSUBModListFunc otv_x_ux +#define SequenceFunc otv_x_ux + + FT_LOCAL( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator otvalid ); + +#define PosClassRuleFunc otv_x_y_ux_sy +#define PosRuleFunc otv_x_y_ux_sy +#define SubClassRuleFunc otv_x_y_ux_sy +#define SubRuleFunc otv_x_y_ux_sy + + FT_LOCAL( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainPosClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainPosRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubClassRuleFunc otv_x_ux_y_uy_z_uz_p_sp +#define ChainSubRuleFunc otv_x_ux_y_uy_z_uz_p_sp + + FT_LOCAL( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator otvalid ); + +#define ContextPosFormat2Func otv_u_O_O_x_Onx +#define ContextSubstFormat2Func otv_u_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ); + +#define ContextPosFormat3Func otv_u_x_y_Ox_sy +#define ContextSubstFormat3Func otv_u_x_y_Ox_sy + + FT_LOCAL( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainContextPosFormat2Func otv_u_O_O_O_O_x_Onx +#define ChainContextSubstFormat2Func otv_u_O_O_O_O_x_Onx + + FT_LOCAL( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator otvalid ); + +#define ChainContextPosFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp +#define ChainContextSubstFormat3Func otv_u_x_Ox_y_Oy_z_Oz_p_sp + + FT_LOCAL( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator otvalid ); + + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ); + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ); + + /* */ + +FT_END_HEADER + +#endif /* OTVCOMMN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otverror.h b/Dependencies/freetype/freetype/src/otvalid/otverror.h new file mode 100644 index 00000000..7f4dd6eb --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otverror.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * otverror.h + * + * OpenType validation module error codes (specification only). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the OpenType validation module error + * enumeration constants. + * + */ + +#ifndef OTVERROR_H_ +#define OTVERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX OTV_Err_ +#define FT_ERR_BASE FT_Mod_Err_OTvalid + +#include + +#endif /* OTVERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvgdef.c b/Dependencies/freetype/freetype/src/otvalid/otvgdef.c new file mode 100644 index 00000000..e36cda75 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvgdef.c @@ -0,0 +1,303 @@ +/**************************************************************************** + * + * otvgdef.c + * + * OpenType GDEF table validation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgdef + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AttachListFunc otv_O_x_Ox +#define LigCaretListFunc otv_O_x_Ox + + /* sets valid->extra1 (0) */ + + static void + otv_O_x_Ox( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_Bytes Coverage; + FT_UInt GlyphCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( Coverage, otvalid, (FT_Int)GlyphCount ); + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = 0; + + for ( ; GlyphCount > 0; GlyphCount-- ) + func( table + FT_NEXT_USHORT( p ), otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LIGATURE CARETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define CaretValueFunc otv_CaretValue_validate + + static void + otv_CaretValue_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt CaretValueFormat; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + + CaretValueFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); + + switch ( CaretValueFormat ) + { + case 1: /* CaretValueFormat1 */ + /* skip Coordinate, no test */ + break; + + case 2: /* CaretValueFormat2 */ + /* skip CaretValuePoint, no test */ + break; + + case 3: /* CaretValueFormat3 */ + p += 2; /* skip Coordinate */ + + OTV_LIMIT_CHECK( 2 ); + + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK GLYPH SETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkGlyphSets_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MarkGlyphSetCount; + + + OTV_NAME_ENTER( "MarkGlyphSets" ); + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + MarkGlyphSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkGlyphSetCount = %d)\n", MarkGlyphSetCount )); + + OTV_LIMIT_CHECK( MarkGlyphSetCount * 4 ); /* CoverageOffsets */ + + for ( ; MarkGlyphSetCount > 0; MarkGlyphSetCount-- ) + otv_Coverage_validate( table + FT_NEXT_ULONG( p ), otvalid, -1 ); + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GDEF TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_Bool need_MarkAttachClassDef = 1; + + OTV_OPTIONAL_TABLE( GlyphClassDef ); + OTV_OPTIONAL_TABLE( AttachListOffset ); + OTV_OPTIONAL_TABLE( LigCaretListOffset ); + OTV_OPTIONAL_TABLE( MarkAttachClassDef ); + OTV_OPTIONAL_TABLE( MarkGlyphSetsDef ); + + OTV_OPTIONAL_TABLE32( itemVarStore ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GDEF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + /* MarkAttachClassDef has been added to the OpenType */ + /* specification without increasing GDEF's version, */ + /* so we use this ugly hack to find out whether the */ + /* table is needed actually. */ + + need_MarkAttachClassDef = FT_BOOL( + otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || + otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); + + if ( need_MarkAttachClassDef ) + { + OTV_LIMIT_CHECK( 8 ); + table_size += 2; + } + else + OTV_LIMIT_CHECK( 6 ); /* OpenType < 1.2 */ + + break; + + case 2: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + case 3: + OTV_LIMIT_CHECK( 14 ); + table_size += 8; + break; + + default: + FT_INVALID_FORMAT; + } + + otvalid->glyph_count = glyph_count; + + OTV_OPTIONAL_OFFSET( GlyphClassDef ); + OTV_SIZE_CHECK( GlyphClassDef ); + if ( GlyphClassDef ) + otv_ClassDef_validate( table + GlyphClassDef, otvalid ); + + OTV_OPTIONAL_OFFSET( AttachListOffset ); + OTV_SIZE_CHECK( AttachListOffset ); + if ( AttachListOffset ) + { + OTV_NEST2( AttachList, AttachPoint ); + OTV_RUN( table + AttachListOffset, otvalid ); + } + + OTV_OPTIONAL_OFFSET( LigCaretListOffset ); + OTV_SIZE_CHECK( LigCaretListOffset ); + if ( LigCaretListOffset ) + { + OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); + OTV_RUN( table + LigCaretListOffset, otvalid ); + } + + if ( need_MarkAttachClassDef ) + { + OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); + OTV_SIZE_CHECK( MarkAttachClassDef ); + if ( MarkAttachClassDef ) + otv_ClassDef_validate( table + MarkAttachClassDef, otvalid ); + } + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET( MarkGlyphSetsDef ); + OTV_SIZE_CHECK( MarkGlyphSetsDef ); + if ( MarkGlyphSetsDef ) + otv_MarkGlyphSets_validate( table + MarkGlyphSetsDef, otvalid ); + } + + if ( version > 2 ) + { + OTV_OPTIONAL_OFFSET32( itemVarStore ); + OTV_SIZE_CHECK32( itemVarStore ); + if ( itemVarStore ) + OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvgpos.c b/Dependencies/freetype/freetype/src/otvalid/otvgpos.c new file mode 100644 index 00000000..d7547a33 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvgpos.c @@ -0,0 +1,1051 @@ +/**************************************************************************** + * + * otvgpos.c + * + * OpenType GPOS table validation (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgpos + + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ); + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define BaseArrayFunc otv_x_sxy +#define LigatureAttachFunc otv_x_sxy +#define Mark2ArrayFunc otv_x_sxy + + /* uses valid->extra1 (counter) */ + /* uses valid->extra2 (boolean to handle NULL anchor field) */ + + static void + otv_x_sxy( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Count, count1, table_size; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 ); + + table_size = Count * otvalid->extra1 * 2 + 2; + + for ( ; Count > 0; Count-- ) + for ( count1 = otvalid->extra1; count1 > 0; count1-- ) + { + OTV_OPTIONAL_TABLE( anchor_offset ); + + + OTV_OPTIONAL_OFFSET( anchor_offset ); + + if ( otvalid->extra2 ) + { + OTV_SIZE_CHECK( anchor_offset ); + if ( anchor_offset ) + otv_Anchor_validate( table + anchor_offset, otvalid ); + } + else + otv_Anchor_validate( table + anchor_offset, otvalid ); + } + + OTV_EXIT; + } + + +#define MarkBasePosFormat1Func otv_u_O_O_u_O_O +#define MarkLigPosFormat1Func otv_u_O_O_u_O_O +#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O + + /* sets otvalid->extra1 (class count) */ + + static void + otv_u_O_O_u_O_O( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt Coverage1, Coverage2, ClassCount; + FT_UInt Array1, Array2; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip PosFormat */ + + OTV_LIMIT_CHECK( 10 ); + Coverage1 = FT_NEXT_USHORT( p ); + Coverage2 = FT_NEXT_USHORT( p ); + ClassCount = FT_NEXT_USHORT( p ); + Array1 = FT_NEXT_USHORT( p ); + Array2 = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage1, otvalid, -1 ); + otv_Coverage_validate( table + Coverage2, otvalid, -1 ); + + otv_MarkArray_validate( table + Array1, otvalid ); + + otvalid->nesting_level++; + func = otvalid->func[otvalid->nesting_level]; + otvalid->extra1 = ClassCount; + + func( table + Array2, otvalid ); + + otvalid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALUE RECORDS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_UInt + otv_value_length( FT_UInt format ) + { + FT_UInt count; + + + count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); + count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); + count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); + + return count * 2; + } + + + /* uses otvalid->extra3 (pointer to base table) */ + + static void + otv_ValueRecord_validate( FT_Bytes table, + FT_UInt format, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt count; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Int loop; + FT_ULong res = 0; + + + OTV_NAME_ENTER( "ValueRecord" ); + + /* display `format' in dual representation */ + for ( loop = 7; loop >= 0; loop-- ) + { + res <<= 4; + res += ( format >> loop ) & 1; + } + + OTV_TRACE(( " (format 0b%08lx)\n", res )); +#endif + + if ( format >= 0x100 ) + FT_INVALID_FORMAT; + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + /* XPlacement, YPlacement, XAdvance, YAdvance */ + OTV_LIMIT_CHECK( 2 ); + p += 2; + } + + format >>= 1; + } + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + FT_PtrDist table_size; + + OTV_OPTIONAL_TABLE( device ); + + + /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ + OTV_LIMIT_CHECK( 2 ); + OTV_OPTIONAL_OFFSET( device ); + + table_size = p - otvalid->extra3; + + OTV_SIZE_CHECK( device ); + if ( device ) + otv_Device_validate( otvalid->extra3 + device, otvalid ); + } + format >>= 1; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ANCHORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt AnchorFormat; + + + OTV_NAME_ENTER( "Anchor"); + + OTV_LIMIT_CHECK( 6 ); + AnchorFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", AnchorFormat )); + + p += 4; /* skip XCoordinate and YCoordinate */ + + switch ( AnchorFormat ) + { + case 1: + break; + + case 2: + OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ + break; + + case 3: + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( XDeviceTable ); + OTV_OPTIONAL_TABLE( YDeviceTable ); + + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( XDeviceTable ); + OTV_OPTIONAL_OFFSET( YDeviceTable ); + + table_size = 6 + 4; + + OTV_SIZE_CHECK( XDeviceTable ); + if ( XDeviceTable ) + otv_Device_validate( table + XDeviceTable, otvalid ); + + OTV_SIZE_CHECK( YDeviceTable ); + if ( YDeviceTable ) + otv_Device_validate( table + YDeviceTable, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK ARRAYS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MarkCount; + + + OTV_NAME_ENTER( "MarkArray" ); + + OTV_LIMIT_CHECK( 2 ); + MarkCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + + OTV_LIMIT_CHECK( MarkCount * 4 ); + + /* MarkRecord */ + for ( ; MarkCount > 0; MarkCount-- ) + { + p += 2; /* skip Class */ + /* MarkAnchor */ + otv_Anchor_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_SinglePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "SinglePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + otvalid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* SinglePosFormat1 */ + { + FT_UInt Coverage, ValueFormat; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ValueRecord_validate( p, ValueFormat, otvalid ); /* Value */ + } + break; + + case 2: /* SinglePosFormat2 */ + { + FT_UInt Coverage, ValueFormat, ValueCount, len_value; + + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + ValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + + len_value = otv_value_length( ValueFormat ); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)ValueCount ); + + OTV_LIMIT_CHECK( ValueCount * len_value ); + + /* Value */ + for ( ; ValueCount > 0; ValueCount-- ) + { + otv_ValueRecord_validate( p, ValueFormat, otvalid ); + p += len_value; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_PairSet_validate( FT_Bytes table, + FT_UInt format1, + FT_UInt format2, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt value_len1, value_len2, PairValueCount; + + + OTV_NAME_ENTER( "PairSet" ); + + otvalid->extra3 = table; + + OTV_LIMIT_CHECK( 2 ); + PairValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + + value_len1 = otv_value_length( format1 ); + value_len2 = otv_value_length( format2 ); + + OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); + + /* PairValueRecord */ + for ( ; PairValueCount > 0; PairValueCount-- ) + { + p += 2; /* skip SecondGlyph */ + + if ( format1 ) + otv_ValueRecord_validate( p, format1, otvalid ); /* Value1 */ + p += value_len1; + + if ( format2 ) + otv_ValueRecord_validate( p, format2, otvalid ); /* Value2 */ + p += value_len2; + } + + OTV_EXIT; + } + + + /* sets otvalid->extra3 (pointer to base table) */ + + static void + otv_PairPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "PairPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* PairPosFormat1 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; + + + OTV_LIMIT_CHECK( 8 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + PairSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + + OTV_LIMIT_CHECK( PairSetCount * 2 ); + + /* PairSetOffset */ + for ( ; PairSetCount > 0; PairSetCount-- ) + otv_PairSet_validate( table + FT_NEXT_USHORT( p ), + ValueFormat1, ValueFormat2, otvalid ); + } + break; + + case 2: /* PairPosFormat2 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; + FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; + + + OTV_LIMIT_CHECK( 14 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + ClassDef1 = FT_NEXT_USHORT( p ); + ClassDef2 = FT_NEXT_USHORT( p ); + ClassCount1 = FT_NEXT_USHORT( p ); + ClassCount2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + + len_value1 = otv_value_length( ValueFormat1 ); + len_value2 = otv_value_length( ValueFormat2 ); + + otv_Coverage_validate( table + Coverage, otvalid, -1 ); + otv_ClassDef_validate( table + ClassDef1, otvalid ); + otv_ClassDef_validate( table + ClassDef2, otvalid ); + + OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * + ( len_value1 + len_value2 ) ); + + otvalid->extra3 = table; + + /* Class1Record */ + for ( ; ClassCount1 > 0; ClassCount1-- ) + { + /* Class2Record */ + for ( count = ClassCount2; count > 0; count-- ) + { + if ( ValueFormat1 ) + /* Value1 */ + otv_ValueRecord_validate( p, ValueFormat1, otvalid ); + p += len_value1; + + if ( ValueFormat2 ) + /* Value2 */ + otv_ValueRecord_validate( p, ValueFormat2, otvalid ); + p += len_value2; + } + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_CursivePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "CursivePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* CursivePosFormat1 */ + { + FT_UInt table_size; + FT_UInt Coverage, EntryExitCount; + + OTV_OPTIONAL_TABLE( EntryAnchor ); + OTV_OPTIONAL_TABLE( ExitAnchor ); + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + EntryExitCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)EntryExitCount ); + + OTV_LIMIT_CHECK( EntryExitCount * 4 ); + + table_size = EntryExitCount * 4 + 4; + + /* EntryExitRecord */ + for ( ; EntryExitCount > 0; EntryExitCount-- ) + { + OTV_OPTIONAL_OFFSET( EntryAnchor ); + OTV_OPTIONAL_OFFSET( ExitAnchor ); + + OTV_SIZE_CHECK( EntryAnchor ); + if ( EntryAnchor ) + otv_Anchor_validate( table + EntryAnchor, otvalid ); + + OTV_SIZE_CHECK( ExitAnchor ); + if ( ExitAnchor ) + otv_Anchor_validate( table + ExitAnchor, otvalid ); + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* UNDOCUMENTED (in OpenType 1.5): */ + /* BaseRecord tables can contain NULL pointers. */ + + /* sets otvalid->extra2 (1) */ + + static void + otv_MarkBasePos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkBasePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 1; + OTV_NEST2( MarkBasePosFormat1, BaseArray ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra2 (1) */ + + static void + otv_MarkLigPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkLigPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 1; + OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra2 (0) */ + + static void + otv_MarkMarkPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkMarkPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + otvalid->extra2 = 0; + OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ContextPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ContextPosFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ChainContextPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ChainContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ChainContextPosFormat1, + ChainPosRuleSet, ChainPosRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextPosFormat2, + ChainPosClassSet, ChainPosClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ChainContextPosFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 9 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_funcs */ + + static void + otv_ExtensionPos_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ExtensionPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* ExtensionPosFormat1 */ + { + FT_UInt ExtensionLookupType; + FT_ULong ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gpos_validate_funcs[9] = + { + otv_SinglePos_validate, + otv_PairPos_validate, + otv_CursivePos_validate, + otv_MarkBasePos_validate, + otv_MarkLigPos_validate, + otv_MarkMarkPos_validate, + otv_ContextPos_validate, + otv_ChainContextPos_validate, + otv_ExtensionPos_validate + }; + + + /* sets otvalid->type_count */ + /* sets otvalid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + otvalid->type_count = 9; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + + otv_Lookup_validate( table, otvalid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator otvalid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_UInt ScriptList, FeatureList, LookupList; + + OTV_OPTIONAL_TABLE32( featureVariations ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GPOS table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 6 ); + break; + + case 1: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + otvalid->type_count = 9; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + otvalid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + otvalid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + otvalid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( featureVariations ); + OTV_SIZE_CHECK32( featureVariations ); + if ( featureVariations ) + OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvgpos.h b/Dependencies/freetype/freetype/src/otvalid/otvgpos.h new file mode 100644 index 00000000..48a9ed0f --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvgpos.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * otvgpos.h + * + * OpenType GPOS table validator (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVGPOS_H_ +#define OTVGPOS_H_ + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ); + + +FT_END_HEADER + +#endif /* OTVGPOS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvgsub.c b/Dependencies/freetype/freetype/src/otvalid/otvgsub.c new file mode 100644 index 00000000..a479101b --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvgsub.c @@ -0,0 +1,627 @@ +/**************************************************************************** + * + * otvgsub.c + * + * OpenType GSUB table validation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvgsub + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->glyph_count */ + + static void + otv_SingleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "SingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* SingleSubstFormat1 */ + { + FT_Bytes Coverage; + FT_Int DeltaGlyphID; + FT_UInt first_cov, last_cov; + FT_UInt first_idx, last_idx; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + DeltaGlyphID = FT_NEXT_SHORT( p ); + + otv_Coverage_validate( Coverage, otvalid, -1 ); + + first_cov = otv_Coverage_get_first( Coverage ); + last_cov = otv_Coverage_get_last( Coverage ); + + /* These additions are modulo 65536. */ + first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU; + last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU; + + /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */ + /* the largest possible glyph index is 65534. For this */ + /* reason there can't be a wrap-around region, which would */ + /* imply the use of the invalid glyph index 65535. */ + if ( first_idx > last_idx ) + FT_INVALID_DATA; + + if ( last_idx >= otvalid->glyph_count ) + FT_INVALID_DATA; + } + break; + + case 2: /* SingleSubstFormat2 */ + { + FT_UInt Coverage, GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( table + Coverage, + otvalid, + (FT_Int)GlyphCount ); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (glyph count) */ + + static void + otv_MultipleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "MultipleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST2( MultipleSubstFormat1, Sequence ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (glyph count) */ + + static void + otv_AlternateSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "AlternateSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST2( AlternateSubstFormat1, AlternateSet ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define LigatureFunc otv_Ligature_validate + + /* uses otvalid->glyph_count */ + + static void + otv_Ligature_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt LigatureGlyph, CompCount; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + LigatureGlyph = FT_NEXT_USHORT( p ); + if ( LigatureGlyph >= otvalid->glyph_count ) + FT_INVALID_DATA; + + CompCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (CompCount = %d)\n", CompCount )); + + if ( CompCount == 0 ) + FT_INVALID_DATA; + + CompCount--; + + OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ + + /* no need to check the Component glyph indices */ + + OTV_EXIT; + } + + + static void + otv_LigatureSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "LigatureSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ContextSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ContextSubstFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->extra1 (lookup count) */ + + static void + otv_ChainContextSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ChainContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + otvalid->extra1 = otvalid->lookup_count; + OTV_NEST3( ChainContextSubstFormat1, + ChainSubRuleSet, ChainSubRule ); + OTV_RUN( table, otvalid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextSubstFormat2, + ChainSubClassSet, ChainSubClassRule ); + OTV_RUN( table, otvalid ); + break; + + case 3: + OTV_NEST1( ChainContextSubstFormat3 ); + OTV_RUN( table, otvalid ); + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->type_funcs */ + + static void + otv_ExtensionSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ExtensionSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ExtensionSubstFormat1 */ + { + FT_UInt ExtensionLookupType; + FT_ULong ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || + ExtensionLookupType == 7 || + ExtensionLookupType > 8 ) + FT_INVALID_DATA; + + validate = otvalid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, otvalid ); + } + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses otvalid->glyph_count */ + + static void + otv_ReverseChainSingleSubst_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table, Coverage; + FT_UInt SubstFormat; + FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; + + + OTV_NAME_ENTER( "ReverseChainSingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ReverseChainSingleSubstFormat1 */ + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + otv_Coverage_validate( Coverage, otvalid, -1 ); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 ); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count ) + FT_INVALID_DATA; + + break; + + default: + FT_INVALID_FORMAT; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gsub_validate_funcs[8] = + { + otv_SingleSubst_validate, + otv_MultipleSubst_validate, + otv_AlternateSubst_validate, + otv_LigatureSubst_validate, + otv_ContextSubst_validate, + otv_ChainContextSubst_validate, + otv_ExtensionSubst_validate, + otv_ReverseChainSingleSubst_validate + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->type_count */ + /* sets otvalid->type_funcs */ + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_UShort version; + FT_UInt ScriptList, FeatureList, LookupList; + + OTV_OPTIONAL_TABLE32( featureVariations ); + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating GSUB table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 4 ); + + if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ + FT_INVALID_FORMAT; + + version = FT_NEXT_USHORT( p ); /* minorVersion */ + + table_size = 10; + switch ( version ) + { + case 0: + OTV_LIMIT_CHECK( 6 ); + break; + + case 1: + OTV_LIMIT_CHECK( 10 ); + table_size += 4; + break; + + default: + FT_INVALID_FORMAT; + } + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + otvalid->type_count = 8; + otvalid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; + otvalid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + otvalid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + otvalid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + otvalid ); + + if ( version > 0 ) + { + OTV_OPTIONAL_OFFSET32( featureVariations ); + OTV_SIZE_CHECK32( featureVariations ); + if ( featureVariations ) + OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */ + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvjstf.c b/Dependencies/freetype/freetype/src/otvalid/otvjstf.c new file mode 100644 index 00000000..1309f6d9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvjstf.c @@ -0,0 +1,259 @@ +/**************************************************************************** + * + * otvjstf.c + * + * OpenType JSTF table validation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvjstf + + +#define JstfPriorityFunc otv_JstfPriority_validate +#define JstfLookupFunc otv_GPOS_subtable_validate + + /* uses otvalid->extra1 (GSUB lookup count) */ + /* uses otvalid->extra2 (GPOS lookup count) */ + /* sets otvalid->extra1 (counter) */ + + static void + otv_JstfPriority_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt gsub_lookup_count, gpos_lookup_count; + + OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); + OTV_OPTIONAL_TABLE( ExtensionJstfMax ); + + + OTV_ENTER; + OTV_TRACE(( "JstfPriority table\n" )); + + OTV_LIMIT_CHECK( 20 ); + + gsub_lookup_count = otvalid->extra1; + gpos_lookup_count = otvalid->extra2; + + table_size = 20; + + otvalid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); + OTV_SIZE_CHECK( ShrinkageEnableGSUB ); + if ( ShrinkageEnableGSUB ) + otv_x_ux( table + ShrinkageEnableGSUB, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); + OTV_SIZE_CHECK( ShrinkageDisableGSUB ); + if ( ShrinkageDisableGSUB ) + otv_x_ux( table + ShrinkageDisableGSUB, otvalid ); + + otvalid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); + OTV_SIZE_CHECK( ShrinkageEnableGPOS ); + if ( ShrinkageEnableGPOS ) + otv_x_ux( table + ShrinkageEnableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); + OTV_SIZE_CHECK( ShrinkageDisableGPOS ); + if ( ShrinkageDisableGPOS ) + otv_x_ux( table + ShrinkageDisableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); + OTV_SIZE_CHECK( ShrinkageJstfMax ); + if ( ShrinkageJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ShrinkageJstfMax, otvalid ); + } + + otvalid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); + OTV_SIZE_CHECK( ExtensionEnableGSUB ); + if ( ExtensionEnableGSUB ) + otv_x_ux( table + ExtensionEnableGSUB, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); + OTV_SIZE_CHECK( ExtensionDisableGSUB ); + if ( ExtensionDisableGSUB ) + otv_x_ux( table + ExtensionDisableGSUB, otvalid ); + + otvalid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); + OTV_SIZE_CHECK( ExtensionEnableGPOS ); + if ( ExtensionEnableGPOS ) + otv_x_ux( table + ExtensionEnableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); + OTV_SIZE_CHECK( ExtensionDisableGPOS ); + if ( ExtensionDisableGPOS ) + otv_x_ux( table + ExtensionDisableGPOS, otvalid ); + + OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); + OTV_SIZE_CHECK( ExtensionJstfMax ); + if ( ExtensionJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ExtensionJstfMax, otvalid ); + } + + otvalid->extra1 = gsub_lookup_count; + otvalid->extra2 = gpos_lookup_count; + + OTV_EXIT; + } + + + /* sets otvalid->extra (glyph count) */ + /* sets otvalid->func1 (otv_JstfPriority_validate) */ + + static void + otv_JstfScript_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt JstfLangSysCount; + + OTV_OPTIONAL_TABLE( ExtGlyph ); + OTV_OPTIONAL_TABLE( DefJstfLangSys ); + + + OTV_NAME_ENTER( "JstfScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( ExtGlyph ); + OTV_OPTIONAL_OFFSET( DefJstfLangSys ); + JstfLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); + + table_size = JstfLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( ExtGlyph ); + if ( ExtGlyph ) + { + otvalid->extra1 = otvalid->glyph_count; + OTV_NEST1( ExtenderGlyph ); + OTV_RUN( table + ExtGlyph, otvalid ); + } + + OTV_SIZE_CHECK( DefJstfLangSys ); + if ( DefJstfLangSys ) + { + OTV_NEST2( JstfLangSys, JstfPriority ); + OTV_RUN( table + DefJstfLangSys, otvalid ); + } + + OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); + + /* JstfLangSysRecord */ + OTV_NEST2( JstfLangSys, JstfPriority ); + for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) + { + p += 4; /* skip JstfLangSysTag */ + + OTV_RUN( table + FT_NEXT_USHORT( p ), otvalid ); + } + + OTV_EXIT; + } + + + /* sets otvalid->extra1 (GSUB lookup count) */ + /* sets otvalid->extra2 (GPOS lookup count) */ + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt JstfScriptCount; + + + otvalid->root = ftvalid; + + + FT_TRACE3(( "validating JSTF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + JstfScriptCount = FT_NEXT_USHORT( p ); + + FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); + + OTV_LIMIT_CHECK( JstfScriptCount * 6 ); + + if ( gsub ) + otvalid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); + else + otvalid->extra1 = 0; + + if ( gpos ) + otvalid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); + else + otvalid->extra2 = 0; + + otvalid->glyph_count = glyph_count; + + /* JstfScriptRecord */ + for ( ; JstfScriptCount > 0; JstfScriptCount-- ) + { + p += 4; /* skip JstfScriptTag */ + + /* JstfScript */ + otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvmath.c b/Dependencies/freetype/freetype/src/otvalid/otvmath.c new file mode 100644 index 00000000..b84845a7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvmath.c @@ -0,0 +1,453 @@ +/**************************************************************************** + * + * otvmath.c + * + * OpenType MATH table validation (body). + * + * Copyright (C) 2007-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvmath + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH TYPOGRAPHIC CONSTANTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathConstants_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + OTV_NAME_ENTER( "MathConstants" ); + + /* 56 constants, 51 have device tables */ + OTV_LIMIT_CHECK( 2 * ( 56 + 51 ) ); + table_size = 2 * ( 56 + 51 ); + + p += 4 * 2; /* First 4 constants have no device tables */ + for ( i = 0; i < 51; i++ ) + { + p += 2; /* skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH ITALICS CORRECTION *****/ + /***** MATH TOP ACCENT ATTACHMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathItalicsCorrectionInfo_validate( FT_Bytes table, + OTV_Validator otvalid, + FT_Int isItalic ) + { + FT_Bytes p = table; + FT_UInt i, cnt, table_size; + + OTV_OPTIONAL_TABLE( Coverage ); + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + FT_UNUSED( isItalic ); /* only used if tracing is active */ + + + OTV_NAME_ENTER( isItalic ? "MathItalicsCorrectionInfo" + : "MathTopAccentAttachment" ); + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( Coverage ); + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * cnt ); + table_size = 4 + 4 * cnt; + + OTV_SIZE_CHECK( Coverage ); + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)cnt ); + + for ( i = 0; i < cnt; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH KERNING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathKern_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i, cnt, table_size; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + /* OTV_NAME_ENTER( "MathKern" ); */ + + OTV_LIMIT_CHECK( 2 ); + + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * cnt + 2 ); + table_size = 4 + 4 * cnt; + + /* Heights */ + for ( i = 0; i < cnt; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + /* One more Kerning value */ + for ( i = 0; i < cnt + 1; i++ ) + { + p += 2; /* Skip the value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + } + + OTV_EXIT; + } + + + static void + otv_MathKernInfo_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt i, j, cnt, table_size; + + OTV_OPTIONAL_TABLE( Coverage ); + OTV_OPTIONAL_TABLE( MKRecordOffset ); + + + OTV_NAME_ENTER( "MathKernInfo" ); + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( Coverage ); + cnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 8 * cnt ); + table_size = 4 + 8 * cnt; + + OTV_SIZE_CHECK( Coverage ); + otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)cnt ); + + for ( i = 0; i < cnt; i++ ) + { + for ( j = 0; j < 4; j++ ) + { + OTV_OPTIONAL_OFFSET( MKRecordOffset ); + OTV_SIZE_CHECK( MKRecordOffset ); + if ( MKRecordOffset ) + otv_MathKern_validate( table + MKRecordOffset, otvalid ); + } + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH GLYPH INFO *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MathGlyphInfo_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt MathItalicsCorrectionInfo, MathTopAccentAttachment; + FT_UInt ExtendedShapeCoverage, MathKernInfo; + + + OTV_NAME_ENTER( "MathGlyphInfo" ); + + OTV_LIMIT_CHECK( 8 ); + + MathItalicsCorrectionInfo = FT_NEXT_USHORT( p ); + MathTopAccentAttachment = FT_NEXT_USHORT( p ); + ExtendedShapeCoverage = FT_NEXT_USHORT( p ); + MathKernInfo = FT_NEXT_USHORT( p ); + + if ( MathItalicsCorrectionInfo ) + otv_MathItalicsCorrectionInfo_validate( + table + MathItalicsCorrectionInfo, otvalid, TRUE ); + + /* Italic correction and Top Accent Attachment have the same format */ + if ( MathTopAccentAttachment ) + otv_MathItalicsCorrectionInfo_validate( + table + MathTopAccentAttachment, otvalid, FALSE ); + + if ( ExtendedShapeCoverage ) + { + OTV_NAME_ENTER( "ExtendedShapeCoverage" ); + otv_Coverage_validate( table + ExtendedShapeCoverage, otvalid, -1 ); + OTV_EXIT; + } + + if ( MathKernInfo ) + otv_MathKernInfo_validate( table + MathKernInfo, otvalid ); + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH GLYPH CONSTRUCTION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_GlyphAssembly_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt pcnt, table_size; + FT_UInt i; + + OTV_OPTIONAL_TABLE( DeviceTableOffset ); + + + /* OTV_NAME_ENTER( "GlyphAssembly" ); */ + + OTV_LIMIT_CHECK( 6 ); + + p += 2; /* Skip the Italics Correction value */ + OTV_OPTIONAL_OFFSET( DeviceTableOffset ); + pcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 8 * pcnt ); + table_size = 6 + 8 * pcnt; + + OTV_SIZE_CHECK( DeviceTableOffset ); + if ( DeviceTableOffset ) + otv_Device_validate( table + DeviceTableOffset, otvalid ); + + for ( i = 0; i < pcnt; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + p += 2*4; /* skip the Start, End, Full, and Flags fields */ + } + + /* OTV_EXIT; */ + } + + + static void + otv_MathGlyphConstruction_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt vcnt, table_size; + FT_UInt i; + + OTV_OPTIONAL_TABLE( GlyphAssembly ); + + + /* OTV_NAME_ENTER( "MathGlyphConstruction" ); */ + + OTV_LIMIT_CHECK( 4 ); + + OTV_OPTIONAL_OFFSET( GlyphAssembly ); + vcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 4 * vcnt ); + table_size = 4 + 4 * vcnt; + + for ( i = 0; i < vcnt; i++ ) + { + FT_UInt gid; + + + gid = FT_NEXT_USHORT( p ); + if ( gid >= otvalid->glyph_count ) + FT_INVALID_GLYPH_ID; + p += 2; /* skip the size */ + } + + OTV_SIZE_CHECK( GlyphAssembly ); + if ( GlyphAssembly ) + otv_GlyphAssembly_validate( table+GlyphAssembly, otvalid ); + + /* OTV_EXIT; */ + } + + + static void + otv_MathVariants_validate( FT_Bytes table, + OTV_Validator otvalid ) + { + FT_Bytes p = table; + FT_UInt vcnt, hcnt, i, table_size; + + OTV_OPTIONAL_TABLE( VCoverage ); + OTV_OPTIONAL_TABLE( HCoverage ); + OTV_OPTIONAL_TABLE( Offset ); + + + OTV_NAME_ENTER( "MathVariants" ); + + OTV_LIMIT_CHECK( 10 ); + + p += 2; /* Skip the MinConnectorOverlap constant */ + OTV_OPTIONAL_OFFSET( VCoverage ); + OTV_OPTIONAL_OFFSET( HCoverage ); + vcnt = FT_NEXT_USHORT( p ); + hcnt = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( 2 * vcnt + 2 * hcnt ); + table_size = 10 + 2 * vcnt + 2 * hcnt; + + OTV_SIZE_CHECK( VCoverage ); + if ( VCoverage ) + otv_Coverage_validate( table + VCoverage, otvalid, (FT_Int)vcnt ); + + OTV_SIZE_CHECK( HCoverage ); + if ( HCoverage ) + otv_Coverage_validate( table + HCoverage, otvalid, (FT_Int)hcnt ); + + for ( i = 0; i < vcnt; i++ ) + { + OTV_OPTIONAL_OFFSET( Offset ); + OTV_SIZE_CHECK( Offset ); + otv_MathGlyphConstruction_validate( table + Offset, otvalid ); + } + + for ( i = 0; i < hcnt; i++ ) + { + OTV_OPTIONAL_OFFSET( Offset ); + OTV_SIZE_CHECK( Offset ); + otv_MathGlyphConstruction_validate( table + Offset, otvalid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MATH TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets otvalid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_MATH_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec otvalidrec; + OTV_Validator otvalid = &otvalidrec; + FT_Bytes p = table; + FT_UInt MathConstants, MathGlyphInfo, MathVariants; + + + otvalid->root = ftvalid; + + FT_TRACE3(( "validating MATH table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + MathConstants = FT_NEXT_USHORT( p ); + MathGlyphInfo = FT_NEXT_USHORT( p ); + MathVariants = FT_NEXT_USHORT( p ); + + otvalid->glyph_count = glyph_count; + + otv_MathConstants_validate( table + MathConstants, + otvalid ); + otv_MathGlyphInfo_validate( table + MathGlyphInfo, + otvalid ); + otv_MathVariants_validate ( table + MathVariants, + otvalid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvmod.c b/Dependencies/freetype/freetype/src/otvalid/otvmod.c new file mode 100644 index 00000000..74e50c78 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvmod.c @@ -0,0 +1,281 @@ +/**************************************************************************** + * + * otvmod.c + * + * FreeType's OpenType validation module implementation (body). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "otvmod.h" +#include "otvalid.h" +#include "otvcommn.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otvmodule + + + static FT_Error + otv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* volatile* table, + FT_ULong* table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + return FT_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_QALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + + static FT_Error + otv_validate( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *ot_base, + FT_Bytes *ot_gdef, + FT_Bytes *ot_gpos, + FT_Bytes *ot_gsub, + FT_Bytes *ot_jstf ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* volatile base; + FT_Byte* volatile gdef; + FT_Byte* volatile gpos; + FT_Byte* volatile gsub; + FT_Byte* volatile jstf; + FT_Byte* volatile math; + FT_ULong len_base, len_gdef, len_gpos, len_gsub, len_jstf; + FT_ULong len_math; + FT_UInt num_glyphs = (FT_UInt)face->num_glyphs; + FT_ValidatorRec volatile valid; + + + base = gdef = gpos = gsub = jstf = math = NULL; + len_base = len_gdef = len_gpos = len_gsub = len_jstf = len_math = 0; + + /* + * XXX: OpenType tables cannot handle 32-bit glyph index, + * although broken TrueType can have 32-bit glyph index. + */ + if ( face->num_glyphs > 0xFFFFL ) + { + FT_TRACE1(( "otv_validate: Invalid glyphs index (0x0000FFFF - 0x%08lx) ", + face->num_glyphs )); + FT_TRACE1(( "are not handled by OpenType tables\n" )); + num_glyphs = 0xFFFF; + } + + /* load tables */ + + if ( ot_flags & FT_VALIDATE_BASE ) + { + error = otv_load_table( face, TTAG_BASE, &base, &len_base ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GDEF ) + { + error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GPOS ) + { + error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GSUB ) + { + error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_JSTF ) + { + error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_MATH ) + { + error = otv_load_table( face, TTAG_MATH, &math, &len_math ); + if ( error ) + goto Exit; + } + + /* validate tables */ + + if ( base ) + { + ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_BASE_validate( base, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gpos ) + { + ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GPOS_validate( gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gsub ) + { + ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GSUB_validate( gsub, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gdef ) + { + ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GDEF_validate( gdef, gsub, gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( jstf ) + { + ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_JSTF_validate( jstf, gsub, gpos, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( math ) + { + ft_validator_init( &valid, math, math + len_math, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_MATH_validate( math, num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ot_base = (FT_Bytes)base; + *ot_gdef = (FT_Bytes)gdef; + *ot_gpos = (FT_Bytes)gpos; + *ot_gsub = (FT_Bytes)gsub; + *ot_jstf = (FT_Bytes)jstf; + + Exit: + if ( error ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( base ); + FT_FREE( gdef ); + FT_FREE( gpos ); + FT_FREE( gsub ); + FT_FREE( jstf ); + } + + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( math ); /* Can't return this as API is frozen */ + } + + return error; + } + + + static + const FT_Service_OTvalidateRec otvalid_interface = + { + otv_validate /* validate */ + }; + + + static + const FT_ServiceDescRec otvalid_services[] = + { + { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + otvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( otvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class otv_module_class = + { + 0, + sizeof ( FT_ModuleRec ), + "otvalid", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) otvalid_get_service /* get_interface */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/otvalid/otvmod.h b/Dependencies/freetype/freetype/src/otvalid/otvmod.h new file mode 100644 index 00000000..245c7802 --- /dev/null +++ b/Dependencies/freetype/freetype/src/otvalid/otvmod.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * otvmod.h + * + * FreeType's OpenType validation module implementation + * (specification). + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTVMOD_H_ +#define OTVMOD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) otv_module_class; + + +FT_END_HEADER + +#endif /* OTVMOD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/README b/Dependencies/freetype/freetype/src/pcf/README new file mode 100644 index 00000000..09ea970e --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/README @@ -0,0 +1,96 @@ + FreeType font driver for PCF fonts + + Francesco Zappa Nardelli + + + +Introduction +************ + +PCF (Portable Compiled Format) is a binary bitmap font format, largely used +in X world. This code implements a PCF driver for the FreeType library. +Glyph images are loaded into memory only on demand, thus leading to a small +memory footprint. + +Information on the PCF font format can only be worked out from +`pcfread.c', and `pcfwrite.c', to be found, for instance, in the XFree86 +(www.xfree86.org) source tree (xc/lib/font/bitmap/). + +Many good bitmap fonts in bdf format come with XFree86: they can be +compiled into the pcf format using the `bdftopcf' utility. + + +Supported hardware +****************** + +The driver has been tested on linux/x86 and sunos5.5/sparc. In both +cases the compiler was gcc. When back in Paris, I will test it also +on linux/alpha. + + +Encodings +********* + +Use `FT_Get_BDF_Charset_ID' to access the encoding and registry. + +The driver always exports `ft_encoding_none' as face->charmap.encoding. +FT_Get_Char_Index() behavior is unmodified, that is, it converts the ULong +value given as argument into the corresponding glyph number. + + +Known problems +************** + +- dealing explicitly with encodings breaks the uniformity of FreeType 2 + API. + +- except for encodings properties, client applications have no + visibility of the PCF_Face object. This means that applications + cannot directly access font tables and are obliged to trust + FreeType. + +- currently, glyph names and ink_metrics are ignored. + +I plan to give full visibility of the PCF_Face object in the next +release of the driver, thus implementing also glyph names and +ink_metrics. + +- height is defined as (ascent - descent). Is this correct? + +- if unable to read size information from the font, PCF_Init_Face + sets available_size->width and available_size->height to 12. + +- too many english grammar errors in the readme file :-( + + +License +******* + +Copyright (C) 2000 by Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Credits +******* + +Keith Packard wrote the pcf driver found in XFree86. His work is at +the same time the specification and the sample implementation of the +PCF format. Undoubtedly, this driver is inspired from his work. diff --git a/Dependencies/freetype/freetype/src/pcf/pcf.c b/Dependencies/freetype/freetype/src/pcf/pcf.c new file mode 100644 index 00000000..6b30fb24 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcf.c @@ -0,0 +1,35 @@ +/* pcf.c + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2003 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pcfdrivr.c" +#include "pcfread.c" +#include "pcfutil.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcf.h b/Dependencies/freetype/freetype/src/pcf/pcf.h new file mode 100644 index 00000000..3134cc35 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcf.h @@ -0,0 +1,251 @@ +/* pcf.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002, 2003, 2006, 2010 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef PCF_H_ +#define PCF_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + typedef struct PCF_TableRec_ + { + FT_ULong type; + FT_ULong format; + FT_ULong size; + FT_ULong offset; + + } PCF_TableRec, *PCF_Table; + + + typedef struct PCF_TocRec_ + { + FT_ULong version; + FT_ULong count; + PCF_Table tables; + + } PCF_TocRec, *PCF_Toc; + + + typedef struct PCF_ParsePropertyRec_ + { + FT_Long name; + FT_Byte isString; + FT_Long value; + + } PCF_ParsePropertyRec, *PCF_ParseProperty; + + + typedef struct PCF_PropertyRec_ + { + FT_String* name; + FT_Byte isString; + + union + { + FT_String* atom; + FT_Long l; + FT_ULong ul; + + } value; + + } PCF_PropertyRec, *PCF_Property; + + + typedef struct PCF_Compressed_MetricRec_ + { + FT_Byte leftSideBearing; + FT_Byte rightSideBearing; + FT_Byte characterWidth; + FT_Byte ascent; + FT_Byte descent; + + } PCF_Compressed_MetricRec, *PCF_Compressed_Metric; + + + typedef struct PCF_MetricRec_ + { + FT_Short leftSideBearing; + FT_Short rightSideBearing; + FT_Short characterWidth; + FT_Short ascent; + FT_Short descent; + FT_Short attributes; + + FT_ULong bits; /* offset into the PCF_BITMAPS table */ + + } PCF_MetricRec, *PCF_Metric; + + + typedef struct PCF_EncRec_ + { + FT_UShort firstCol; + FT_UShort lastCol; + FT_UShort firstRow; + FT_UShort lastRow; + FT_UShort defaultChar; + + FT_UShort* offset; + + } PCF_EncRec, *PCF_Enc; + + + typedef struct PCF_AccelRec_ + { + FT_Byte noOverlap; + FT_Byte constantMetrics; + FT_Byte terminalFont; + FT_Byte constantWidth; + FT_Byte inkInside; + FT_Byte inkMetrics; + FT_Byte drawDirection; + FT_Long fontAscent; + FT_Long fontDescent; + FT_Long maxOverlap; + PCF_MetricRec minbounds; + PCF_MetricRec maxbounds; + PCF_MetricRec ink_minbounds; + PCF_MetricRec ink_maxbounds; + + } PCF_AccelRec, *PCF_Accel; + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a `character code' in FreeType speak. + */ + typedef struct PCF_FaceRec_ + { + FT_FaceRec root; + + FT_StreamRec comp_stream; + FT_Stream comp_source; + + char* charset_encoding; + char* charset_registry; + + PCF_TocRec toc; + PCF_AccelRec accel; + + int nprops; + PCF_Property properties; + + FT_ULong nmetrics; + PCF_Metric metrics; + + PCF_EncRec enc; + + FT_ULong bitmapsFormat; + + } PCF_FaceRec, *PCF_Face; + + + typedef struct PCF_DriverRec_ + { + FT_DriverRec root; + + FT_Bool no_long_family_names; + + } PCF_DriverRec, *PCF_Driver; + + + /* macros for pcf font format */ + +#define LSBFirst 0 +#define MSBFirst 1 + +#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \ + ( 'c' << 16 ) | \ + ( 'f' << 8 ) | 1 ) +#define PCF_FORMAT_MASK 0xFFFFFF00UL + +#define PCF_DEFAULT_FORMAT 0x00000000UL +#define PCF_INKBOUNDS 0x00000200UL +#define PCF_ACCEL_W_INKBOUNDS 0x00000100UL +#define PCF_COMPRESSED_METRICS 0x00000100UL + +#define PCF_FORMAT_MATCH( a, b ) \ + ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) ) + +#define PCF_GLYPH_PAD_MASK ( 3 << 0 ) +#define PCF_BYTE_MASK ( 1 << 2 ) +#define PCF_BIT_MASK ( 1 << 3 ) +#define PCF_SCAN_UNIT_MASK ( 3 << 4 ) + +#define PCF_BYTE_ORDER( f ) \ + ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_BIT_ORDER( f ) \ + ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_GLYPH_PAD_INDEX( f ) \ + ( (f) & PCF_GLYPH_PAD_MASK ) +#define PCF_GLYPH_PAD( f ) \ + ( 1 << PCF_GLYPH_PAD_INDEX( f ) ) +#define PCF_SCAN_UNIT_INDEX( f ) \ + ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 ) +#define PCF_SCAN_UNIT( f ) \ + ( 1 << PCF_SCAN_UNIT_INDEX( f ) ) +#define PCF_FORMAT_BITS( f ) \ + ( (f) & ( PCF_GLYPH_PAD_MASK | \ + PCF_BYTE_MASK | \ + PCF_BIT_MASK | \ + PCF_SCAN_UNIT_MASK ) ) + +#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 ) +#define PCF_INDEX_TO_SIZE( b ) ( 1 << b ) + +#define PCF_FORMAT( bit, byte, glyph, scan ) \ + ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \ + ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \ + ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \ + ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) ) + +#define PCF_PROPERTIES ( 1 << 0 ) +#define PCF_ACCELERATORS ( 1 << 1 ) +#define PCF_METRICS ( 1 << 2 ) +#define PCF_BITMAPS ( 1 << 3 ) +#define PCF_INK_METRICS ( 1 << 4 ) +#define PCF_BDF_ENCODINGS ( 1 << 5 ) +#define PCF_SWIDTHS ( 1 << 6 ) +#define PCF_GLYPH_NAMES ( 1 << 7 ) +#define PCF_BDF_ACCELERATORS ( 1 << 8 ) + +#define GLYPHPADOPTIONS 4 /* I'm not sure about this */ + + FT_LOCAL( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face, + FT_Long face_index ); + +FT_END_HEADER + +#endif /* PCF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfdrivr.c b/Dependencies/freetype/freetype/src/pcf/pcfdrivr.c new file mode 100644 index 00000000..93632f17 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfdrivr.c @@ -0,0 +1,836 @@ +/* pcfdrivr.c + + FreeType font driver for pcf files + + Copyright (C) 2000-2004, 2006-2011, 2013, 2014 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcf.h" +#include "pcfdrivr.h" +#include "pcfread.h" + +#include "pcferror.h" +#include "pcfutil.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pcfread + +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT pcfdriver + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a `character code' in FreeType speak. + */ + typedef struct PCF_CMapRec_ + { + FT_CMapRec root; + PCF_Enc enc; + + } PCF_CMapRec, *PCF_CMap; + + + FT_CALLBACK_DEF( FT_Error ) + pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */ + FT_Pointer init_data ) + { + PCF_CMap pcfcmap = (PCF_CMap)cmap; + PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap ); + + FT_UNUSED( init_data ); + + + pcfcmap->enc = &face->enc; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */ + { + PCF_CMap pcfcmap = (PCF_CMap)cmap; + + + pcfcmap->enc = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */ + FT_UInt32 charcode ) + { + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; + + + /* wrapped around "negative" values are also rejected */ + if ( i >= h || j >= w ) + return 0; + + return (FT_UInt)enc->offset[i * w + j]; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */ + FT_UInt32 *acharcode ) + { + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + FT_UInt32 charcode = *acharcode + 1; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; + + FT_UInt result = 0; + + + /* adjust wrapped around "negative" values */ + if ( (FT_Int32)i < 0 ) + i = 0; + if ( (FT_Int32)j < 0 ) + j = 0; + + for ( ; i < h; i++, j = 0 ) + for ( ; j < w; j++ ) + { + result = (FT_UInt)enc->offset[i * w + j]; + if ( result != 0xFFFFU ) + goto Exit; + } + + Exit: + *acharcode = ( ( i + enc->firstRow ) << 8 ) | ( j + enc->firstCol ); + + return result; + } + + + static + const FT_CMap_ClassRec pcf_cmap_class = + { + sizeof ( PCF_CMapRec ), + pcf_cmap_init, + pcf_cmap_done, + pcf_cmap_char_index, + pcf_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + + FT_CALLBACK_DEF( void ) + PCF_Face_Done( FT_Face face ) /* PCF_Face */ + { + PCF_Face pcfface = (PCF_Face)face; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + FT_FREE( pcfface->metrics ); + FT_FREE( pcfface->enc.offset ); + + /* free properties */ + if ( pcfface->properties ) + { + FT_Int i; + + + for ( i = 0; i < pcfface->nprops; i++ ) + { + PCF_Property prop = &pcfface->properties[i]; + + + if ( prop ) + { + FT_FREE( prop->name ); + if ( prop->isString ) + FT_FREE( prop->value.atom ); + } + } + + FT_FREE( pcfface->properties ); + } + + FT_FREE( pcfface->toc.tables ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); + FT_FREE( face->available_sizes ); + FT_FREE( pcfface->charset_encoding ); + FT_FREE( pcfface->charset_registry ); + + /* close compressed stream if any */ + if ( face->stream == &pcfface->comp_stream ) + { + FT_Stream_Close( &pcfface->comp_stream ); + face->stream = pcfface->comp_source; + } + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Face_Init( FT_Stream stream, + FT_Face face, /* PCF_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PCF_Face pcfface = (PCF_Face)face; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "PCF driver\n" )); + + error = pcf_load_font( stream, pcfface, face_index ); + if ( error ) + { + PCF_Face_Done( face ); + +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_LZW ) || \ + defined( FT_CONFIG_OPTION_USE_BZIP2 ) + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + { + FT_Error error2; + + + /* this didn't work, try gzip support! */ + FT_TRACE2(( " ... try gzip stream\n" )); + error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error2, Unimplemented_Feature ) ) + goto Fail; + + error = error2; + } +#endif /* FT_CONFIG_OPTION_USE_ZLIB */ + +#ifdef FT_CONFIG_OPTION_USE_LZW + if ( error ) + { + FT_Error error3; + + + /* this didn't work, try LZW support! */ + FT_TRACE2(( " ... try LZW stream\n" )); + error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error3, Unimplemented_Feature ) ) + goto Fail; + + error = error3; + } +#endif /* FT_CONFIG_OPTION_USE_LZW */ + +#ifdef FT_CONFIG_OPTION_USE_BZIP2 + if ( error ) + { + FT_Error error4; + + + /* this didn't work, try Bzip2 support! */ + FT_TRACE2(( " ... try Bzip2 stream\n" )); + error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream ); + if ( FT_ERR_EQ( error4, Unimplemented_Feature ) ) + goto Fail; + + error = error4; + } +#endif /* FT_CONFIG_OPTION_USE_BZIP2 */ + + if ( error ) + goto Fail; + + pcfface->comp_source = stream; + face->stream = &pcfface->comp_stream; + + stream = face->stream; + + error = pcf_load_font( stream, pcfface, face_index ); + if ( error ) + goto Fail; + +#else /* !(FT_CONFIG_OPTION_USE_ZLIB || + FT_CONFIG_OPTION_USE_LZW || + FT_CONFIG_OPTION_USE_BZIP2) */ + + goto Fail; + +#endif + } + + /* PCF cannot have multiple faces in a single font file. + * XXX: A non-zero face_index is already an invalid argument, but + * Type1, Type42 drivers have a convention to return + * an invalid argument error when the font could be + * opened by the specified driver. + */ + if ( face_index < 0 ) + goto Exit; + else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "PCF_Face_Init: invalid face index\n" )); + PCF_Face_Done( face ); + return FT_THROW( Invalid_Argument ); + } + + /* set up charmap */ + { + FT_String *charset_registry = pcfface->charset_registry; + FT_String *charset_encoding = pcfface->charset_encoding; + FT_Bool unicode_charmap = 0; + + + if ( charset_registry && charset_encoding ) + { + char* s = charset_registry; + + + /* Uh, oh, compare first letters manually to avoid dependency + on locales. */ + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( pcfface->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + /* another name for ASCII */ + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( pcfface->charset_encoding, "IRV" ) ) + unicode_charmap = 1; + } + } + + { + FT_CharMapRec charmap; + + + charmap.face = face; + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + + error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL ); + } + } + + Exit: + return error; + + Fail: + FT_TRACE2(( " not a PCF file\n" )); + PCF_Face_Done( face ); + error = FT_THROW( Unknown_File_Format ); /* error */ + goto Exit; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + PCF_Accel accel = &( (PCF_Face)size->face )->accel; + + + FT_Select_Metrics( size->face, strike_index ); + + size->metrics.ascender = accel->fontAscent * 64; + size->metrics.descender = -accel->fontDescent * 64; + size->metrics.max_advance = accel->maxbounds.characterWidth * 64; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + PCF_Face face = (PCF_Face)size->face; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( face->accel.fontAscent + + face->accel.fontDescent ) ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return PCF_Size_Select( size, 0 ); + } + + + FT_CALLBACK_DEF( FT_Error ) + PCF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + PCF_Face face = (PCF_Face)size->face; + FT_Stream stream; + FT_Error error = FT_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + PCF_Metric metric; + FT_ULong bytes; + + + FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index )); + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + stream = face->root.stream; + + metric = face->metrics + glyph_index; + + bitmap->rows = (unsigned int)( metric->ascent + + metric->descent ); + bitmap->width = (unsigned int)( metric->rightSideBearing - + metric->leftSideBearing ); + bitmap->num_grays = 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) + { + case 1: + bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 ); + break; + + case 2: + bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 ); + break; + + case 4: + bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 ); + break; + + case 8: + bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 ); + break; + + default: + return FT_THROW( Invalid_File_Format ); + } + + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = metric->leftSideBearing; + slot->bitmap_top = metric->ascent; + + slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 ); + slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 ); + slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 ); + slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing - + metric->leftSideBearing ) * 64 ); + slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); + + ft_synthesize_vertical_metrics( &slot->metrics, + ( face->accel.fontAscent + + face->accel.fontDescent ) * 64 ); + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + goto Exit; + + /* XXX: to do: are there cases that need repadding the bitmap? */ + bytes = (FT_ULong)bitmap->pitch * bitmap->rows; + + error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( metric->bits ) || + FT_STREAM_READ( bitmap->buffer, bytes ) ) + goto Exit; + + if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) + BitOrderInvert( bitmap->buffer, bytes ); + + if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != + PCF_BIT_ORDER( face->bitmapsFormat ) ) ) + { + switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) + { + case 1: + break; + + case 2: + TwoByteSwap( bitmap->buffer, bytes ); + break; + + case 4: + FourByteSwap( bitmap->buffer, bytes ); + break; + } + } + + Exit: + return error; + } + + + /* + * + * BDF SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pcf_get_bdf_property( FT_Face face, /* PCF_Face */ + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + PCF_Face pcfface = (PCF_Face)face; + PCF_Property prop; + + + prop = pcf_find_property( pcfface, prop_name ); + if ( prop ) + { + if ( prop->isString ) + { + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + } + else + { + if ( prop->value.l > 0x7FFFFFFFL || + prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE2(( "pcf_get_bdf_property:" + " too large integer 0x%lx is truncated\n", + prop->value.l )); + } + + /* + * The PCF driver loads all properties as signed integers. + * This really doesn't seem to be a problem, because this is + * sufficient for any meaningful values. + */ + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + } + + return FT_Err_Ok; + } + + return FT_THROW( Invalid_Argument ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_get_charset_id( FT_Face face, /* PCF_Face */ + const char* *acharset_encoding, + const char* *acharset_registry ) + { + PCF_Face pcfface = (PCF_Face)face; + + + *acharset_encoding = pcfface->charset_encoding; + *acharset_registry = pcfface->charset_registry; + + return FT_Err_Ok; + } + + + static const FT_Service_BDFRec pcf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, /* get_charset_id */ + (FT_BDF_GetPropertyFunc) pcf_get_bdf_property /* get_property */ + }; + + + /* + * PROPERTY SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + pcf_property_set( FT_Module module, /* PCF_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + FT_Error error = FT_Err_Ok; + PCF_Driver driver = (PCF_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "no-long-family-names" ) ) + { +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long lfn = ft_strtol( s, NULL, 10 ); + + + if ( lfn == 0 ) + driver->no_long_family_names = 0; + else if ( lfn == 1 ) + driver->no_long_family_names = 1; + else + return FT_THROW( Invalid_Argument ); + } + else +#endif + { + FT_Bool* no_long_family_names = (FT_Bool*)value; + + + driver->no_long_family_names = *no_long_family_names; + } + + return error; + } + +#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_UNUSED( module ); + FT_UNUSED( value ); + FT_UNUSED( value_is_string ); +#ifndef FT_DEBUG_LEVEL_TRACE + FT_UNUSED( property_name ); +#endif + +#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_TRACE2(( "pcf_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_property_get( FT_Module module, /* PCF_Driver */ + const char* property_name, + void* value ) + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + FT_Error error = FT_Err_Ok; + PCF_Driver driver = (PCF_Driver)module; + + + if ( !ft_strcmp( property_name, "no-long-family-names" ) ) + { + FT_Bool no_long_family_names = driver->no_long_family_names; + FT_Bool* val = (FT_Bool*)value; + + + *val = no_long_family_names; + + return error; + } + +#else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_UNUSED( module ); + FT_UNUSED( value ); +#ifndef FT_DEBUG_LEVEL_TRACE + FT_UNUSED( property_name ); +#endif + +#endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + FT_TRACE2(( "pcf_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + pcf_service_properties, + + (FT_Properties_SetFunc)pcf_property_set, /* set_property */ + (FT_Properties_GetFunc)pcf_property_get ) /* get_property */ + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pcf_services[] = + { + { FT_SERVICE_ID_BDF, &pcf_service_bdf }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF }, + { FT_SERVICE_ID_PROPERTIES, &pcf_service_properties }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pcf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pcf_services, name ); + } + + + FT_CALLBACK_DEF( FT_Error ) + pcf_driver_init( FT_Module module ) /* PCF_Driver */ + { +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + PCF_Driver driver = (PCF_Driver)module; + + + driver->no_long_family_names = 0; +#else + FT_UNUSED( module ); +#endif + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + pcf_driver_done( FT_Module module ) /* PCF_Driver */ + { + FT_UNUSED( module ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pcf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + + sizeof ( PCF_DriverRec ), + "pcf", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + pcf_driver_init, /* FT_Module_Constructor module_init */ + pcf_driver_done, /* FT_Module_Destructor module_done */ + pcf_driver_requester /* FT_Module_Requester get_interface */ + }, + + sizeof ( PCF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + PCF_Face_Init, /* FT_Face_InitFunc init_face */ + PCF_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + PCF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + PCF_Size_Request, /* FT_Size_RequestFunc request_size */ + PCF_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfdrivr.h b/Dependencies/freetype/freetype/src/pcf/pcfdrivr.h new file mode 100644 index 00000000..d4653937 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfdrivr.h @@ -0,0 +1,44 @@ +/* pcfdrivr.h + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2002 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef PCFDRIVR_H_ +#define PCFDRIVR_H_ + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class; + +FT_END_HEADER + + +#endif /* PCFDRIVR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcferror.h b/Dependencies/freetype/freetype/src/pcf/pcferror.h new file mode 100644 index 00000000..8b9e9902 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcferror.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pcferror.h + * + * PCF error codes (specification only). + * + * Copyright 2001, 2012 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PCF error enumeration constants. + * + */ + +#ifndef PCFERROR_H_ +#define PCFERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PCF_Err_ +#define FT_ERR_BASE FT_Mod_Err_PCF + +#include + +#endif /* PCFERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfread.c b/Dependencies/freetype/freetype/src/pcf/pcfread.c new file mode 100644 index 00000000..f167bcb8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfread.c @@ -0,0 +1,1731 @@ +/* pcfread.c + + FreeType font driver for pcf fonts + + Copyright 2000-2010, 2012-2014 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + + +#include +#include +#include + +#include "pcf.h" +#include "pcfread.h" + +#include "pcferror.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT pcfread + + +#ifdef FT_DEBUG_LEVEL_TRACE + static const char* const tableNames[] = + { + "properties", + "accelerators", + "metrics", + "bitmaps", + "ink metrics", + "encodings", + "swidths", + "glyph names", + "BDF accelerators" + }; +#endif + + + static + const FT_Frame_Field pcf_toc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TocRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( version ), + FT_FRAME_ULONG_LE( count ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_table_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( type ), + FT_FRAME_ULONG_LE( format ), + FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */ + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + + static FT_Error + pcf_read_TOC( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + PCF_Toc toc = &face->toc; + PCF_Table tables; + + FT_Memory memory = FT_FACE( face )->memory; + FT_UInt n; + + FT_ULong size; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) ) + return FT_THROW( Cannot_Open_Resource ); + + if ( toc->version != PCF_FILE_VERSION || + toc->count == 0 ) + return FT_THROW( Invalid_File_Format ); + + if ( stream->size < 16 ) + return FT_THROW( Invalid_File_Format ); + + /* we need 16 bytes per TOC entry, */ + /* and there can be most 9 tables */ + if ( toc->count > ( stream->size >> 4 ) || + toc->count > 9 ) + { + FT_TRACE0(( "pcf_read_TOC: adjusting number of tables" + " (from %ld to %ld)\n", + toc->count, + FT_MIN( stream->size >> 4, 9 ) )); + toc->count = FT_MIN( stream->size >> 4, 9 ); + } + + if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) ) + return error; + + tables = face->toc.tables; + for ( n = 0; n < toc->count; n++ ) + { + if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) + goto Exit; + tables++; + } + + /* Sort tables and check for overlaps. Because they are almost */ + /* always ordered already, an in-place bubble sort with simultaneous */ + /* boundary checking seems appropriate. */ + tables = face->toc.tables; + + for ( n = 0; n < toc->count - 1; n++ ) + { + FT_UInt i, have_change; + + + have_change = 0; + + for ( i = 0; i < toc->count - 1 - n; i++ ) + { + PCF_TableRec tmp; + + + if ( tables[i].offset > tables[i + 1].offset ) + { + tmp = tables[i]; + tables[i] = tables[i + 1]; + tables[i + 1] = tmp; + + have_change = 1; + } + + if ( ( tables[i].size > tables[i + 1].offset ) || + ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + } + + if ( !have_change ) + break; + } + + /* + * We now check whether the `size' and `offset' values are reasonable: + * `offset' + `size' must not exceed the stream size. + * + * Note, however, that X11's `pcfWriteFont' routine (used by the + * `bdftopcf' program to create PCF font files) has two special + * features. + * + * - It always assigns the accelerator table a size of 100 bytes in the + * TOC, regardless of its real size, which can vary between 34 and 72 + * bytes. + * + * - Due to the way the routine is designed, it ships out the last font + * table with its real size, ignoring the TOC's size value. Since + * the TOC size values are always rounded up to a multiple of 4, the + * difference can be up to three bytes for all tables except the + * accelerator table, for which the difference can be as large as 66 + * bytes. + * + */ + + tables = face->toc.tables; + size = stream->size; + + for ( n = 0; n < toc->count - 1; n++ ) + { + /* we need two checks to avoid overflow */ + if ( ( tables->size > size ) || + ( tables->offset > size - tables->size ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + tables++; + } + + /* only check `tables->offset' for last table element ... */ + if ( ( tables->offset > size ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + /* ... and adjust `tables->size' to the real value if necessary */ + if ( tables->size > size - tables->offset ) + tables->size = size - tables->offset; + +#ifdef FT_DEBUG_LEVEL_TRACE + + { + FT_UInt i, j; + const char* name = "?"; + + + FT_TRACE4(( "pcf_read_TOC:\n" )); + + FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); + + tables = face->toc.tables; + for ( i = 0; i < toc->count; i++ ) + { + for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); + j++ ) + if ( tables[i].type == 1UL << j ) + name = tableNames[j]; + + FT_TRACE4(( " %d: type=%s, format=0x%lX," + " size=%ld (0x%lX), offset=%ld (0x%lX)\n", + i, name, + tables[i].format, + tables[i].size, tables[i].size, + tables[i].offset, tables[i].offset )); + } + } + +#endif + + return FT_Err_Ok; + + Exit: + FT_FREE( face->toc.tables ); + return error; + } + + +#define PCF_METRIC_SIZE 12 + + static + const FT_Frame_Field pcf_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT_LE( leftSideBearing ), + FT_FRAME_SHORT_LE( rightSideBearing ), + FT_FRAME_SHORT_LE( characterWidth ), + FT_FRAME_SHORT_LE( ascent ), + FT_FRAME_SHORT_LE( descent ), + FT_FRAME_SHORT_LE( attributes ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_metric_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT( leftSideBearing ), + FT_FRAME_SHORT( rightSideBearing ), + FT_FRAME_SHORT( characterWidth ), + FT_FRAME_SHORT( ascent ), + FT_FRAME_SHORT( descent ), + FT_FRAME_SHORT( attributes ), + FT_FRAME_END + }; + + +#define PCF_COMPRESSED_METRIC_SIZE 5 + + static + const FT_Frame_Field pcf_compressed_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_Compressed_MetricRec + + FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), + FT_FRAME_BYTE( leftSideBearing ), + FT_FRAME_BYTE( rightSideBearing ), + FT_FRAME_BYTE( characterWidth ), + FT_FRAME_BYTE( ascent ), + FT_FRAME_BYTE( descent ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_metric( FT_Stream stream, + FT_ULong format, + PCF_Metric metric ) + { + FT_Error error = FT_Err_Ok; + + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + const FT_Frame_Field* fields; + + + /* parsing normal metrics */ + fields = ( PCF_BYTE_ORDER( format ) == MSBFirst ) + ? pcf_metric_msb_header + : pcf_metric_header; + + /* the following sets `error' but doesn't return in case of failure */ + (void)FT_STREAM_READ_FIELDS( fields, metric ); + } + else + { + PCF_Compressed_MetricRec compr; + + + /* parsing compressed metrics */ + if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) + goto Exit; + + metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); + metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); + metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); + metric->ascent = (FT_Short)( compr.ascent - 0x80 ); + metric->descent = (FT_Short)( compr.descent - 0x80 ); + metric->attributes = 0; + } + + FT_TRACE5(( " width=%d," + " lsb=%d, rsb=%d," + " ascent=%d, descent=%d," + " attributes=%d\n", + metric->characterWidth, + metric->leftSideBearing, + metric->rightSideBearing, + metric->ascent, + metric->descent, + metric->attributes )); + + Exit: + return error; + } + + + static FT_Error + pcf_seek_to_table_type( FT_Stream stream, + PCF_Table tables, + FT_ULong ntables, /* same as PCF_Toc->count */ + FT_ULong type, + FT_ULong *aformat, + FT_ULong *asize ) + { + FT_Error error = FT_ERR( Invalid_File_Format ); + FT_ULong i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + { + if ( stream->pos > tables[i].offset ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Fail; + } + + if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Fail; + } + + *asize = tables[i].size; + *aformat = tables[i].format; + + return FT_Err_Ok; + } + + Fail: + *asize = 0; + return error; + } + + + static FT_Bool + pcf_has_table_type( PCF_Table tables, + FT_ULong ntables, /* same as PCF_Toc->count */ + FT_ULong type ) + { + FT_ULong i; + + + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + return TRUE; + + return FALSE; + } + + +#define PCF_PROPERTY_SIZE 9 + + static + const FT_Frame_Field pcf_property_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG_LE( name ), + FT_FRAME_BYTE ( isString ), + FT_FRAME_LONG_LE( value ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_property_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG( name ), + FT_FRAME_BYTE( isString ), + FT_FRAME_LONG( value ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ) + { + PCF_Property properties = face->properties; + FT_Bool found = 0; + int i; + + + for ( i = 0; i < face->nprops && !found; i++ ) + { + if ( !ft_strcmp( properties[i].name, prop ) ) + found = 1; + } + + if ( found ) + return properties + i - 1; + else + return NULL; + } + + + static FT_Error + pcf_get_properties( FT_Stream stream, + PCF_Face face ) + { + PCF_ParseProperty props = NULL; + PCF_Property properties = NULL; + FT_ULong nprops, orig_nprops, i; + FT_ULong format, size; + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong string_size; + FT_String* strings = NULL; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_PROPERTIES, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_properties:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( orig_nprops ); + else + (void)FT_READ_ULONG_LE( orig_nprops ); + if ( error ) + goto Bail; + + FT_TRACE4(( " number of properties: %ld\n", orig_nprops )); + + /* rough estimate */ + if ( orig_nprops > size / PCF_PROPERTY_SIZE ) + { + error = FT_THROW( Invalid_Table ); + goto Bail; + } + + /* as a heuristic limit to avoid excessive allocation in */ + /* gzip bombs (i.e., very small, invalid input data that */ + /* pretends to expand to an insanely large file) we only */ + /* load the first 256 properties */ + if ( orig_nprops > 256 ) + { + FT_TRACE0(( "pcf_get_properties:" + " only loading first 256 properties\n" )); + nprops = 256; + } + else + nprops = orig_nprops; + + face->nprops = (int)nprops; + + if ( FT_QNEW_ARRAY( props, nprops ) ) + goto Bail; + + for ( i = 0; i < nprops; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) + goto Bail; + } + } + + /* this skip will only work if we really have an extremely large */ + /* number of properties; it will fail for fake data, avoiding an */ + /* unnecessarily large allocation later on */ + if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Bail; + } + + /* pad the property array */ + /* */ + /* clever here - nprops is the same as the number of odd-units read, */ + /* as only isStringProp are odd length (Keith Packard) */ + /* */ + if ( orig_nprops & 3 ) + { + i = 4 - ( orig_nprops & 3 ); + if ( FT_STREAM_SKIP( i ) ) + { + error = FT_THROW( Invalid_Stream_Skip ); + goto Bail; + } + } + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( string_size ); + else + (void)FT_READ_ULONG_LE( string_size ); + if ( error ) + goto Bail; + + FT_TRACE4(( " string size: %ld\n", string_size )); + + /* rough estimate */ + if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE ) + { + error = FT_THROW( Invalid_Table ); + goto Bail; + } + + /* the strings in the `strings' array are PostScript strings, */ + /* which can have a maximum length of 65536 characters each */ + if ( string_size > 16777472 ) /* 256 * (65536 + 1) */ + { + FT_TRACE0(( "pcf_get_properties:" + " loading only 16777472 bytes of strings array\n" )); + string_size = 16777472; + } + + /* allocate one more byte so that we have a final null byte */ + if ( FT_QALLOC( strings, string_size + 1 ) || + FT_STREAM_READ( strings, string_size ) ) + goto Bail; + + strings[string_size] = '\0'; + + /* zero out in case of failure */ + if ( FT_NEW_ARRAY( properties, nprops ) ) + goto Bail; + + face->properties = properties; + + FT_TRACE4(( "\n" )); + for ( i = 0; i < nprops; i++ ) + { + FT_Long name_offset = props[i].name; + + + if ( ( name_offset < 0 ) || + ( (FT_ULong)name_offset > string_size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Bail; + } + + if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) + goto Bail; + + FT_TRACE4(( " %s:", properties[i].name )); + + properties[i].isString = props[i].isString; + + if ( props[i].isString ) + { + FT_Long value_offset = props[i].value; + + + if ( ( value_offset < 0 ) || + ( (FT_ULong)value_offset > string_size ) ) + { + error = FT_THROW( Invalid_Offset ); + goto Bail; + } + + if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) + goto Bail; + + FT_TRACE4(( " `%s'\n", properties[i].value.atom )); + } + else + { + properties[i].value.l = props[i].value; + + FT_TRACE4(( " %ld\n", properties[i].value.l )); + } + } + + error = FT_Err_Ok; + + Bail: + FT_FREE( props ); + FT_FREE( strings ); + + return error; + } + + + static FT_Error + pcf_get_metrics( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong format, size; + PCF_Metric metrics = NULL; + FT_ULong nmetrics, orig_nmetrics, i; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_METRICS, + &format, + &size ); + if ( error ) + return error; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_metrics:\n" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", + PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ? + "compressed" : "uncompressed" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) + return FT_THROW( Invalid_File_Format ); + + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( orig_nmetrics ); + else + (void)FT_READ_ULONG_LE( orig_nmetrics ); + } + else + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_USHORT( orig_nmetrics ); + else + (void)FT_READ_USHORT_LE( orig_nmetrics ); + } + if ( error ) + return FT_THROW( Invalid_File_Format ); + + FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics )); + + /* rough estimate */ + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( orig_nmetrics > size / PCF_METRIC_SIZE ) + return FT_THROW( Invalid_Table ); + } + else + { + if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) + return FT_THROW( Invalid_Table ); + } + + if ( !orig_nmetrics ) + return FT_THROW( Invalid_Table ); + + /* + * PCF is a format from ancient times; Unicode was in its infancy, and + * widely used two-byte character sets for CJK scripts (Big 5, GB 2312, + * JIS X 0208, etc.) did have at most 15000 characters. Even the more + * exotic CNS 11643 and CCCII standards, which were essentially + * three-byte character sets, provided less then 65536 assigned + * characters. + * + * While technically possible to have a larger number of glyphs in PCF + * files, we thus limit the number to 65535, taking into account that we + * synthesize the metrics of glyph 0 to be a copy of the `default + * character', and that 0xFFFF in the encodings array indicates a + * missing glyph. + */ + if ( orig_nmetrics > 65534 ) + { + FT_TRACE0(( "pcf_get_metrics:" + " only loading first 65534 metrics\n" )); + nmetrics = 65534; + } + else + nmetrics = orig_nmetrics; + + face->nmetrics = nmetrics + 1; + + if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) ) + return error; + + /* we handle glyph index 0 later on */ + metrics = face->metrics + 1; + + FT_TRACE4(( "\n" )); + for ( i = 1; i < face->nmetrics; i++, metrics++ ) + { + FT_TRACE5(( " idx %ld:", i )); + error = pcf_get_metric( stream, format, metrics ); + + metrics->bits = 0; + + if ( error ) + break; + + /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ + /* compute a glyph's bitmap dimensions, thus setting them to zero in */ + /* case of an error disables this particular glyph only */ + if ( metrics->rightSideBearing < metrics->leftSideBearing || + metrics->ascent < -metrics->descent ) + { + metrics->characterWidth = 0; + metrics->leftSideBearing = 0; + metrics->rightSideBearing = 0; + metrics->ascent = 0; + metrics->descent = 0; + + FT_TRACE0(( "pcf_get_metrics:" + " invalid metrics for glyph %ld\n", i )); + } + } + + if ( error ) + FT_FREE( face->metrics ); + + Bail: + return error; + } + + + static FT_Error + pcf_get_bitmaps( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_ULong bitmapSizes[GLYPHPADOPTIONS]; + FT_ULong format, size, pos; + FT_ULong nbitmaps, orig_nbitmaps, i, sizebitmaps = 0; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BITMAPS, + &format, + &size ); + if ( error ) + return error; + + error = FT_Stream_EnterFrame( stream, 8 ); + if ( error ) + return error; + + format = FT_GET_ULONG_LE(); + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + orig_nbitmaps = FT_GET_ULONG(); + else + orig_nbitmaps = FT_GET_ULONG_LE(); + + FT_Stream_ExitFrame( stream ); + + FT_TRACE4(( "pcf_get_bitmaps:\n" )); + FT_TRACE4(( " format: 0x%lX\n", format )); + FT_TRACE4(( " (%s, %s,\n", + PCF_BYTE_ORDER( format ) == MSBFirst + ? "most significant byte first" + : "least significant byte first", + PCF_BIT_ORDER( format ) == MSBFirst + ? "most significant bit first" + : "least significant bit first" )); + FT_TRACE4(( " padding=%d bit%s, scanning=%d bit%s)\n", + 8 << PCF_GLYPH_PAD_INDEX( format ), + ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s", + 8 << PCF_SCAN_UNIT_INDEX( format ), + ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return FT_THROW( Invalid_File_Format ); + + FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps )); + + /* see comment in `pcf_get_metrics' */ + if ( orig_nbitmaps > 65534 ) + { + FT_TRACE0(( "pcf_get_bitmaps:" + " only loading first 65534 bitmaps\n" )); + nbitmaps = 65534; + } + else + nbitmaps = orig_nbitmaps; + + /* no extra bitmap for glyph 0 */ + if ( nbitmaps != face->nmetrics - 1 ) + return FT_THROW( Invalid_File_Format ); + + /* start position of bitmap data */ + pos = stream->pos + nbitmaps * 4 + 4 * 4; + + FT_TRACE5(( "\n" )); + for ( i = 1; i <= nbitmaps; i++ ) + { + FT_ULong offset; + + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( offset ); + else + (void)FT_READ_ULONG_LE( offset ); + + FT_TRACE5(( " bitmap %lu: offset %lu (0x%lX)\n", + i, offset, offset )); + + /* right now, we only check the offset with a rough estimate; */ + /* actual bitmaps are only loaded on demand */ + if ( offset > size ) + { + FT_TRACE0(( "pcf_get_bitmaps:" + " invalid offset to bitmap data of glyph %lu\n", i )); + face->metrics[i].bits = pos; + } + else + face->metrics[i].bits = pos + offset; + } + if ( error ) + goto Bail; + + for ( i = 0; i < GLYPHPADOPTIONS; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( bitmapSizes[i] ); + else + (void)FT_READ_ULONG_LE( bitmapSizes[i] ); + if ( error ) + goto Bail; + + sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; + + FT_TRACE4(( " %d-bit padding implies a size of %lu\n", + 8 << i, bitmapSizes[i] )); + } + + FT_TRACE4(( " %lu bitmaps, using %d-bit padding\n", + nbitmaps, + 8 << PCF_GLYPH_PAD_INDEX( format ) )); + FT_TRACE4(( " bitmap size: %lu\n", sizebitmaps )); + + FT_UNUSED( sizebitmaps ); /* only used for debugging */ + + face->bitmapsFormat = format; + + Bail: + return error; + } + + + /* + * This file uses X11 terminology for PCF data; an `encoding' in X11 speak + * is the same as a character code in FreeType speak. + */ +#define PCF_ENC_SIZE 10 + + static + const FT_Frame_Field pcf_enc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_EncRec + + FT_FRAME_START( PCF_ENC_SIZE ), + FT_FRAME_USHORT_LE( firstCol ), + FT_FRAME_USHORT_LE( lastCol ), + FT_FRAME_USHORT_LE( firstRow ), + FT_FRAME_USHORT_LE( lastRow ), + FT_FRAME_USHORT_LE( defaultChar ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_enc_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_EncRec + + FT_FRAME_START( PCF_ENC_SIZE ), + FT_FRAME_USHORT( firstCol ), + FT_FRAME_USHORT( lastCol ), + FT_FRAME_USHORT( firstRow ), + FT_FRAME_USHORT( lastRow ), + FT_FRAME_USHORT( defaultChar ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_encodings( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_ULong format, size; + PCF_Enc enc = &face->enc; + FT_ULong nencoding; + FT_UShort* offset; + FT_UShort defaultCharRow, defaultCharCol; + FT_UShort encodingOffset, defaultCharEncodingOffset; + FT_UShort i, j; + FT_Byte* pos; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BDF_ENCODINGS, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_encodings:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS ) ) + return FT_THROW( Invalid_File_Format ); + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) ) + goto Bail; + } + + FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n", + enc->firstCol, enc->lastCol )); + FT_TRACE4(( " firstRow 0x%X, lastRow 0x%X\n", + enc->firstRow, enc->lastRow )); + FT_TRACE4(( " defaultChar 0x%X\n", + enc->defaultChar )); + + /* sanity checks; we limit numbers of rows and columns to 256 */ + if ( enc->firstCol > enc->lastCol || + enc->lastCol > 0xFF || + enc->firstRow > enc->lastRow || + enc->lastRow > 0xFF ) + return FT_THROW( Invalid_Table ); + + FT_TRACE5(( "\n" )); + + defaultCharRow = enc->defaultChar >> 8; + defaultCharCol = enc->defaultChar & 0xFF; + + /* validate default character */ + if ( defaultCharRow < enc->firstRow || + defaultCharRow > enc->lastRow || + defaultCharCol < enc->firstCol || + defaultCharCol > enc->lastCol ) + { + enc->defaultChar = enc->firstRow * 256U + enc->firstCol; + FT_TRACE0(( "pcf_get_encodings:" + " Invalid default character set to %u\n", + enc->defaultChar )); + + defaultCharRow = enc->firstRow; + defaultCharCol = enc->firstCol; + } + + nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) * + (FT_ULong)( enc->lastRow - enc->firstRow + 1 ); + + error = FT_Stream_EnterFrame( stream, 2 * nencoding ); + if ( error ) + goto Bail; + + /* + * FreeType mandates that glyph index 0 is the `undefined glyph', which + * PCF calls the `default character'. However, FreeType needs glyph + * index 0 to be used for the undefined glyph only, which is is not the + * case for PCF. For this reason, we add one slot for glyph index 0 and + * simply copy the default character to it. + * + * `stream->cursor' still points to the beginning of the frame; we can + * thus easily get the offset to the default character. + */ + pos = stream->cursor + + 2 * ( ( defaultCharRow - enc->firstRow ) * + ( enc->lastCol - enc->firstCol + 1 ) + + defaultCharCol - enc->firstCol ); + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + defaultCharEncodingOffset = FT_PEEK_USHORT( pos ); + else + defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos ); + + if ( defaultCharEncodingOffset == 0xFFFF ) + { + FT_TRACE0(( "pcf_get_encodings:" + " No glyph for default character,\n" )); + FT_TRACE0(( " " + " setting it to the first glyph of the font\n" )); + defaultCharEncodingOffset = 1; + } + else + { + defaultCharEncodingOffset++; + + if ( defaultCharEncodingOffset >= face->nmetrics ) + { + FT_TRACE0(( "pcf_get_encodings:" + " Invalid glyph index for default character,\n" )); + FT_TRACE0(( " " + " setting it to the first glyph of the font\n" )); + defaultCharEncodingOffset = 1; + } + } + + /* copy metrics of default character to index 0 */ + face->metrics[0] = face->metrics[defaultCharEncodingOffset]; + + if ( FT_QNEW_ARRAY( enc->offset, nencoding ) ) + goto Bail; + + /* now loop over all values */ + offset = enc->offset; + for ( i = enc->firstRow; i <= enc->lastRow; i++ ) + { + for ( j = enc->firstCol; j <= enc->lastCol; j++ ) + { + /* X11's reference implementation uses the equivalent to */ + /* `FT_GET_SHORT', however PCF fonts with more than 32768 */ + /* characters (e.g., `unifont.pcf') clearly show that an */ + /* unsigned value is needed. */ + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + encodingOffset = FT_GET_USHORT(); + else + encodingOffset = FT_GET_USHORT_LE(); + + /* everything is off by 1 due to the artificial glyph 0 */ + *offset++ = encodingOffset == 0xFFFF ? 0xFFFF + : encodingOffset + 1; + } + } + FT_Stream_ExitFrame( stream ); + + Bail: + return error; + } + + + static + const FT_Frame_Field pcf_accel_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG_LE ( fontAscent ), + FT_FRAME_LONG_LE ( fontDescent ), + FT_FRAME_LONG_LE ( maxOverlap ), + FT_FRAME_END + }; + + + static + const FT_Frame_Field pcf_accel_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG ( fontAscent ), + FT_FRAME_LONG ( fontDescent ), + FT_FRAME_LONG ( maxOverlap ), + FT_FRAME_END + }; + + + static FT_Error + pcf_get_accel( FT_Stream stream, + PCF_Face face, + FT_ULong type ) + { + FT_ULong format, size; + FT_Error error; + PCF_Accel accel = &face->accel; + + + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + type, + &format, + &size ); + if ( error ) + goto Bail; + + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + + FT_TRACE4(( "pcf_get_accel%s:\n", + type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)" + : "" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", + format, + PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", + PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ? + "accelerated" : "not accelerated" )); + + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + goto Bail; + + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) + goto Bail; + } + + FT_TRACE5(( " noOverlap=%s, constantMetrics=%s," + " terminalFont=%s, constantWidth=%s\n", + accel->noOverlap ? "yes" : "no", + accel->constantMetrics ? "yes" : "no", + accel->terminalFont ? "yes" : "no", + accel->constantWidth ? "yes" : "no" )); + FT_TRACE5(( " inkInside=%s, inkMetrics=%s, drawDirection=%s\n", + accel->inkInside ? "yes" : "no", + accel->inkMetrics ? "yes" : "no", + accel->drawDirection ? "RTL" : "LTR" )); + FT_TRACE5(( " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", + accel->fontAscent, + accel->fontDescent, + accel->maxOverlap )); + + /* sanity checks */ + if ( FT_ABS( accel->fontAscent ) > 0x7FFF ) + { + accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n", + accel->fontAscent )); + } + if ( FT_ABS( accel->fontDescent ) > 0x7FFF ) + { + accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF; + FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n", + accel->fontDescent )); + } + + FT_TRACE5(( " minbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->minbounds) ); + if ( error ) + goto Bail; + + FT_TRACE5(( " maxbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->maxbounds) ); + if ( error ) + goto Bail; + + if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + { + FT_TRACE5(( " ink minbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_minbounds) ); + if ( error ) + goto Bail; + + FT_TRACE5(( " ink maxbounds:" )); + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_maxbounds) ); + if ( error ) + goto Bail; + } + else + { + accel->ink_minbounds = accel->minbounds; + accel->ink_maxbounds = accel->maxbounds; + } + + Bail: + return error; + } + + + static FT_Error + pcf_interpret_style( PCF_Face pcf ) + { + FT_Error error = FT_Err_Ok; + FT_Face face = FT_FACE( pcf ); + FT_Memory memory = face->memory; + + PCF_Property prop; + + const char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t lengths[4], nn, len; + + + face->style_flags = 0; + + prop = pcf_find_property( pcf, "SLANT" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || + *(prop->value.atom) == 'o' ) ? "Oblique" + : "Italic"; + } + + prop = pcf_find_property( pcf, "WEIGHT_NAME" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = "Bold"; + } + + prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (const char*)( prop->value.atom ); + + prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (const char*)( prop->value.atom ); + + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + + if ( len == 0 ) + { + strings[0] = "Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + + { + char* s; + + + if ( FT_QALLOC( face->style_name, len ) ) + return error; + + s = face->style_name; + + for ( nn = 0; nn < 4; nn++ ) + { + const char* src = strings[nn]; + + + len = lengths[nn]; + + if ( !src ) + continue; + + /* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + + ft_memcpy( s, src, len ); + + /* need to convert spaces to dashes for */ + /* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + + + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + + s += len; + } + *s = 0; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face, + FT_Long face_index ) + { + FT_Face root = FT_FACE( face ); + FT_Error error; + FT_Memory memory = FT_FACE( face )->memory; + FT_Bool hasBDFAccelerators; + + + error = pcf_read_TOC( stream, face ); + if ( error ) + goto Exit; + + root->num_faces = 1; + root->face_index = 0; + + /* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return FT_Err_Ok; + + error = pcf_get_properties( stream, face ); + if ( error ) + goto Exit; + + /* Use the old accelerators if no BDF accelerators are in the file. */ + hasBDFAccelerators = pcf_has_table_type( face->toc.tables, + face->toc.count, + PCF_BDF_ACCELERATORS ); + if ( !hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* metrics */ + error = pcf_get_metrics( stream, face ); + if ( error ) + goto Exit; + + /* bitmaps */ + error = pcf_get_bitmaps( stream, face ); + if ( error ) + goto Exit; + + /* encodings */ + error = pcf_get_encodings( stream, face ); + if ( error ) + goto Exit; + + /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ + if ( hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); + if ( error ) + goto Exit; + } + + /* XXX: TO DO: inkmetrics and glyph_names are missing */ + + /* now construct the face object */ + { + PCF_Property prop; + + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( face->accel.constantWidth ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( FT_SET_ERROR( pcf_interpret_style( face ) ) ) + goto Exit; + + prop = pcf_find_property( face, "FAMILY_NAME" ); + if ( prop && prop->isString ) + { + +#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES + + PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face ); + + + if ( !driver->no_long_family_names ) + { + /* Prepend the foundry name plus a space to the family name. */ + /* There are many fonts just called `Fixed' which look */ + /* completely different, and which have nothing to do with each */ + /* other. When selecting `Fixed' in KDE or Gnome one gets */ + /* results that appear rather random, the style changes often if */ + /* one changes the size and one cannot select some fonts at all. */ + /* */ + /* We also check whether we have `wide' characters; all put */ + /* together, we get family names like `Sony Fixed' or `Misc */ + /* Fixed Wide'. */ + + PCF_Property foundry_prop, point_size_prop, average_width_prop; + + int l = ft_strlen( prop->value.atom ) + 1; + int wide = 0; + + + foundry_prop = pcf_find_property( face, "FOUNDRY" ); + point_size_prop = pcf_find_property( face, "POINT_SIZE" ); + average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + + if ( point_size_prop && average_width_prop ) + { + if ( average_width_prop->value.l >= point_size_prop->value.l ) + { + /* This font is at least square shaped or even wider */ + wide = 1; + l += ft_strlen( " Wide" ); + } + } + + if ( foundry_prop && foundry_prop->isString ) + { + l += ft_strlen( foundry_prop->value.atom ) + 1; + + if ( FT_QALLOC( root->family_name, l ) ) + goto Exit; + + ft_strcpy( root->family_name, foundry_prop->value.atom ); + ft_strcat( root->family_name, " " ); + ft_strcat( root->family_name, prop->value.atom ); + } + else + { + if ( FT_QALLOC( root->family_name, l ) ) + goto Exit; + + ft_strcpy( root->family_name, prop->value.atom ); + } + + if ( wide ) + ft_strcat( root->family_name, " Wide" ); + } + else + +#endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + + { + if ( FT_STRDUP( root->family_name, prop->value.atom ) ) + goto Exit; + } + } + else + root->family_name = NULL; + + root->num_glyphs = (FT_Long)face->nmetrics; + + root->num_fixed_sizes = 1; + if ( FT_NEW( root->available_sizes ) ) + goto Exit; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + + + /* for simplicity, we take absolute values of integer properties */ + +#if 0 + bsize->height = face->accel.maxbounds.ascent << 6; +#endif + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( face->accel.fontAscent + face->accel.fontDescent < 0 ) + FT_TRACE0(( "pcf_load_font: negative height\n" )); +#endif + if ( FT_ABS( face->accel.fontAscent + + face->accel.fontDescent ) > 0x7FFF ) + { + bsize->height = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping height to value %d\n", + bsize->height )); + } + else + bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent + + face->accel.fontDescent ) ); + + prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative average width\n" )); +#endif + if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) ) + { + bsize->width = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n", + bsize->width )); + } + else + bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); + } + else + { + /* this is a heuristical value */ + bsize->width = ( bsize->height * 2 + 1 ) / 3; + } + + prop = pcf_find_property( face, "POINT_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative point size\n" )); +#endif + /* convert from 722.7 decipoints to 72 points per inch */ + if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */ + { + bsize->size = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n", + bsize->size )); + } + else + bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), + 64 * 7200, + 72270L ); + } + + prop = pcf_find_property( face, "PIXEL_SIZE" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative pixel size\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + bsize->y_ppem = 0x7FFF << 6; + FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n", + bsize->y_ppem )); + } + else + bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; + } + + prop = pcf_find_property( face, "RESOLUTION_X" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative X resolution\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + resolution_x = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n", + resolution_x )); + } + else + resolution_x = FT_ABS( (FT_Short)prop->value.l ); + } + + prop = pcf_find_property( face, "RESOLUTION_Y" ); + if ( prop ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + if ( prop->value.l < 0 ) + FT_TRACE0(( "pcf_load_font: negative Y resolution\n" )); +#endif + if ( FT_ABS( prop->value.l ) > 0x7FFF ) + { + resolution_y = 0x7FFF; + FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n", + resolution_y )); + } + else + resolution_y = FT_ABS( (FT_Short)prop->value.l ); + } + + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = FT_MulDiv( bsize->y_ppem, + resolution_x, + resolution_y ); + else + bsize->x_ppem = bsize->y_ppem; + } + + /* set up charset */ + { + PCF_Property charset_registry, charset_encoding; + + + charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); + charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); + + if ( charset_registry && charset_registry->isString && + charset_encoding && charset_encoding->isString ) + { + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + } + } + } + + Exit: + if ( error ) + { + /* This is done to respect the behaviour of the original */ + /* PCF font driver. */ + error = FT_THROW( Invalid_File_Format ); + } + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfread.h b/Dependencies/freetype/freetype/src/pcf/pcfread.h new file mode 100644 index 00000000..a54648fb --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfread.h @@ -0,0 +1,44 @@ +/* pcfread.h + + FreeType font driver for pcf fonts + + Copyright 2003 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef PCFREAD_H_ +#define PCFREAD_H_ + + + +FT_BEGIN_HEADER + + FT_LOCAL( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ); + +FT_END_HEADER + +#endif /* PCFREAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfutil.c b/Dependencies/freetype/freetype/src/pcf/pcfutil.c new file mode 100644 index 00000000..cd26c77c --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfutil.c @@ -0,0 +1,119 @@ +/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */ + +/* + * Author: Keith Packard, MIT X Consortium + */ + +/* Modified for use with FreeType */ + + +#include "pcfutil.h" + + + /* + * Invert bit order within each BYTE of an array. + */ + + FT_LOCAL_DEF( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ) + { + for ( ; nbytes > 0; nbytes--, buf++ ) + { + unsigned int val = *buf; + + + val = ( ( val >> 1 ) & 0x55 ) | ( ( val << 1 ) & 0xAA ); + val = ( ( val >> 2 ) & 0x33 ) | ( ( val << 2 ) & 0xCC ); + val = ( ( val >> 4 ) & 0x0F ) | ( ( val << 4 ) & 0xF0 ); + + *buf = (unsigned char)val; + } + } + + +#if ( defined( __clang_major__ ) && __clang_major__ >= 5 ) || \ + ( defined( __GNUC__ ) && \ + ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 ) ) ) + +#define BSWAP16( x ) __builtin_bswap16( x ) +#define BSWAP32( x ) __builtin_bswap32( x ) + +#elif defined( _MSC_VER ) && _MSC_VER >= 1300 + +#pragma intrinsic( _byteswap_ushort ) +#pragma intrinsic( _byteswap_ulong ) + +#define BSWAP16( x ) _byteswap_ushort( x ) +#define BSWAP32( x ) _byteswap_ulong( x ) + +#else + +#define BSWAP16( x ) \ + (FT_UInt16)( ( ( ( x ) >> 8 ) & 0xff ) | \ + ( ( ( x ) & 0xff ) << 8 ) ) +#define BSWAP32( x ) \ + (FT_UInt32)( ( ( ( x ) & 0xff000000u ) >> 24 ) | \ + ( ( ( x ) & 0x00ff0000u ) >> 8 ) | \ + ( ( ( x ) & 0x0000ff00u ) << 8 ) | \ + ( ( ( x ) & 0x000000ffu ) << 24 ) ) + +#endif + + /* + * Invert byte order within each 16-bits of an array. + */ + + FT_LOCAL_DEF( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ) + { + FT_UInt16* b = (FT_UInt16*)buf; + + + for ( ; nbytes >= 2; nbytes -= 2, b++ ) + *b = BSWAP16( *b ); + } + + /* + * Invert byte order within each 32-bits of an array. + */ + + FT_LOCAL_DEF( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ) + { + FT_UInt32* b = (FT_UInt32*)buf; + + + for ( ; nbytes >= 4; nbytes -= 4, b++ ) + *b = BSWAP32( *b ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pcf/pcfutil.h b/Dependencies/freetype/freetype/src/pcf/pcfutil.h new file mode 100644 index 00000000..a197c155 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pcf/pcfutil.h @@ -0,0 +1,55 @@ +/* pcfutil.h + + FreeType font driver for pcf fonts + + Copyright 2000, 2001, 2004 by + Francesco Zappa Nardelli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#ifndef PCFUTIL_H_ +#define PCFUTIL_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ); + + FT_LOCAL( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ); + + FT_LOCAL( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ); + +FT_END_HEADER + +#endif /* PCFUTIL_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfr.c b/Dependencies/freetype/freetype/src/pfr/pfr.c new file mode 100644 index 00000000..71b57930 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfr.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * pfr.c + * + * FreeType PFR driver component. + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pfrcmap.c" +#include "pfrdrivr.c" +#include "pfrgload.c" +#include "pfrload.c" +#include "pfrobjs.c" +#include "pfrsbit.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrcmap.c b/Dependencies/freetype/freetype/src/pfr/pfrcmap.c new file mode 100644 index 00000000..cd701661 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrcmap.c @@ -0,0 +1,188 @@ +/**************************************************************************** + * + * pfrcmap.c + * + * FreeType PFR cmap handling (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "pfrcmap.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */ + FT_Pointer pointer ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_Error error = FT_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + + FT_UNUSED( pointer ); + + + pfrcmap->num_chars = face->phy_font.num_chars; + pfrcmap->chars = face->phy_font.chars; + + /* just for safety, check that the character entries are correctly */ + /* sorted in increasing character code order */ + { + FT_UInt n; + + + for ( n = 1; n < pfrcmap->num_chars; n++ ) + { + if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */ + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + + + pfrcmap->chars = NULL; + pfrcmap->num_chars = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 char_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + return mid + 1; + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */ + FT_UInt32 *pchar_code ) + { + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + Restart: + { + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; + + + while ( min < max ) + { + gchar = pfrcmap->chars + mid; + + if ( gchar->char_code == char_code ) + { + result = mid; + if ( result != 0 ) + { + result++; + goto Exit; + } + + char_code++; + goto Restart; + } + + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + /* we didn't find it, but we have a pair just above it */ + char_code = 0; + + if ( min < pfrcmap->num_chars ) + { + gchar = pfrcmap->chars + min; + result = min; + if ( result != 0 ) + { + result++; + char_code = gchar->char_code; + } + } + } + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + pfr_cmap_class_rec = + { + sizeof ( PFR_CMapRec ), + + (FT_CMap_InitFunc) pfr_cmap_init, /* init */ + (FT_CMap_DoneFunc) pfr_cmap_done, /* done */ + (FT_CMap_CharIndexFunc)pfr_cmap_char_index, /* char_index */ + (FT_CMap_CharNextFunc) pfr_cmap_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrcmap.h b/Dependencies/freetype/freetype/src/pfr/pfrcmap.h new file mode 100644 index 00000000..ab791357 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrcmap.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * pfrcmap.h + * + * FreeType PFR cmap handling (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRCMAP_H_ +#define PFRCMAP_H_ + +#include +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_chars; + PFR_Char chars; + + } PFR_CMapRec, *PFR_CMap; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec; + +FT_END_HEADER + + +#endif /* PFRCMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrdrivr.c b/Dependencies/freetype/freetype/src/pfr/pfrdrivr.c new file mode 100644 index 00000000..ffd82227 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrdrivr.c @@ -0,0 +1,212 @@ +/**************************************************************************** + * + * pfrdrivr.c + * + * FreeType PFR driver interface (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include "pfrdrivr.h" +#include "pfrobjs.h" + +#include "pfrerror.h" + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + + + (void)pfr_face_get_kerning( face, left, right, avector ); + + /* convert from metrics to outline units when necessary */ + if ( phys->outline_resolution != phys->metrics_resolution ) + { + if ( avector->x != 0 ) + avector->x = FT_MulDiv( avector->x, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + if ( avector->y != 0 ) + avector->y = FT_MulDiv( avector->y, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + } + + return FT_Err_Ok; + } + + + /* + * PFR METRICS SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_advance( FT_Face face, /* PFR_Face */ + FT_UInt gindex, + FT_Pos *anadvance ) + { + PFR_Face pfrface = (PFR_Face)face; + FT_Error error = FT_ERR( Invalid_Argument ); + + + *anadvance = 0; + + if ( !gindex ) + goto Exit; + + gindex--; + + if ( pfrface ) + { + PFR_PhyFont phys = &pfrface->phy_font; + + + if ( gindex < phys->num_chars ) + { + *anadvance = phys->chars[gindex].advance; + error = FT_Err_Ok; + } + } + + Exit: + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + pfr_get_metrics( FT_Face face, /* PFR_Face */ + FT_UInt *anoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; + FT_Fixed x_scale, y_scale; + FT_Size size = pfrface->root.size; + + + if ( anoutline_resolution ) + *anoutline_resolution = phys->outline_resolution; + + if ( ametrics_resolution ) + *ametrics_resolution = phys->metrics_resolution; + + x_scale = 0x10000L; + y_scale = 0x10000L; + + if ( size ) + { + x_scale = FT_DivFix( size->metrics.x_ppem << 6, + (FT_Long)phys->metrics_resolution ); + + y_scale = FT_DivFix( size->metrics.y_ppem << 6, + (FT_Long)phys->metrics_resolution ); + } + + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + + return FT_Err_Ok; + } + + + static + const FT_Service_PfrMetricsRec pfr_metrics_service_rec = + { + pfr_get_metrics, /* get_metrics */ + pfr_face_get_kerning, /* get_kerning */ + pfr_get_advance /* get_advance */ + }; + + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec pfr_services[] = + { + { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PFR }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + pfr_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pfr_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pfr_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE, + + sizeof ( FT_DriverRec ), + + "pfr", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + pfr_get_service /* FT_Module_Requester get_interface */ + }, + + sizeof ( PFR_FaceRec ), + sizeof ( PFR_SizeRec ), + sizeof ( PFR_SlotRec ), + + pfr_face_init, /* FT_Face_InitFunc init_face */ + pfr_face_done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + pfr_slot_init, /* FT_Slot_InitFunc init_slot */ + pfr_slot_done, /* FT_Slot_DoneFunc done_slot */ + + pfr_slot_load, /* FT_Slot_LoadFunc load_glyph */ + + pfr_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + NULL, /* FT_Size_RequestFunc request_size */ + NULL, /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrdrivr.h b/Dependencies/freetype/freetype/src/pfr/pfrdrivr.h new file mode 100644 index 00000000..58954a9a --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrdrivr.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * pfrdrivr.h + * + * High-level Type PFR driver interface (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRDRIVR_H_ +#define PFRDRIVR_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class; + +FT_END_HEADER + + +#endif /* PFRDRIVR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrerror.h b/Dependencies/freetype/freetype/src/pfr/pfrerror.h new file mode 100644 index 00000000..af0ddaf1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrerror.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pfrerror.h + * + * PFR error codes (specification only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PFR error enumeration constants. + * + */ + +#ifndef PFRERROR_H_ +#define PFRERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PFR_Err_ +#define FT_ERR_BASE FT_Mod_Err_PFR + +#include + +#endif /* PFRERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrgload.c b/Dependencies/freetype/freetype/src/pfr/pfrgload.c new file mode 100644 index 00000000..e8500755 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrgload.c @@ -0,0 +1,849 @@ +/**************************************************************************** + * + * pfrgload.c + * + * FreeType PFR glyph loader (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrgload.h" +#include "pfrsbit.h" +#include "pfrload.h" /* for macro definitions */ +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ) + { + FT_ZERO( glyph ); + + glyph->loader = loader; + + FT_GlyphLoader_Rewind( loader ); + } + + + FT_LOCAL_DEF( void ) + pfr_glyph_done( PFR_Glyph glyph ) + { + FT_Memory memory = glyph->loader->memory; + + + FT_FREE( glyph->x_control ); + glyph->y_control = NULL; + + glyph->max_xy_control = 0; +#if 0 + glyph->num_x_control = 0; + glyph->num_y_control = 0; +#endif + + FT_FREE( glyph->subs ); + + glyph->max_subs = 0; + glyph->num_subs = 0; + + glyph->loader = NULL; + glyph->path_begun = 0; + } + + + /* close current contour, if any */ + static void + pfr_glyph_close_contour( PFR_Glyph glyph ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Int last, first; + + + if ( !glyph->path_begun ) + return; + + /* compute first and last point indices in current glyph outline */ + last = outline->n_points - 1; + first = 0; + if ( outline->n_contours > 0 ) + first = outline->contours[outline->n_contours - 1]; + + /* if the last point falls on the same location as the first one */ + /* we need to delete it */ + if ( last > first ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + last; + + + if ( p1->x == p2->x && p1->y == p2->y ) + { + outline->n_points--; + last--; + } + } + + /* don't add empty contours */ + if ( last >= first ) + outline->contours[outline->n_contours++] = (FT_UShort)last; + + glyph->path_begun = 0; + } + + + /* reset glyph to start the loading of a new glyph */ + static void + pfr_glyph_start( PFR_Glyph glyph ) + { + glyph->path_begun = 0; + } + + + static FT_Error + pfr_glyph_line_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); + if ( !error ) + { + FT_Int n = outline->n_points; + + + outline->points[n] = *to; + outline->tags [n] = FT_CURVE_TAG_ON; + + outline->n_points++; + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_curve_to( PFR_Glyph glyph, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; + + + /* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); + if ( !error ) + { + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = outline->tags + outline->n_points; + + + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_CURVE_TAG_CUBIC; + tag[1] = FT_CURVE_TAG_CUBIC; + tag[2] = FT_CURVE_TAG_ON; + + outline->n_points += 3; + } + + Exit: + return error; + } + + + static FT_Error + pfr_glyph_move_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Error error; + + + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* indicate that a new contour has started */ + glyph->path_begun = 1; + + /* check that there is space for a new contour and a new point */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); + if ( !error ) + { + /* add new start point */ + error = pfr_glyph_line_to( glyph, to ); + } + + return error; + } + + + static void + pfr_glyph_end( PFR_Glyph glyph ) + { + /* close current contour if any */ + pfr_glyph_close_contour( glyph ); + + /* merge the current glyph into the stack */ + FT_GlyphLoader_Add( glyph->loader ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR GLYPH LOADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* load a simple glyph */ + static FT_Error + pfr_glyph_load_simple( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + FT_UInt flags, x_count, y_count, i, count, mask; + FT_Int x; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( flags & PFR_GLYPH_IS_COMPOUND ) + goto Failure; + + x_count = 0; + y_count = 0; + + if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) + { + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + x_count = count & 15; + y_count = count >> 4; + } + else + { + if ( flags & PFR_GLYPH_XCOUNT ) + { + PFR_CHECK( 1 ); + x_count = PFR_NEXT_BYTE( p ); + } + + if ( flags & PFR_GLYPH_YCOUNT ) + { + PFR_CHECK( 1 ); + y_count = PFR_NEXT_BYTE( p ); + } + } + + count = x_count + y_count; + + /* re-allocate array when necessary */ + if ( count > glyph->max_xy_control ) + { + FT_UInt new_max = FT_PAD_CEIL( count, 8 ); + + + if ( FT_RENEW_ARRAY( glyph->x_control, + glyph->max_xy_control, + new_max ) ) + goto Exit; + + glyph->max_xy_control = new_max; + } + + glyph->y_control = glyph->x_control + x_count; + + mask = 0; + x = 0; + + for ( i = 0; i < count; i++ ) + { + if ( ( i & 7 ) == 0 ) + { + PFR_CHECK( 1 ); + mask = PFR_NEXT_BYTE( p ); + } + + if ( mask & 1 ) + { + PFR_CHECK( 2 ); + x = PFR_NEXT_SHORT( p ); + } + else + { + PFR_CHECK( 1 ); + x += PFR_NEXT_BYTE( p ); + } + + glyph->x_control[i] = x; + + mask >>= 1; + } + + /* XXX: we ignore the secondary stroke and edge definitions */ + /* since we don't support native PFR hinting */ + /* */ + if ( flags & PFR_GLYPH_SINGLE_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + pfr_glyph_start( glyph ); + + /* now load a simple glyph */ + { + FT_Vector pos[4]; + FT_Vector* cur; + + + pos[0].x = pos[0].y = 0; + pos[3] = pos[0]; + + for (;;) + { + FT_UInt format, format_low, args_format = 0, args_count, n; + + + /**************************************************************** + * read instruction + */ + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + format_low = format & 15; + + switch ( format >> 4 ) + { + case 0: /* end glyph */ + FT_TRACE6(( "- end glyph" )); + args_count = 0; + break; + + case 1: /* general line operation */ + FT_TRACE6(( "- general line" )); + goto Line1; + + case 4: /* move to inside contour */ + FT_TRACE6(( "- move to inside" )); + goto Line1; + + case 5: /* move to outside contour */ + FT_TRACE6(( "- move to outside" )); + Line1: + args_format = format_low; + args_count = 1; + break; + + case 2: /* horizontal line to */ + FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + if ( format_low >= x_count ) + goto Failure; + pos[0].x = glyph->x_control[format_low]; + pos[0].y = pos[3].y; + pos[3] = pos[0]; + args_count = 0; + break; + + case 3: /* vertical line to */ + FT_TRACE6(( "- vertical line to cy.%d", format_low )); + if ( format_low >= y_count ) + goto Failure; + pos[0].x = pos[3].x; + pos[0].y = glyph->y_control[format_low]; + pos[3] = pos[0]; + args_count = 0; + break; + + case 6: /* horizontal to vertical curve */ + FT_TRACE6(( "- hv curve" )); + args_format = 0xB8E; + args_count = 3; + break; + + case 7: /* vertical to horizontal curve */ + FT_TRACE6(( "- vh curve" )); + args_format = 0xE2B; + args_count = 3; + break; + + default: /* general curve to */ + FT_TRACE6(( "- general curve" )); + args_count = 4; + args_format = format_low; + } + + /************************************************************ + * now read arguments + */ + cur = pos; + for ( n = 0; n < args_count; n++ ) + { + FT_UInt idx; + FT_Int delta; + + + /* read the X argument */ + switch ( args_format & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= x_count ) + goto Failure; + cur->x = glyph->x_control[idx]; + FT_TRACE7(( " cx#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->x = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " x.%ld", cur->x )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->x = pos[3].x + delta; + FT_TRACE7(( " dx.%d", delta )); + break; + + default: + FT_TRACE7(( " |" )); + cur->x = pos[3].x; + } + + /* read the Y argument */ + switch ( ( args_format >> 2 ) & 3 ) + { + case 0: /* 8-bit index */ + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= y_count ) + goto Failure; + cur->y = glyph->y_control[idx]; + FT_TRACE7(( " cy#%d", idx )); + break; + + case 1: /* 16-bit absolute value */ + PFR_CHECK( 2 ); + cur->y = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " y.%ld", cur->y )); + break; + + case 2: /* 8-bit delta */ + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->y = pos[3].y + delta; + FT_TRACE7(( " dy.%d", delta )); + break; + + default: + FT_TRACE7(( " -" )); + cur->y = pos[3].y; + } + + /* read the additional format flag for the general curve */ + if ( n == 0 && args_count == 4 ) + { + PFR_CHECK( 1 ); + args_format = PFR_NEXT_BYTE( p ); + args_count--; + } + else + args_format >>= 4; + + /* save the previous point */ + pos[3] = cur[0]; + cur++; + } + + FT_TRACE7(( "\n" )); + + /************************************************************ + * finally, execute instruction + */ + switch ( format >> 4 ) + { + case 0: /* end glyph => EXIT */ + pfr_glyph_end( glyph ); + goto Exit; + + case 1: /* line operations */ + case 2: + case 3: + error = pfr_glyph_line_to( glyph, pos ); + goto Test_Error; + + case 4: /* move to inside contour */ + case 5: /* move to outside contour */ + error = pfr_glyph_move_to( glyph, pos ); + goto Test_Error; + + default: /* curve operations */ + error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); + + Test_Error: /* test error condition */ + if ( error ) + goto Exit; + } + } /* for (;;) */ + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); + goto Exit; + } + + + /* load a composite/compound glyph */ + static FT_Error + pfr_glyph_load_compound( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = glyph->loader->memory; + PFR_SubGlyph subglyph; + FT_UInt flags, i, count, org_count; + FT_Int x_pos, y_pos; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + /* test for composite glyphs */ + if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) + goto Failure; + + count = flags & 0x3F; + + /* ignore extra items when present */ + /* */ + if ( flags & PFR_GLYPH_COMPOUND_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + + /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ + /* the PFR format is dumb, using direct file offsets to point to the */ + /* sub-glyphs (instead of glyph indices). Sigh. */ + /* */ + /* For now, we load the list of sub-glyphs into a different array */ + /* but this will prevent us from using the auto-hinter at its best */ + /* quality. */ + /* */ + org_count = glyph->num_subs; + + if ( org_count + count > glyph->max_subs ) + { + FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; + + + /* we arbitrarily limit the number of subglyphs */ + /* to avoid endless recursion */ + if ( new_max > 64 ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound:" + " too many compound glyphs components\n" )); + goto Exit; + } + + if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) + goto Exit; + + glyph->max_subs = new_max; + } + + subglyph = glyph->subs + org_count; + + for ( i = 0; i < count; i++, subglyph++ ) + { + FT_UInt format; + + + x_pos = 0; + y_pos = 0; + + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + + /* read scale when available */ + subglyph->x_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_XSCALE ) + { + PFR_CHECK( 2 ); + subglyph->x_scale = PFR_NEXT_SHORT( p ) * 16; + } + + subglyph->y_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_YSCALE ) + { + PFR_CHECK( 2 ); + subglyph->y_scale = PFR_NEXT_SHORT( p ) * 16; + } + + /* read offset */ + switch ( format & 3 ) + { + case 1: + PFR_CHECK( 2 ); + x_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + x_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + switch ( ( format >> 2 ) & 3 ) + { + case 1: + PFR_CHECK( 2 ); + y_pos = PFR_NEXT_SHORT( p ); + break; + + case 2: + PFR_CHECK( 1 ); + y_pos += PFR_NEXT_INT8( p ); + break; + + default: + ; + } + + subglyph->x_delta = x_pos; + subglyph->y_delta = y_pos; + + /* read glyph position and size now */ + if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) + { + PFR_CHECK( 2 ); + subglyph->gps_size = PFR_NEXT_USHORT( p ); + } + else + { + PFR_CHECK( 1 ); + subglyph->gps_size = PFR_NEXT_BYTE( p ); + } + + if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) + { + PFR_CHECK( 3 ); + subglyph->gps_offset = PFR_NEXT_ULONG( p ); + } + else + { + PFR_CHECK( 2 ); + subglyph->gps_offset = PFR_NEXT_USHORT( p ); + } + + glyph->num_subs++; + } + + Exit: + return error; + + Failure: + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_glyph_load_rec( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + FT_Error error; + FT_Byte* p; + FT_Byte* limit; + + + if ( FT_STREAM_SEEK( gps_offset + offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + limit = p + size; + + if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) + { + FT_UInt n, old_count, count; + FT_GlyphLoader loader = glyph->loader; + FT_Outline* base = &loader->base.outline; + + + old_count = glyph->num_subs; + + /* this is a compound glyph - load it */ + error = pfr_glyph_load_compound( glyph, p, limit ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + count = glyph->num_subs - old_count; + + FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n", + count, + count == 1 ? "" : "s", + offset )); + + /* now, load each individual glyph */ + for ( n = 0; n < count; n++ ) + { + FT_Int i, old_points, num_points; + PFR_SubGlyph subglyph; + + + FT_TRACE4(( " subglyph %d:\n", n )); + + subglyph = glyph->subs + old_count + n; + old_points = base->n_points; + + error = pfr_glyph_load_rec( glyph, stream, gps_offset, + subglyph->gps_offset, + subglyph->gps_size ); + if ( error ) + break; + + /* note that `glyph->subs' might have been re-allocated */ + subglyph = glyph->subs + old_count + n; + num_points = base->n_points - old_points; + + /* translate and eventually scale the new glyph points */ + if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) + { + FT_Vector* vec = base->points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + + subglyph->x_delta; + vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + + subglyph->y_delta; + } + } + else + { + FT_Vector* vec = loader->base.outline.points + old_points; + + + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x += subglyph->x_delta; + vec->y += subglyph->y_delta; + } + } + + /* proceed to next sub-glyph */ + } + + FT_TRACE4(( "end compound glyph with %d element%s\n", + count, + count == 1 ? "" : "s" )); + } + else + { + FT_TRACE4(( "simple glyph (offset %lu)\n", offset )); + + /* load a simple glyph */ + error = pfr_glyph_load_simple( glyph, p, limit ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + /* initialize glyph loader */ + FT_GlyphLoader_Rewind( glyph->loader ); + + glyph->num_subs = 0; + + /* load the glyph, recursively when needed */ + return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrgload.h b/Dependencies/freetype/freetype/src/pfr/pfrgload.h new file mode 100644 index 00000000..d86549fb --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrgload.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * pfrgload.h + * + * FreeType PFR glyph loader (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRGLOAD_H_ +#define PFRGLOAD_H_ + +#include "pfrtypes.h" + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ); + + FT_LOCAL( void ) + pfr_glyph_done( PFR_Glyph glyph ); + + + FT_LOCAL( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ); + + +FT_END_HEADER + + +#endif /* PFRGLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrload.c b/Dependencies/freetype/freetype/src/pfr/pfrload.c new file mode 100644 index 00000000..358af5c7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrload.c @@ -0,0 +1,1062 @@ +/**************************************************************************** + * + * pfrload.c + * + * FreeType PFR loader (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrload.h" +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /* + * The overall structure of a PFR file is as follows. + * + * PFR header + * 58 bytes (contains nPhysFonts) + * + * Logical font directory (size at most 2^16 bytes) + * 2 bytes (nLogFonts) + * + nLogFonts * 5 bytes + * + * ==> nLogFonts <= 13106 + * + * Logical font section (size at most 2^24 bytes) + * nLogFonts * logFontRecord + * + * logFontRecord (size at most 2^16 bytes) + * 12 bytes (fontMatrix) + * + 1 byte (flags) + * + 0-5 bytes (depending on `flags') + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + 5 bytes (physical font info) + * + 0-1 bytes (depending on PFR header) + * + * ==> minimum size 18 bytes + * + * Physical font section (size at most 2^24 bytes) + * nPhysFonts * (physFontRecord + * + nBitmapSizes * nBmapChars * bmapCharRecord) + * + * physFontRecord (size at most 2^24 bytes) + * 14 bytes (font info) + * + 1 byte (flags) + * + 0-2 (depending on `flags') + * + 0-? (structure too complicated to be shown here; depending on + * `flags'; contains `nBitmapSizes' and `nBmapChars') + * + 3 bytes (nAuxBytes) + * + nAuxBytes + * + 1 byte (nBlueValues) + * + 2 * nBlueValues + * + 6 bytes (hinting data) + * + 2 bytes (nCharacters) + * + nCharacters * (4-10 bytes) (depending on `flags') + * + * ==> minimum size 27 bytes + * + * bmapCharRecord + * 4-7 bytes + * + * Glyph program strings (three possible types: simpleGps, compoundGps, + * and bitmapGps; size at most 2^24 bytes) + * simpleGps (size at most 2^16 bytes) + * 1 byte (flags) + * 1-2 bytes (n[XY]orus, depending on `flags') + * 0-(64+512*2) = 0-1088 bytes (depending on `n[XY]orus') + * 0-? (structure too complicated to be shown here; depending on + * `flags') + * 1-? glyph data (faintly resembling PS Type 1 charstrings) + * + * ==> minimum size 3 bytes + * + * compoundGps (size at most 2^16 bytes) + * 1 byte (nElements <= 63, flags) + * + 0-(1+255*(2+255)) = 0-65536 (depending on `flags') + * + nElements * (6-14 bytes) + * + * bitmapGps (size at most 2^16 bytes) + * 1 byte (flags) + * 3-13 bytes (position info, depending on `flags') + * 0-? bitmap data + * + * ==> minimum size 4 bytes + * + * PFR trailer + * 8 bytes + * + * + * ==> minimum size of a valid PFR: + * 58 (header) + * + 2 (nLogFonts) + * + 27 (1 physFontRecord) + * + 8 (trailer) + * ----- + * 95 bytes + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** EXTRA ITEMS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ) + { + return pfr_extra_items_parse( pp, limit, NULL, NULL ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* p = *pp; + FT_UInt num_items, item_type, item_size; + + + PFR_CHECK( 1 ); + num_items = PFR_NEXT_BYTE( p ); + + for ( ; num_items > 0; num_items-- ) + { + PFR_CHECK( 2 ); + item_size = PFR_NEXT_BYTE( p ); + item_type = PFR_NEXT_BYTE( p ); + + PFR_CHECK( item_size ); + + if ( item_list ) + { + PFR_ExtraItem extra = item_list; + + + for ( extra = item_list; extra->parser != NULL; extra++ ) + { + if ( extra->type == item_type ) + { + error = extra->parser( p, p + item_size, item_data ); + if ( error ) + goto Exit; + + break; + } + } + } + + p += item_size; + } + + Exit: + *pp = p; + return error; + + Too_Short: + FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR HEADER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static const FT_Frame_Field pfr_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PFR_HeaderRec + + FT_FRAME_START( 58 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_USHORT( version ), + FT_FRAME_USHORT( signature2 ), + FT_FRAME_USHORT( header_size ), + + FT_FRAME_USHORT( log_dir_size ), + FT_FRAME_USHORT( log_dir_offset ), + + FT_FRAME_USHORT( log_font_max_size ), + FT_FRAME_UOFF3 ( log_font_section_size ), + FT_FRAME_UOFF3 ( log_font_section_offset ), + + FT_FRAME_USHORT( phy_font_max_size ), + FT_FRAME_UOFF3 ( phy_font_section_size ), + FT_FRAME_UOFF3 ( phy_font_section_offset ), + + FT_FRAME_USHORT( gps_max_size ), + FT_FRAME_UOFF3 ( gps_section_size ), + FT_FRAME_UOFF3 ( gps_section_offset ), + + FT_FRAME_BYTE ( max_blue_values ), + FT_FRAME_BYTE ( max_x_orus ), + FT_FRAME_BYTE ( max_y_orus ), + + FT_FRAME_BYTE ( phy_font_max_size_high ), + FT_FRAME_BYTE ( color_flags ), + + FT_FRAME_UOFF3 ( bct_max_size ), + FT_FRAME_UOFF3 ( bct_set_max_size ), + FT_FRAME_UOFF3 ( phy_bct_set_max_size ), + + FT_FRAME_USHORT( num_phy_fonts ), + FT_FRAME_BYTE ( max_vert_stem_snap ), + FT_FRAME_BYTE ( max_horz_stem_snap ), + FT_FRAME_USHORT( max_chars ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ) + { + FT_Error error; + + + /* read header directly */ + if ( !FT_STREAM_SEEK( 0 ) && + !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) ) + { + /* make a few adjustments to the header */ + header->phy_font_max_size += + (FT_UInt32)header->phy_font_max_size_high << 16; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Bool ) + pfr_header_check( PFR_Header header ) + { + FT_Bool result = 1; + + + /* check signature and header size */ + if ( header->signature != 0x50465230L || /* "PFR0" */ + header->version > 4 || + header->header_size < 58 || + header->signature2 != 0x0D0A ) /* CR/LF */ + result = 0; + + return result; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR LOGICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 section_offset, + FT_Long *acount ) + { + FT_Error error; + FT_UInt count; + FT_UInt result = 0; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( count ) ) + goto Exit; + + /* check maximum value and a rough minimum size: */ + /* - no more than 13106 log fonts */ + /* - we need 5 bytes for a log header record */ + /* - we need at least 18 bytes for a log font record */ + /* - the overall size is at least 95 bytes plus the */ + /* log header and log font records */ + if ( count > ( ( 1 << 16 ) - 2 ) / 5 || + 2 + count * 5 >= stream->size - section_offset || + 95 + count * ( 5 + 18 ) >= stream->size ) + { + FT_ERROR(( "pfr_log_font_count:" + " invalid number of logical fonts\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + result = count; + + Exit: + *acount = (FT_Long)result; + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt idx, + FT_UInt32 section_offset, + FT_Bool size_increment ) + { + FT_UInt num_log_fonts; + FT_UInt flags; + FT_UInt32 offset; + FT_UInt32 size; + FT_Error error; + + + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( num_log_fonts ) ) + goto Exit; + + if ( idx >= num_log_fonts ) + return FT_THROW( Invalid_Argument ); + + if ( FT_STREAM_SKIP( idx * 5 ) || + FT_READ_USHORT( size ) || + FT_READ_UOFF3 ( offset ) ) + goto Exit; + + /* save logical font size and offset */ + log_font->size = size; + log_font->offset = offset; + + /* now, check the rest of the table before loading it */ + { + FT_Byte* p; + FT_Byte* limit; + FT_UInt local; + + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 13 ); + + log_font->matrix[0] = PFR_NEXT_LONG( p ); + log_font->matrix[1] = PFR_NEXT_LONG( p ); + log_font->matrix[2] = PFR_NEXT_LONG( p ); + log_font->matrix[3] = PFR_NEXT_LONG( p ); + + flags = PFR_NEXT_BYTE( p ); + + local = 0; + if ( flags & PFR_LOG_STROKE ) + { + local++; + if ( flags & PFR_LOG_2BYTE_STROKE ) + local++; + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + local += 3; + } + if ( flags & PFR_LOG_BOLD ) + { + local++; + if ( flags & PFR_LOG_2BYTE_BOLD ) + local++; + } + + PFR_CHECK( local ); + + if ( flags & PFR_LOG_STROKE ) + { + log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + log_font->miter_limit = PFR_NEXT_LONG( p ); + } + + if ( flags & PFR_LOG_BOLD ) + log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + + if ( flags & PFR_LOG_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Fail; + } + + PFR_CHECK( 5 ); + log_font->phys_size = PFR_NEXT_USHORT( p ); + log_font->phys_offset = PFR_NEXT_ULONG( p ); + if ( size_increment ) + { + PFR_CHECK( 1 ); + log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16; + } + } + + Fail: + FT_FRAME_EXIT(); + + Exit: + return error; + + Too_Short: + FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + + /***********************************************************************/ + /***********************************************************************/ + /***** *****/ + /***** PFR PHYSICAL FONTS *****/ + /***** *****/ + /***********************************************************************/ + /***********************************************************************/ + + + /* load bitmap strikes lists */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = FT_Err_Ok; + + + PFR_CHECK( 5 ); + + p += 3; /* skip bctSize */ + flags0 = PFR_NEXT_BYTE( p ); + count = PFR_NEXT_BYTE( p ); + + /* re-allocate when needed */ + if ( phy_font->num_strikes + count > phy_font->max_strikes ) + { + FT_UInt new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 ); + + + if ( FT_RENEW_ARRAY( phy_font->strikes, + phy_font->num_strikes, + new_max ) ) + goto Exit; + + phy_font->max_strikes = new_max; + } + + size1 = 1 + 1 + 1 + 2 + 2 + 1; + if ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + size1++; + + if ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + size1++; + + if ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + size1++; + + strike = phy_font->strikes + phy_font->num_strikes; + + PFR_CHECK( count * size1 ); + + for ( n = 0; n < count; n++, strike++ ) + { + strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + strike->flags = PFR_NEXT_BYTE( p ); + + strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + + strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + } + + phy_font->num_strikes += count; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_bitmap_info:" + " invalid bitmap info table\n" )); + goto Exit; + } + + + /* Load font ID. This is a so-called `unique' name that is rather + * long and descriptive (like `Tiresias ScreenFont v7.51'). + * + * Note that a PFR font's family name is contained in an *undocumented* + * string of the `auxiliary data' portion of a physical font record. This + * may also contain the `real' style name! + * + * If no family name is present, the font ID is used instead for the + * family. + */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_UInt len = (FT_UInt)( limit - p ); + + + if ( phy_font->font_id ) + goto Exit; + + if ( FT_QALLOC( phy_font->font_id, len + 1 ) ) + goto Exit; + + /* copy font ID name, and terminate it for safety */ + FT_MEM_COPY( phy_font->font_id, p, len ); + phy_font->font_id[len] = 0; + + Exit: + return error; + } + + + /* load stem snap tables */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_UInt count, num_vert, num_horz; + FT_Int* snaps = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( phy_font->vertical.stem_snaps ) + goto Exit; + + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + + num_vert = count & 15; + num_horz = count >> 4; + count = num_vert + num_horz; + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( snaps, count ) ) + goto Exit; + + phy_font->vertical.stem_snaps = snaps; + phy_font->horizontal.stem_snaps = snaps + num_vert; + + for ( ; count > 0; count--, snaps++ ) + *snaps = FT_NEXT_SHORT( p ); + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_stem_snaps:" + " invalid stem snaps table\n" )); + goto Exit; + } + + + /* load kerning pair data */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) + { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + PFR_KernItem item = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + + + if ( FT_NEW( item ) ) + goto Exit; + + PFR_CHECK( 4 ); + + item->pair_count = PFR_NEXT_BYTE( p ); + item->base_adj = PFR_NEXT_SHORT( p ); + item->flags = PFR_NEXT_BYTE( p ); + item->offset = phy_font->offset + + (FT_Offset)( p - phy_font->cursor ); + +#ifndef PFR_CONFIG_NO_CHECKS + item->pair_size = 3; + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + item->pair_size += 2; + + if ( item->flags & PFR_KERN_2BYTE_ADJ ) + item->pair_size += 1; + + PFR_CHECK( item->pair_count * item->pair_size ); +#endif + + /* load first and last pairs into the item to speed up */ + /* lookup later... */ + if ( item->pair_count > 0 ) + { + FT_UInt char1, char2; + FT_Byte* q; + + + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + { + q = p; + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + else + { + q = p; + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + + /* add new item to the current list */ + item->next = NULL; + *phy_font->kern_items_tail = item; + phy_font->kern_items_tail = &item->next; + phy_font->num_kern_pairs += item->pair_count; + } + else + { + /* empty item! */ + FT_FREE( item ); + } + + Exit: + return error; + + Too_Short: + FT_FREE( item ); + + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_extra_item_load_kerning_pairs:" + " invalid kerning pairs table\n" )); + goto Exit; + } + + + static const PFR_ExtraItemRec pfr_phy_font_extra_items[] = + { + { 1, pfr_extra_item_load_bitmap_info }, + { 2, pfr_extra_item_load_font_id }, + { 3, pfr_extra_item_load_stem_snaps }, + { 4, pfr_extra_item_load_kerning_pairs }, + { 0, NULL } + }; + + + /* + * Load a name from the auxiliary data. Since this extracts undocumented + * strings from the font file, we need to be careful here. + */ + static FT_Error + pfr_aux_name_load( FT_Byte* p, + FT_UInt len, + FT_Memory memory, + FT_String* *astring ) + { + FT_Error error = FT_Err_Ok; + FT_String* result = NULL; + FT_UInt n, ok; + + + if ( *astring ) + FT_FREE( *astring ); + + if ( len > 0 && p[len - 1] == 0 ) + len--; + + /* check that each character is ASCII */ + /* for making sure not to load garbage */ + ok = ( len > 0 ); + for ( n = 0; n < len; n++ ) + if ( p[n] < 32 || p[n] > 127 ) + { + ok = 0; + break; + } + + if ( ok ) + { + if ( FT_QALLOC( result, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( result, p, len ); + result[len] = 0; + } + + Exit: + *astring = result; + return error; + } + + + FT_LOCAL_DEF( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ) + { + FT_FREE( phy_font->font_id ); + FT_FREE( phy_font->family_name ); + FT_FREE( phy_font->style_name ); + + FT_FREE( phy_font->vertical.stem_snaps ); + phy_font->vertical.num_stem_snaps = 0; + + phy_font->horizontal.stem_snaps = NULL; + phy_font->horizontal.num_stem_snaps = 0; + + FT_FREE( phy_font->strikes ); + phy_font->num_strikes = 0; + phy_font->max_strikes = 0; + + FT_FREE( phy_font->chars ); + phy_font->num_chars = 0; + phy_font->chars_offset = 0; + + FT_FREE( phy_font->blue_values ); + phy_font->num_blue_values = 0; + + { + PFR_KernItem item, next; + + + item = phy_font->kern_items; + while ( item ) + { + next = item->next; + FT_FREE( item ); + item = next; + } + phy_font->kern_items = NULL; + phy_font->kern_items_tail = NULL; + } + + phy_font->num_kern_pairs = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt flags; + FT_ULong num_aux; + FT_Byte* p; + FT_Byte* limit; + + + phy_font->memory = memory; + phy_font->offset = offset; + + phy_font->kern_items = NULL; + phy_font->kern_items_tail = &phy_font->kern_items; + + if ( FT_STREAM_SEEK( offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + + phy_font->cursor = stream->cursor; + + p = stream->cursor; + limit = p + size; + + PFR_CHECK( 15 ); + phy_font->font_ref_number = PFR_NEXT_USHORT( p ); + phy_font->outline_resolution = PFR_NEXT_USHORT( p ); + phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); + phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); + phy_font->flags = flags = PFR_NEXT_BYTE( p ); + + if ( !phy_font->outline_resolution || + !phy_font->metrics_resolution ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid resolution\n" )); + goto Fail; + } + + /* get the standard advance for non-proportional fonts */ + if ( !( flags & PFR_PHY_PROPORTIONAL ) ) + { + PFR_CHECK( 2 ); + phy_font->standard_advance = PFR_NEXT_SHORT( p ); + } + + /* load the extra items when present */ + if ( flags & PFR_PHY_EXTRA_ITEMS ) + { + error = pfr_extra_items_parse( &p, limit, + pfr_phy_font_extra_items, phy_font ); + if ( error ) + goto Fail; + } + + /* In certain fonts, the auxiliary bytes contain interesting */ + /* information. These are not in the specification but can be */ + /* guessed by looking at the content of a few 'PFR0' fonts. */ + PFR_CHECK( 3 ); + num_aux = PFR_NEXT_ULONG( p ); + + if ( num_aux > 0 ) + { + FT_Byte* q = p; + FT_Byte* q2; + + + PFR_CHECK_SIZE( num_aux ); + p += num_aux; + + while ( num_aux > 0 ) + { + FT_UInt length, type; + + + if ( q + 4 > p ) + break; + + length = PFR_NEXT_USHORT( q ); + if ( length < 4 || length > num_aux ) + break; + + q2 = q + length - 2; + type = PFR_NEXT_USHORT( q ); + + switch ( type ) + { + case 1: + /* this seems to correspond to the font's family name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->family_name ); + if ( error ) + goto Exit; + break; + + case 2: + if ( q + 32 > q2 ) + break; + + q += 10; + phy_font->ascent = PFR_NEXT_SHORT( q ); + phy_font->descent = PFR_NEXT_SHORT( q ); + phy_font->leading = PFR_NEXT_SHORT( q ); + break; + + case 3: + /* this seems to correspond to the font's style name, padded to */ + /* an even number of bytes with a zero byte appended if needed */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->style_name ); + if ( error ) + goto Exit; + break; + + default: + ; + } + + q = q2; + num_aux -= length; + } + } + + /* read the blue values */ + { + FT_UInt n, count; + + + PFR_CHECK( 1 ); + phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); + + PFR_CHECK( count * 2 ); + + if ( FT_QNEW_ARRAY( phy_font->blue_values, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); + } + + PFR_CHECK( 8 ); + phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); + phy_font->blue_scale = PFR_NEXT_BYTE( p ); + + phy_font->vertical.standard = PFR_NEXT_USHORT( p ); + phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); + + /* read the character descriptors */ + { + FT_UInt n, count, Size; + + + phy_font->num_chars = count = PFR_NEXT_USHORT( p ); + phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor ); + + if ( !phy_font->num_chars ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: no glyphs\n" )); + goto Fail; + } + + Size = 1 + 1 + 2; + if ( flags & PFR_PHY_2BYTE_CHARCODE ) + Size += 1; + + if ( flags & PFR_PHY_PROPORTIONAL ) + Size += 2; + + if ( flags & PFR_PHY_ASCII_CODE ) + Size += 1; + + if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + Size += 1; + + if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + Size += 1; + + PFR_CHECK_SIZE( count * Size ); + + if ( FT_QNEW_ARRAY( phy_font->chars, count ) ) + goto Fail; + + for ( n = 0; n < count; n++ ) + { + PFR_Char cur = &phy_font->chars[n]; + + + cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) + ? PFR_NEXT_SHORT( p ) + : phy_font->standard_advance; + +#if 0 + cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) + ? PFR_NEXT_BYTE( p ) + : 0; +#else + if ( flags & PFR_PHY_ASCII_CODE ) + p += 1; +#endif + cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + + cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + } + } + + /* that's it! */ + + Fail: + FT_FRAME_EXIT(); + + /* save position of bitmap info */ + phy_font->bct_offset = FT_STREAM_POS(); + phy_font->cursor = NULL; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); + goto Fail; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrload.h b/Dependencies/freetype/freetype/src/pfr/pfrload.h new file mode 100644 index 00000000..7390296d --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrload.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * pfrload.h + * + * FreeType PFR loader (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRLOAD_H_ +#define PFRLOAD_H_ + +#include "pfrobjs.h" +#include + + +FT_BEGIN_HEADER + + /* some size checks should be always done (mainly to prevent */ + /* excessive allocation for malformed data), ... */ +#define PFR_CHECK_SIZE( x ) do \ + { \ + if ( p + (x) > limit ) \ + goto Too_Short; \ + } while ( 0 ) + + /* ... and some only if intensive checking is explicitly requested */ +#ifdef PFR_CONFIG_NO_CHECKS +#define PFR_CHECK( x ) do { } while ( 0 ) +#else +#define PFR_CHECK PFR_CHECK_SIZE +#endif + +#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p ) +#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p ) +#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p ) +#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p ) +#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p ) +#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p ) + + + /* handling extra items */ + + typedef FT_Error + (*PFR_ExtraItem_ParseFunc)( FT_Byte* p, + FT_Byte* limit, + FT_Pointer data ); + + typedef struct PFR_ExtraItemRec_ + { + FT_UInt type; + PFR_ExtraItem_ParseFunc parser; + + } PFR_ExtraItemRec; + + typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem; + + + FT_LOCAL( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ); + + FT_LOCAL( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ); + + + /* load a PFR header */ + FT_LOCAL( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ); + + /* check a PFR header */ + FT_LOCAL( FT_Bool ) + pfr_header_check( PFR_Header header ); + + + /* return number of logical fonts in this file */ + FT_LOCAL( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 log_section_offset, + FT_Long *acount ); + + /* load a pfr logical font entry */ + FT_LOCAL( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt face_index, + FT_UInt32 section_offset, + FT_Bool size_increment ); + + + /* load a physical font entry */ + FT_LOCAL( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ); + + /* finalize a physical font */ + FT_LOCAL( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ); + + /* */ + +FT_END_HEADER + +#endif /* PFRLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrobjs.c b/Dependencies/freetype/freetype/src/pfr/pfrobjs.c new file mode 100644 index 00000000..084d2ef5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrobjs.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * pfrobjs.c + * + * FreeType PFR object methods (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrobjs.h" +#include "pfrload.h" +#include "pfrgload.h" +#include "pfrcmap.h" +#include "pfrsbit.h" +#include +#include +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FACE OBJECT METHODS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + pfr_face_done( FT_Face pfrface ) /* PFR_Face */ + { + PFR_Face face = (PFR_Face)pfrface; + FT_Memory memory; + + + if ( !face ) + return; + + memory = pfrface->memory; + + /* we don't want dangling pointers */ + pfrface->family_name = NULL; + pfrface->style_name = NULL; + + /* finalize the physical font record */ + pfr_phy_font_done( &face->phy_font, memory ); + + /* no need to finalize the logical font or the header */ + FT_FREE( pfrface->available_sizes ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face pfrface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "PFR driver\n" )); + + /* load the header and check it */ + error = pfr_header_load( &face->header, stream ); + if ( error ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( !pfr_header_check( &face->header ) ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* check face index */ + { + FT_Long num_faces; + + + error = pfr_log_font_count( stream, + face->header.log_dir_offset, + &num_faces ); + if ( error ) + goto Exit; + + pfrface->num_faces = num_faces; + } + + if ( face_index < 0 ) + goto Exit; + + if ( ( face_index & 0xFFFF ) >= pfrface->num_faces ) + { + FT_ERROR(( "pfr_face_init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* load the face */ + error = pfr_log_font_load( + &face->log_font, + stream, + (FT_UInt)( face_index & 0xFFFF ), + face->header.log_dir_offset, + FT_BOOL( face->header.phy_font_max_size_high ) ); + if ( error ) + goto Exit; + + /* load the physical font descriptor */ + error = pfr_phy_font_load( &face->phy_font, stream, + face->log_font.phys_offset, + face->log_font.phys_size ); + if ( error ) + goto Exit; + + /* set up all root face fields */ + { + PFR_PhyFont phy_font = &face->phy_font; + + + pfrface->face_index = face_index & 0xFFFF; + pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1; + + pfrface->face_flags |= FT_FACE_FLAG_SCALABLE; + + /* if gps_offset == 0 for all characters, we */ + /* assume that the font only contains bitmaps */ + { + FT_UInt nn; + + + for ( nn = 0; nn < phy_font->num_chars; nn++ ) + if ( phy_font->chars[nn].gps_offset != 0 ) + break; + + if ( nn == phy_font->num_chars ) + { + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + else + { + FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } + } + + if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( phy_font->flags & PFR_PHY_VERTICAL ) + pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; + else + pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + + if ( phy_font->num_kern_pairs > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + + /* If no family name was found in the `undocumented' auxiliary + * data, use the font ID instead. This sucks but is better than + * nothing. + */ + pfrface->family_name = phy_font->family_name; + if ( !pfrface->family_name ) + pfrface->family_name = phy_font->font_id; + + /* note that the style name can be NULL in certain PFR fonts, + * probably meaning `Regular' + */ + pfrface->style_name = phy_font->style_name; + + pfrface->num_fixed_sizes = 0; + pfrface->available_sizes = NULL; + + pfrface->bbox = phy_font->bbox; + pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; + pfrface->ascender = (FT_Short) phy_font->bbox.yMax; + pfrface->descender = (FT_Short) phy_font->bbox.yMin; + + pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); + if ( pfrface->height < pfrface->ascender - pfrface->descender ) + pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender ); + + if ( phy_font->num_strikes > 0 ) + { + FT_UInt n, count = phy_font->num_strikes; + FT_Bitmap_Size* size; + PFR_Strike strike; + FT_Memory memory = pfrface->memory; + + + if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) ) + goto Exit; + + size = pfrface->available_sizes; + strike = phy_font->strikes; + for ( n = 0; n < count; n++, size++, strike++ ) + { + size->height = (FT_Short)strike->y_ppm; + size->width = (FT_Short)strike->x_ppm; + size->size = (FT_Pos)( strike->y_ppm << 6 ); + size->x_ppem = (FT_Pos)( strike->x_ppm << 6 ); + size->y_ppem = (FT_Pos)( strike->y_ppm << 6 ); + } + pfrface->num_fixed_sizes = (FT_Int)count; + } + + /* now compute maximum advance width */ + if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; + else + { + FT_Int max = 0; + FT_UInt count = phy_font->num_chars; + PFR_Char gchar = phy_font->chars; + + + for ( ; count > 0; count--, gchar++ ) + { + if ( max < gchar->advance ) + max = gchar->advance; + } + + pfrface->max_advance_width = (FT_Short)max; + } + + pfrface->max_advance_height = pfrface->height; + + pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); + pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); + + /* create charmap */ + { + FT_CharMapRec charmap; + + + charmap.face = pfrface; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); + } + + /* check whether we have loaded any kerning pairs */ + if ( phy_font->num_kern_pairs ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SLOT OBJECT METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + FT_GlyphLoader loader = pfrslot->internal->loader; + + + pfr_glyph_init( &slot->glyph, loader ); + + return 0; + } + + + FT_LOCAL_DEF( void ) + pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ + { + PFR_Slot slot = (PFR_Slot)pfrslot; + + + pfr_glyph_done( &slot->glyph ); + } + + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ + FT_Size pfrsize, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + PFR_Size size = (PFR_Size)pfrsize; + FT_Error error; + PFR_Face face = (PFR_Face)pfrslot->face; + PFR_Char gchar; + FT_Outline* outline = &pfrslot->outline; + FT_ULong gps_offset; + + + FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); + + if ( gindex > 0 ) + gindex--; + + if ( !face || gindex >= face->phy_font.num_chars ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* try to load an embedded bitmap */ + if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) ) + { + error = pfr_slot_load_bitmap( + slot, + size, + gindex, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + if ( !error ) + goto Exit; + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + gchar = face->phy_font.chars + gindex; + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; + outline->n_points = 0; + outline->n_contours = 0; + gps_offset = face->header.gps_section_offset; + + /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ + error = pfr_glyph_load( &slot->glyph, face->root.stream, + gps_offset, gchar->gps_offset, gchar->gps_size ); + + if ( !error ) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &pfrslot->metrics; + FT_Pos advance; + FT_UInt em_metrics, em_outline; + FT_Bool scaling; + + + scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + + /* copy outline data */ + *outline = slot->glyph.loader->base.outline; + + outline->flags &= ~FT_OUTLINE_OWNER; + outline->flags |= FT_OUTLINE_REVERSE_FILL; + + if ( pfrsize->metrics.y_ppem < 24 ) + outline->flags |= FT_OUTLINE_HIGH_PRECISION; + + /* compute the advance vector */ + metrics->horiAdvance = 0; + metrics->vertAdvance = 0; + + advance = gchar->advance; + em_metrics = face->phy_font.metrics_resolution; + em_outline = face->phy_font.outline_resolution; + + if ( em_metrics != em_outline ) + advance = FT_MulDiv( advance, + (FT_Long)em_outline, + (FT_Long)em_metrics ); + + if ( face->phy_font.flags & PFR_PHY_VERTICAL ) + metrics->vertAdvance = advance; + else + metrics->horiAdvance = advance; + + pfrslot->linearHoriAdvance = metrics->horiAdvance; + pfrslot->linearVertAdvance = metrics->vertAdvance; + + /* make up vertical metrics(?) */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + +#if 0 /* some fonts seem to be broken here! */ + + /* Apply the font matrix, if any. */ + /* TODO: Test existing fonts with unusual matrix */ + /* whether we have to adjust Units per EM. */ + { + FT_Matrix font_matrix; + + + font_matrix.xx = face->log_font.matrix[0] << 8; + font_matrix.yx = face->log_font.matrix[1] << 8; + font_matrix.xy = face->log_font.matrix[2] << 8; + font_matrix.yy = face->log_font.matrix[3] << 8; + + FT_Outline_Transform( outline, &font_matrix ); + } +#endif + + /* scale when needed */ + if ( scaling ) + { + FT_Int n; + FT_Fixed x_scale = pfrsize->metrics.x_scale; + FT_Fixed y_scale = pfrsize->metrics.y_scale; + FT_Vector* vec = outline->points; + + + /* scale outline points */ + for ( n = 0; n < outline->n_points; n++, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* scale the advance */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the rest of the metrics */ + FT_Outline_Get_CBox( outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax - metrics->height; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** KERNING METHOD *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = FT_Err_Ok; + PFR_PhyFont phy_font = &face->phy_font; + FT_UInt32 code1, code2, pair; + + + kerning->x = 0; + kerning->y = 0; + + /* PFR indexing skips .notdef, which becomes UINT_MAX */ + glyph1--; + glyph2--; + + /* check the array bounds, .notdef is automatically out */ + if ( glyph1 >= phy_font->num_chars || + glyph2 >= phy_font->num_chars ) + goto Exit; + + /* convert glyph indices to character codes */ + code1 = phy_font->chars[glyph1].char_code; + code2 = phy_font->chars[glyph2].char_code; + pair = PFR_KERN_INDEX( code1, code2 ); + + /* now search the list of kerning items */ + { + PFR_KernItem item = phy_font->kern_items; + FT_Stream stream = pfrface->stream; + + + for ( ; item; item = item->next ) + { + if ( pair >= item->pair1 && pair <= item->pair2 ) + goto FoundPair; + } + goto Exit; + + FoundPair: /* we found an item, now parse it and find the value if any */ + if ( FT_STREAM_SEEK( item->offset ) || + FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) + goto Exit; + + { + FT_UInt count = item->pair_count; + FT_UInt size = item->pair_size; + FT_UInt power = 1 << FT_MSB( count ); + FT_UInt probe = power * size; + FT_UInt extra = count - power; + FT_Byte* base = stream->cursor; + FT_Bool twobytes = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR ); + FT_Bool twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ ); + FT_Byte* p; + FT_UInt32 cpair; + + + if ( extra > 0 ) + { + p = base + extra * size; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + { + if ( twobyte_adj ) + p += 2; + else + p++; + base = p; + } + } + + while ( probe > size ) + { + probe >>= 1; + p = base + probe; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + goto Found; + + if ( cpair < pair ) + base += probe; + } + + p = base; + + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + + if ( cpair == pair ) + { + FT_Int value; + + + Found: + if ( twobyte_adj ) + value = FT_PEEK_SHORT( p ); + else + value = p[0]; + + kerning->x = item->base_adj + value; + } + } + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrobjs.h b/Dependencies/freetype/freetype/src/pfr/pfrobjs.h new file mode 100644 index 00000000..1b548a1b --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrobjs.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * + * pfrobjs.h + * + * FreeType PFR object methods (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFROBJS_H_ +#define PFROBJS_H_ + +#include "pfrtypes.h" + + +FT_BEGIN_HEADER + + typedef struct PFR_FaceRec_* PFR_Face; + + typedef struct PFR_SizeRec_* PFR_Size; + + typedef struct PFR_SlotRec_* PFR_Slot; + + + typedef struct PFR_FaceRec_ + { + FT_FaceRec root; + PFR_HeaderRec header; + PFR_LogFontRec log_font; + PFR_PhyFontRec phy_font; + + } PFR_FaceRec; + + + typedef struct PFR_SizeRec_ + { + FT_SizeRec root; + + } PFR_SizeRec; + + + typedef struct PFR_SlotRec_ + { + FT_GlyphSlotRec root; + PFR_GlyphRec glyph; + + } PFR_SlotRec; + + + FT_LOCAL( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face face, /* PFR_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + pfr_face_done( FT_Face face ); /* PFR_Face */ + + + FT_LOCAL( FT_Error ) + pfr_face_get_kerning( FT_Face face, /* PFR_Face */ + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + + FT_LOCAL( FT_Error ) + pfr_slot_init( FT_GlyphSlot slot ); /* PFR_Slot */ + + FT_LOCAL( void ) + pfr_slot_done( FT_GlyphSlot slot ); /* PFR_Slot */ + + + FT_LOCAL( FT_Error ) + pfr_slot_load( FT_GlyphSlot slot, /* PFR_Slot */ + FT_Size size, /* PFR_Size */ + FT_UInt gindex, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* PFROBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrsbit.c b/Dependencies/freetype/freetype/src/pfr/pfrsbit.c new file mode 100644 index 00000000..96cc7fec --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrsbit.c @@ -0,0 +1,813 @@ +/**************************************************************************** + * + * pfrsbit.c + * + * FreeType PFR bitmap loader (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "pfrsbit.h" +#include "pfrload.h" +#include +#include + +#include "pfrerror.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pfr + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PFR BIT WRITER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct PFR_BitWriter_ + { + FT_Byte* line; /* current line start */ + FT_Int pitch; /* line size in bytes */ + FT_UInt width; /* width in pixels/bits */ + FT_UInt rows; /* number of remaining rows to scan */ + FT_UInt total; /* total number of bits to draw */ + + } PFR_BitWriterRec, *PFR_BitWriter; + + + static void + pfr_bitwriter_init( PFR_BitWriter writer, + FT_Bitmap* target, + FT_Bool decreasing ) + { + writer->line = target->buffer; + writer->pitch = target->pitch; + writer->width = target->width; + writer->rows = target->rows; + writer->total = writer->width * writer->rows; + + if ( !decreasing ) + { + writer->line += writer->pitch * (FT_Int)( target->rows - 1 ); + writer->pitch = -writer->pitch; + } + } + + + static void + pfr_bitwriter_decode_bytes( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt val = 0; + FT_UInt c = 0; + + + n = (FT_UInt)( limit - p ) * 8; + if ( n > writer->total ) + n = writer->total; + + reload = n & 7; + + for ( ; n > 0; n-- ) + { + if ( ( n & 7 ) == reload ) + val = *p++; + + if ( val & 0x80 ) + c |= mask; + + val <<= 1; + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte)c; + } + + + static void + pfr_bitwriter_decode_rle1( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count, counts[2]; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + counts[0] = 0; + counts[1] = 0; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( phase ) + { + FT_Int v; + + + if ( p >= limit ) + break; + + v = *p++; + counts[0] = v >> 4; + counts[1] = v & 15; + phase = 0; + count = counts[0]; + } + else + { + phase = 1; + count = counts[1]; + } + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + static void + pfr_bitwriter_decode_rle2( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int phase, count; + FT_UInt n, reload; + FT_UInt left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + + + n = writer->total; + + phase = 1; + count = 0; + reload = 1; + + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( p >= limit ) + break; + + count = *p++; + phase = phase ^ 1; + + } while ( count == 0 ); + } + + if ( phase ) + c |= mask; + + mask >>= 1; + + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + left = writer->width; + + writer->line += writer->pitch; + cur = writer->line; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + cur++; + } + + reload = ( --count <= 0 ); + } + + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP DATA DECODING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + pfr_lookup_bitmap_data( FT_Byte* base, + FT_Byte* limit, + FT_UInt count, + FT_UInt* flags, + FT_UInt char_code, + FT_ULong* found_offset, + FT_ULong* found_size ) + { + FT_UInt min, max, mid, char_len; + FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); + FT_Byte* buff; + + + char_len = 4; + if ( two ) + char_len += 1; + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + if ( !( *flags & PFR_BITMAP_CHARCODES_VALIDATED ) ) + { + FT_Byte* p; + FT_Byte* lim; + FT_UInt code; + FT_Long prev_code; + + + *flags |= PFR_BITMAP_VALID_CHARCODES; + prev_code = -1; + lim = base + count * char_len; + + if ( lim > limit ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " number of bitmap records too large,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + } + else + { + /* check whether records are sorted by code */ + for ( p = base; p < lim; p += char_len ) + { + if ( two ) + code = FT_PEEK_USHORT( p ); + else + code = *p; + + if ( (FT_Long)code <= prev_code ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " bitmap records are not sorted,\n" )); + FT_TRACE0(( " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + break; + } + + prev_code = code; + } + } + + *flags |= PFR_BITMAP_CHARCODES_VALIDATED; + } + + /* ignore bitmaps in case table is not valid */ + /* (this might be sanitized, but PFR is dead...) */ + if ( !( *flags & PFR_BITMAP_VALID_CHARCODES ) ) + goto Fail; + + min = 0; + max = count; + mid = min + ( max - min ) / 2; + + /* binary search */ + while ( min < max ) + { + FT_UInt code; + + + buff = base + mid * char_len; + + if ( two ) + code = PFR_NEXT_USHORT( buff ); + else + code = PFR_NEXT_BYTE( buff ); + + if ( char_code < code ) + max = mid; + else if ( char_code > code ) + min = mid + 1; + else + goto Found_It; + + /* reasonable prediction in a continuous block */ + mid += char_code - code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + Fail: + /* Not found */ + *found_size = 0; + *found_offset = 0; + return; + + Found_It: + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) + *found_size = PFR_NEXT_USHORT( buff ); + else + *found_size = PFR_NEXT_BYTE( buff ); + + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) + *found_offset = PFR_NEXT_ULONG( buff ); + else + *found_offset = PFR_NEXT_USHORT( buff ); + } + + + /* load bitmap metrics. `*aadvance' must be set to the default value */ + /* before calling this function */ + /* */ + static FT_Error + pfr_load_bitmap_metrics( FT_Byte** pdata, + FT_Byte* limit, + FT_Long scaled_advance, + FT_Long *axpos, + FT_Long *aypos, + FT_UInt *axsize, + FT_UInt *aysize, + FT_Long *aadvance, + FT_UInt *aformat ) + { + FT_Error error = FT_Err_Ok; + FT_Byte flags; + FT_Byte b; + FT_Byte* p = *pdata; + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize; + + + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + + xpos = 0; + ypos = 0; + xsize = 0; + ysize = 0; + advance = 0; + + switch ( flags & 3 ) + { + case 0: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xpos = (FT_Char)b >> 4; + ypos = ( (FT_Char)( b << 4 ) ) >> 4; + break; + + case 1: + PFR_CHECK( 2 ); + xpos = PFR_NEXT_INT8( p ); + ypos = PFR_NEXT_INT8( p ); + break; + + case 2: + PFR_CHECK( 4 ); + xpos = PFR_NEXT_SHORT( p ); + ypos = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 6 ); + xpos = PFR_NEXT_LONG( p ); + ypos = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + /* blank image */ + xsize = 0; + ysize = 0; + break; + + case 1: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xsize = ( b >> 4 ) & 0xF; + ysize = b & 0xF; + break; + + case 2: + PFR_CHECK( 2 ); + xsize = PFR_NEXT_BYTE( p ); + ysize = PFR_NEXT_BYTE( p ); + break; + + case 3: + PFR_CHECK( 4 ); + xsize = PFR_NEXT_USHORT( p ); + ysize = PFR_NEXT_USHORT( p ); + break; + + default: + ; + } + + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + advance = scaled_advance; + break; + + case 1: + PFR_CHECK( 1 ); + advance = PFR_NEXT_INT8( p ) * 256; + break; + + case 2: + PFR_CHECK( 2 ); + advance = PFR_NEXT_SHORT( p ); + break; + + case 3: + PFR_CHECK( 3 ); + advance = PFR_NEXT_LONG( p ); + break; + + default: + ; + } + + *axpos = xpos; + *aypos = ypos; + *axsize = xsize; + *aysize = ysize; + *aadvance = advance; + *aformat = flags >> 2; + *pdata = p; + + Exit: + return error; + + Too_Short: + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); + goto Exit; + } + + + static FT_Error + pfr_load_bitmap_bits( FT_Byte* p, + FT_Byte* limit, + FT_UInt format, + FT_Bool decreasing, + FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + PFR_BitWriterRec writer; + + + if ( target->rows > 0 && target->width > 0 ) + { + pfr_bitwriter_init( &writer, target, decreasing ); + + switch ( format ) + { + case 0: /* packed bits */ + pfr_bitwriter_decode_bytes( &writer, p, limit ); + break; + + case 1: /* RLE1 */ + pfr_bitwriter_decode_rle1( &writer, p, limit ); + break; + + case 2: /* RLE2 */ + pfr_bitwriter_decode_rle2( &writer, p, limit ); + break; + + default: + ; + } + } + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BITMAP LOADING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ) + { + FT_Error error; + PFR_Face face = (PFR_Face) glyph->root.face; + FT_Stream stream = face->root.stream; + PFR_PhyFont phys = &face->phy_font; + FT_ULong gps_offset; + FT_ULong gps_size; + PFR_Char character; + PFR_Strike strike; + + + character = &phys->chars[glyph_index]; + + /* look up a bitmap strike corresponding to the current */ + /* character dimensions */ + { + FT_UInt n; + + + strike = phys->strikes; + for ( n = 0; n < phys->num_strikes; n++ ) + { + if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && + strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) + goto Found_Strike; + + strike++; + } + + /* couldn't find it */ + return FT_THROW( Invalid_Argument ); + } + + Found_Strike: + + /* now look up the glyph's position within the file */ + { + FT_UInt char_len; + + + char_len = 4; + if ( strike->flags & PFR_BITMAP_2BYTE_CHARCODE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_2BYTE_SIZE ) + char_len += 1; + if ( strike->flags & PFR_BITMAP_3BYTE_OFFSET ) + char_len += 1; + + /* access data directly in the frame to speed up lookups */ + if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || + FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) + goto Exit; + + pfr_lookup_bitmap_data( stream->cursor, + stream->limit, + strike->num_bitmaps, + &strike->flags, + character->char_code, + &gps_offset, + &gps_size ); + + FT_FRAME_EXIT(); + + if ( gps_size == 0 ) + { + /* could not find a bitmap program string for this glyph */ + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + /* get the bitmap metrics */ + { + FT_Long xpos = 0, ypos = 0, advance = 0; + FT_UInt xsize = 0, ysize = 0, format = 0; + FT_Byte* p; + + + /* compute linear advance */ + advance = character->advance; + if ( phys->metrics_resolution != phys->outline_resolution ) + advance = FT_MulDiv( advance, + (FT_Long)phys->outline_resolution, + (FT_Long)phys->metrics_resolution ); + + glyph->root.linearHoriAdvance = advance; + + /* compute default advance, i.e., scaled advance; this can be */ + /* overridden in the bitmap header of certain glyphs */ + advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, + character->advance, + (FT_Long)phys->metrics_resolution ); + + if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || + FT_FRAME_ENTER( gps_size ) ) + goto Exit; + + p = stream->cursor; + error = pfr_load_bitmap_metrics( &p, stream->limit, + advance, + &xpos, &ypos, + &xsize, &ysize, + &advance, &format ); + if ( error ) + goto Exit1; + + /* + * Before allocating the target bitmap, we check whether the given + * bitmap dimensions are valid, depending on the image format. + * + * Format 0: We have a stream of pixels (with 8 pixels per byte). + * + * (xsize * ysize + 7) / 8 <= gps_size + * + * Format 1: Run-length encoding; the high nibble holds the number of + * white bits, the low nibble the number of black bits. In + * other words, a single byte can represent at most 15 + * pixels. + * + * xsize * ysize <= 15 * gps_size + * + * Format 2: Run-length encoding; the high byte holds the number of + * white bits, the low byte the number of black bits. In + * other words, two bytes can represent at most 255 pixels. + * + * xsize * ysize <= 255 * (gps_size + 1) / 2 + */ + switch ( format ) + { + case 0: + if ( ( (FT_ULong)xsize * ysize + 7 ) / 8 > gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 1: + if ( (FT_ULong)xsize * ysize > 15 * gps_size ) + error = FT_THROW( Invalid_Table ); + break; + case 2: + if ( (FT_ULong)xsize * ysize > 255 * ( ( gps_size + 1 ) / 2 ) ) + error = FT_THROW( Invalid_Table ); + break; + default: + FT_ERROR(( "pfr_slot_load_bitmap: invalid image type\n" )); + error = FT_THROW( Invalid_Table ); + } + + if ( error ) + { + if ( FT_ERR_EQ( error, Invalid_Table ) ) + FT_ERROR(( "pfr_slot_load_bitmap: invalid bitmap dimensions\n" )); + goto Exit1; + } + + /* + * XXX: on 16bit systems we return an error for huge bitmaps + * that cause size truncation, because truncated + * size properties make bitmap glyphs broken. + */ + if ( xpos > FT_INT_MAX || + xpos < FT_INT_MIN || + ysize > FT_INT_MAX || + ypos > FT_INT_MAX - (FT_Long)ysize || + ypos + (FT_Long)ysize < FT_INT_MIN ) + { + FT_TRACE1(( "pfr_slot_load_bitmap:" + " huge bitmap glyph %ldx%ld over FT_GlyphSlot\n", + xpos, ypos )); + error = FT_THROW( Invalid_Pixel_Size ); + } + + if ( !error ) + { + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; + + /* Set up glyph bitmap and metrics */ + + /* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */ + glyph->root.bitmap.width = xsize; + glyph->root.bitmap.rows = ysize; + glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3; + glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + /* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */ + glyph->root.metrics.width = (FT_Pos)xsize << 6; + glyph->root.metrics.height = (FT_Pos)ysize << 6; + glyph->root.metrics.horiBearingX = xpos * 64; + glyph->root.metrics.horiBearingY = ypos * 64; + glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); + glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; + glyph->root.metrics.vertBearingY = 0; + glyph->root.metrics.vertAdvance = size->root.metrics.height; + + /* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */ + glyph->root.bitmap_left = (FT_Int)xpos; + glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize ); + + if ( metrics_only ) + goto Exit1; + + /* Allocate and read bitmap data */ + { + FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize; + + + error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); + if ( !error ) + error = pfr_load_bitmap_bits( + p, + stream->limit, + format, + FT_BOOL( face->header.color_flags & + PFR_FLAG_INVERT_BITMAP ), + &glyph->root.bitmap ); + } + } + + Exit1: + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrsbit.h b/Dependencies/freetype/freetype/src/pfr/pfrsbit.h new file mode 100644 index 00000000..105a2991 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrsbit.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * pfrsbit.h + * + * FreeType PFR bitmap loader (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRSBIT_H_ +#define PFRSBIT_H_ + +#include "pfrobjs.h" + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index, + FT_Bool metrics_only ); + +FT_END_HEADER + +#endif /* PFRSBIT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pfr/pfrtypes.h b/Dependencies/freetype/freetype/src/pfr/pfrtypes.h new file mode 100644 index 00000000..435a77c8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pfr/pfrtypes.h @@ -0,0 +1,331 @@ +/**************************************************************************** + * + * pfrtypes.h + * + * FreeType PFR data structures (specification only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PFRTYPES_H_ +#define PFRTYPES_H_ + +#include + +FT_BEGIN_HEADER + + /************************************************************************/ + + /* the PFR Header structure */ + typedef struct PFR_HeaderRec_ + { + FT_UInt32 signature; + FT_UInt version; + FT_UInt signature2; + FT_UInt header_size; + + FT_UInt log_dir_size; + FT_UInt log_dir_offset; + + FT_UInt log_font_max_size; + FT_UInt32 log_font_section_size; + FT_UInt32 log_font_section_offset; + + FT_UInt32 phy_font_max_size; + FT_UInt32 phy_font_section_size; + FT_UInt32 phy_font_section_offset; + + FT_UInt gps_max_size; + FT_UInt32 gps_section_size; + FT_UInt32 gps_section_offset; + + FT_UInt max_blue_values; + FT_UInt max_x_orus; + FT_UInt max_y_orus; + + FT_UInt phy_font_max_size_high; + FT_UInt color_flags; + + FT_UInt32 bct_max_size; + FT_UInt32 bct_set_max_size; + FT_UInt32 phy_bct_set_max_size; + + FT_UInt num_phy_fonts; + FT_UInt max_vert_stem_snap; + FT_UInt max_horz_stem_snap; + FT_UInt max_chars; + + } PFR_HeaderRec, *PFR_Header; + + + /* used in `color_flags' field of the PFR_Header */ +#define PFR_FLAG_BLACK_PIXEL 0x01U +#define PFR_FLAG_INVERT_BITMAP 0x02U + + + /************************************************************************/ + + typedef struct PFR_LogFontRec_ + { + FT_UInt32 size; + FT_UInt32 offset; + + FT_Int32 matrix[4]; + FT_UInt stroke_flags; + FT_Int stroke_thickness; + FT_Int bold_thickness; + FT_Int32 miter_limit; + + FT_UInt32 phys_size; + FT_UInt32 phys_offset; + + } PFR_LogFontRec, *PFR_LogFont; + + +#define PFR_LINE_JOIN_MITER 0x00U +#define PFR_LINE_JOIN_ROUND 0x01U +#define PFR_LINE_JOIN_BEVEL 0x02U +#define PFR_LINE_JOIN_MASK ( PFR_LINE_JOIN_ROUND | PFR_LINE_JOIN_BEVEL ) + +#define PFR_LOG_STROKE 0x04U +#define PFR_LOG_2BYTE_STROKE 0x08U +#define PFR_LOG_BOLD 0x10U +#define PFR_LOG_2BYTE_BOLD 0x20U +#define PFR_LOG_EXTRA_ITEMS 0x40U + + + /************************************************************************/ + +#define PFR_BITMAP_2BYTE_CHARCODE 0x01U +#define PFR_BITMAP_2BYTE_SIZE 0x02U +#define PFR_BITMAP_3BYTE_OFFSET 0x04U + + /* not part of the specification but used for implementation */ +#define PFR_BITMAP_CHARCODES_VALIDATED 0x40U +#define PFR_BITMAP_VALID_CHARCODES 0x80U + + + typedef struct PFR_BitmapCharRec_ + { + FT_UInt char_code; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_BitmapCharRec, *PFR_BitmapChar; + + +#define PFR_STRIKE_2BYTE_XPPM 0x01U +#define PFR_STRIKE_2BYTE_YPPM 0x02U +#define PFR_STRIKE_3BYTE_SIZE 0x04U +#define PFR_STRIKE_3BYTE_OFFSET 0x08U +#define PFR_STRIKE_2BYTE_COUNT 0x10U + + + typedef struct PFR_StrikeRec_ + { + FT_UInt x_ppm; + FT_UInt y_ppm; + FT_UInt flags; + + FT_UInt32 gps_size; + FT_UInt32 gps_offset; + + FT_UInt32 bct_size; + FT_UInt32 bct_offset; + + /* optional */ + FT_UInt num_bitmaps; + PFR_BitmapChar bitmaps; + + } PFR_StrikeRec, *PFR_Strike; + + + /************************************************************************/ + + typedef struct PFR_CharRec_ + { + FT_UInt char_code; + FT_Int advance; + FT_UInt gps_size; + FT_UInt32 gps_offset; + + } PFR_CharRec, *PFR_Char; + + + /************************************************************************/ + + typedef struct PFR_DimensionRec_ + { + FT_UInt standard; + FT_UInt num_stem_snaps; + FT_Int* stem_snaps; + + } PFR_DimensionRec, *PFR_Dimension; + + /************************************************************************/ + + typedef struct PFR_KernItemRec_* PFR_KernItem; + + typedef struct PFR_KernItemRec_ + { + PFR_KernItem next; + FT_Byte pair_count; + FT_Byte flags; + FT_Short base_adj; + FT_UInt pair_size; + FT_Offset offset; + FT_UInt32 pair1; + FT_UInt32 pair2; + + } PFR_KernItemRec; + + +#define PFR_KERN_INDEX( g1, g2 ) \ + ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) ) + +#define PFR_KERN_PAIR_INDEX( pair ) \ + PFR_KERN_INDEX( (pair)->glyph1, (pair)->glyph2 ) + +#define PFR_NEXT_KPAIR( p ) ( p += 2, \ + ( (FT_UInt32)p[-2] << 16 ) | p[-1] ) + + + /************************************************************************/ + + typedef struct PFR_PhyFontRec_ + { + FT_Memory memory; + FT_UInt32 offset; + + FT_UInt font_ref_number; + FT_UInt outline_resolution; + FT_UInt metrics_resolution; + FT_BBox bbox; + FT_UInt flags; + FT_Int standard_advance; + + FT_Int ascent; /* optional, bbox.yMax if not present */ + FT_Int descent; /* optional, bbox.yMin if not present */ + FT_Int leading; /* optional, 0 if not present */ + + PFR_DimensionRec horizontal; + PFR_DimensionRec vertical; + + FT_String* font_id; + FT_String* family_name; + FT_String* style_name; + + FT_UInt num_strikes; + FT_UInt max_strikes; + PFR_StrikeRec* strikes; + + FT_UInt num_blue_values; + FT_Int *blue_values; + FT_UInt blue_fuzz; + FT_UInt blue_scale; + + FT_UInt num_chars; + FT_Offset chars_offset; + PFR_Char chars; + + FT_UInt num_kern_pairs; + PFR_KernItem kern_items; + PFR_KernItem* kern_items_tail; + + /* not part of the spec, but used during load */ + FT_ULong bct_offset; + FT_Byte* cursor; + + } PFR_PhyFontRec, *PFR_PhyFont; + + +#define PFR_PHY_VERTICAL 0x01U +#define PFR_PHY_2BYTE_CHARCODE 0x02U +#define PFR_PHY_PROPORTIONAL 0x04U +#define PFR_PHY_ASCII_CODE 0x08U +#define PFR_PHY_2BYTE_GPS_SIZE 0x10U +#define PFR_PHY_3BYTE_GPS_OFFSET 0x20U +#define PFR_PHY_EXTRA_ITEMS 0x80U + + +#define PFR_KERN_2BYTE_CHAR 0x01U +#define PFR_KERN_2BYTE_ADJ 0x02U + + + /************************************************************************/ + +#define PFR_GLYPH_YCOUNT 0x01U +#define PFR_GLYPH_XCOUNT 0x02U +#define PFR_GLYPH_1BYTE_XYCOUNT 0x04U + +#define PFR_GLYPH_SINGLE_EXTRA_ITEMS 0x08U +#define PFR_GLYPH_COMPOUND_EXTRA_ITEMS 0x40U + +#define PFR_GLYPH_IS_COMPOUND 0x80U + + + /* controlled coordinate */ + typedef struct PFR_CoordRec_ + { + FT_UInt org; + FT_UInt cur; + + } PFR_CoordRec, *PFR_Coord; + + + typedef struct PFR_SubGlyphRec_ + { + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Int x_delta; + FT_Int y_delta; + FT_UInt32 gps_offset; + FT_UInt gps_size; + + } PFR_SubGlyphRec, *PFR_SubGlyph; + + +#define PFR_SUBGLYPH_XSCALE 0x10U +#define PFR_SUBGLYPH_YSCALE 0x20U +#define PFR_SUBGLYPH_2BYTE_SIZE 0x40U +#define PFR_SUBGLYPH_3BYTE_OFFSET 0x80U + + + typedef struct PFR_GlyphRec_ + { + FT_Byte format; + +#if 0 + FT_UInt num_x_control; + FT_UInt num_y_control; +#endif + FT_UInt max_xy_control; + FT_Pos* x_control; + FT_Pos* y_control; + + + FT_UInt num_subs; + FT_UInt max_subs; + PFR_SubGlyphRec* subs; + + FT_GlyphLoader loader; + FT_Bool path_begun; + + } PFR_GlyphRec, *PFR_Glyph; + + +FT_END_HEADER + +#endif /* PFRTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/afmparse.c b/Dependencies/freetype/freetype/src/psaux/afmparse.c new file mode 100644 index 00000000..e2f6a8e5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/afmparse.c @@ -0,0 +1,1094 @@ +/**************************************************************************** + * + * afmparse.c + * + * AFM parser (body). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include + +#ifndef T1_CONFIG_OPTION_NO_AFM + +#include "afmparse.h" +#include "psconv.h" + +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afmparse + + + /************************************************************************** + * + * AFM_Stream + * + * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. + * + */ + + enum + { + AFM_STREAM_STATUS_NORMAL, + AFM_STREAM_STATUS_EOC, + AFM_STREAM_STATUS_EOL, + AFM_STREAM_STATUS_EOF + }; + + + typedef struct AFM_StreamRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + FT_Int status; + + } AFM_StreamRec; + + +#ifndef EOF +#define EOF -1 +#endif + + + /* this works because empty lines are ignored */ +#define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' ) + +#define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' ) +#define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) + + /* column separator; there is no `column' in the spec actually */ +#define AFM_IS_SEP( ch ) ( (ch) == ';' ) + +#define AFM_GETC() \ + ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ + : EOF ) + +#define AFM_STREAM_KEY_BEGIN( stream ) \ + (char*)( (stream)->cursor - 1 ) + +#define AFM_STREAM_KEY_LEN( stream, key ) \ + (FT_Offset)( (char*)(stream)->cursor - key - 1 ) + +#define AFM_STATUS_EOC( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOC ) + +#define AFM_STATUS_EOL( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOL ) + +#define AFM_STATUS_EOF( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOF ) + + + static int + afm_stream_skip_spaces( AFM_Stream stream ) + { + int ch = 0; /* make stupid compiler happy */ + + + if ( AFM_STATUS_EOC( stream ) ) + return ';'; + + while ( 1 ) + { + ch = AFM_GETC(); + if ( !AFM_IS_SPACE( ch ) ) + break; + } + + if ( AFM_IS_NEWLINE( ch ) ) + stream->status = AFM_STREAM_STATUS_EOL; + else if ( AFM_IS_SEP( ch ) ) + stream->status = AFM_STREAM_STATUS_EOC; + else if ( AFM_IS_EOF( ch ) ) + stream->status = AFM_STREAM_STATUS_EOF; + + return ch; + } + + + /* read a key or value in current column */ + static char* + afm_stream_read_one( AFM_Stream stream ) + { + char* str; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOC( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + while ( 1 ) + { + int ch = AFM_GETC(); + + + if ( AFM_IS_SPACE( ch ) ) + break; + else if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_SEP( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOC; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /* read a string (i.e., read to EOL) */ + static char* + afm_stream_read_string( AFM_Stream stream ) + { + char* str; + + + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOL( stream ) ) + return NULL; + + str = AFM_STREAM_KEY_BEGIN( stream ); + + /* scan to eol */ + while ( 1 ) + { + int ch = AFM_GETC(); + + + if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + + return str; + } + + + /************************************************************************** + * + * AFM_Parser + * + */ + + /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */ + typedef enum AFM_Token_ + { + AFM_TOKEN_ASCENDER, + AFM_TOKEN_AXISLABEL, + AFM_TOKEN_AXISTYPE, + AFM_TOKEN_B, + AFM_TOKEN_BLENDAXISTYPES, + AFM_TOKEN_BLENDDESIGNMAP, + AFM_TOKEN_BLENDDESIGNPOSITIONS, + AFM_TOKEN_C, + AFM_TOKEN_CC, + AFM_TOKEN_CH, + AFM_TOKEN_CAPHEIGHT, + AFM_TOKEN_CHARWIDTH, + AFM_TOKEN_CHARACTERSET, + AFM_TOKEN_CHARACTERS, + AFM_TOKEN_DESCENDER, + AFM_TOKEN_ENCODINGSCHEME, + AFM_TOKEN_ENDAXIS, + AFM_TOKEN_ENDCHARMETRICS, + AFM_TOKEN_ENDCOMPOSITES, + AFM_TOKEN_ENDDIRECTION, + AFM_TOKEN_ENDFONTMETRICS, + AFM_TOKEN_ENDKERNDATA, + AFM_TOKEN_ENDKERNPAIRS, + AFM_TOKEN_ENDTRACKKERN, + AFM_TOKEN_ESCCHAR, + AFM_TOKEN_FAMILYNAME, + AFM_TOKEN_FONTBBOX, + AFM_TOKEN_FONTNAME, + AFM_TOKEN_FULLNAME, + AFM_TOKEN_ISBASEFONT, + AFM_TOKEN_ISCIDFONT, + AFM_TOKEN_ISFIXEDPITCH, + AFM_TOKEN_ISFIXEDV, + AFM_TOKEN_ITALICANGLE, + AFM_TOKEN_KP, + AFM_TOKEN_KPH, + AFM_TOKEN_KPX, + AFM_TOKEN_KPY, + AFM_TOKEN_L, + AFM_TOKEN_MAPPINGSCHEME, + AFM_TOKEN_METRICSSETS, + AFM_TOKEN_N, + AFM_TOKEN_NOTICE, + AFM_TOKEN_PCC, + AFM_TOKEN_STARTAXIS, + AFM_TOKEN_STARTCHARMETRICS, + AFM_TOKEN_STARTCOMPOSITES, + AFM_TOKEN_STARTDIRECTION, + AFM_TOKEN_STARTFONTMETRICS, + AFM_TOKEN_STARTKERNDATA, + AFM_TOKEN_STARTKERNPAIRS, + AFM_TOKEN_STARTKERNPAIRS0, + AFM_TOKEN_STARTKERNPAIRS1, + AFM_TOKEN_STARTTRACKKERN, + AFM_TOKEN_STDHW, + AFM_TOKEN_STDVW, + AFM_TOKEN_TRACKKERN, + AFM_TOKEN_UNDERLINEPOSITION, + AFM_TOKEN_UNDERLINETHICKNESS, + AFM_TOKEN_VV, + AFM_TOKEN_VVECTOR, + AFM_TOKEN_VERSION, + AFM_TOKEN_W, + AFM_TOKEN_W0, + AFM_TOKEN_W0X, + AFM_TOKEN_W0Y, + AFM_TOKEN_W1, + AFM_TOKEN_W1X, + AFM_TOKEN_W1Y, + AFM_TOKEN_WX, + AFM_TOKEN_WY, + AFM_TOKEN_WEIGHT, + AFM_TOKEN_WEIGHTVECTOR, + AFM_TOKEN_XHEIGHT, + N_AFM_TOKENS, + AFM_TOKEN_UNKNOWN + + } AFM_Token; + + + static const char* const afm_key_table[N_AFM_TOKENS] = + { + "Ascender", + "AxisLabel", + "AxisType", + "B", + "BlendAxisTypes", + "BlendDesignMap", + "BlendDesignPositions", + "C", + "CC", + "CH", + "CapHeight", + "CharWidth", + "CharacterSet", + "Characters", + "Descender", + "EncodingScheme", + "EndAxis", + "EndCharMetrics", + "EndComposites", + "EndDirection", + "EndFontMetrics", + "EndKernData", + "EndKernPairs", + "EndTrackKern", + "EscChar", + "FamilyName", + "FontBBox", + "FontName", + "FullName", + "IsBaseFont", + "IsCIDFont", + "IsFixedPitch", + "IsFixedV", + "ItalicAngle", + "KP", + "KPH", + "KPX", + "KPY", + "L", + "MappingScheme", + "MetricsSets", + "N", + "Notice", + "PCC", + "StartAxis", + "StartCharMetrics", + "StartComposites", + "StartDirection", + "StartFontMetrics", + "StartKernData", + "StartKernPairs", + "StartKernPairs0", + "StartKernPairs1", + "StartTrackKern", + "StdHW", + "StdVW", + "TrackKern", + "UnderlinePosition", + "UnderlineThickness", + "VV", + "VVector", + "Version", + "W", + "W0", + "W0X", + "W0Y", + "W1", + "W1X", + "W1Y", + "WX", + "WY", + "Weight", + "WeightVector", + "XHeight" + }; + + + /* + * `afm_parser_read_vals' and `afm_parser_next_key' provide + * high-level operations to an AFM_Stream. The rest of the + * parser functions should use them without accessing the + * AFM_Stream directly. + */ + + FT_LOCAL_DEF( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ) + { + AFM_Stream stream = parser->stream; + char* str; + FT_Int i; + + + if ( n > AFM_MAX_ARGUMENTS ) + return 0; + + for ( i = 0; i < n; i++ ) + { + FT_Offset len; + AFM_Value val = vals + i; + + + if ( val->type == AFM_VALUE_TYPE_STRING ) + str = afm_stream_read_string( stream ); + else + str = afm_stream_read_one( stream ); + + if ( !str ) + break; + + len = AFM_STREAM_KEY_LEN( stream, str ); + + switch ( val->type ) + { + case AFM_VALUE_TYPE_STRING: + case AFM_VALUE_TYPE_NAME: + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( !FT_QALLOC( val->u.s, len + 1 ) ) + { + ft_memcpy( val->u.s, str, len ); + val->u.s[len] = '\0'; + } + } + break; + + case AFM_VALUE_TYPE_FIXED: + val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len, 0 ); + break; + + case AFM_VALUE_TYPE_INTEGER: + val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len ); + break; + + case AFM_VALUE_TYPE_BOOL: + val->u.b = FT_BOOL( len == 4 && + !ft_strncmp( str, "true", 4 ) ); + break; + + case AFM_VALUE_TYPE_INDEX: + if ( parser->get_index ) + val->u.i = parser->get_index( str, len, parser->user_data ); + else + val->u.i = 0; + break; + } + } + + return i; + } + + + FT_LOCAL_DEF( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_Offset* len ) + { + AFM_Stream stream = parser->stream; + char* key = NULL; /* make stupid compiler happy */ + + + if ( line ) + { + while ( 1 ) + { + /* skip current line */ + if ( !AFM_STATUS_EOL( stream ) ) + afm_stream_read_string( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty line */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOL( stream ) ) + continue; + + break; + } + } + else + { + while ( 1 ) + { + /* skip current column */ + while ( !AFM_STATUS_EOC( stream ) ) + afm_stream_read_one( stream ); + + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); + + /* skip empty column */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOC( stream ) ) + continue; + + break; + } + } + + if ( len ) + *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key ) + : 0; + + return key; + } + + + static AFM_Token + afm_tokenize( const char* key, + FT_Offset len ) + { + int n; + + + for ( n = 0; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) == *key ) + { + for ( ; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) != *key ) + return AFM_TOKEN_UNKNOWN; + + if ( ft_strncmp( afm_key_table[n], key, len ) == 0 ) + return (AFM_Token) n; + } + } + } + + return AFM_TOKEN_UNKNOWN; + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ) + { + AFM_Stream stream = NULL; + FT_Error error; + + + if ( FT_NEW( stream ) ) + return error; + + stream->cursor = stream->base = base; + stream->limit = limit; + + /* don't skip the first line during the first call */ + stream->status = AFM_STREAM_STATUS_EOL; + + parser->memory = memory; + parser->stream = stream; + parser->FontInfo = NULL; + parser->get_index = NULL; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + afm_parser_done( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + + + FT_FREE( parser->stream ); + } + + + static FT_Error + afm_parser_read_int( AFM_Parser parser, + FT_Int* aint ) + { + AFM_ValueRec val; + + + val.type = AFM_VALUE_TYPE_INTEGER; + + if ( afm_parser_read_vals( parser, &val, 1 ) == 1 ) + { + *aint = val.u.i; + + return FT_Err_Ok; + } + else + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parse_track_kern( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; + AFM_TrackKern tk; + + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; + + + if ( afm_parser_read_int( parser, &tmp ) ) + goto Fail; + + if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" )); + goto Fail; + } + + fi->NumTrackKern = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n", + fi->NumTrackKern, + fi->NumTrackKern == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `TrackKern` */ + /* command is 20 characters (including the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 20 < + fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern:" + " number of track kern entries exceeds stream size\n" )); + goto Fail; + } + + if ( fi->NumTrackKern ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[5]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_TRACKKERN: + n++; + + if ( n >= (int)fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" )); + goto Fail; + } + + tk = fi->TrackKerns + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + shared_vals[4].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) + { + FT_ERROR(( "afm_parse_track_kern:" + " insufficient number of parameters for entry %d\n", + n )); + goto Fail; + } + + tk->degree = shared_vals[0].u.i; + tk->min_ptsize = shared_vals[1].u.f; + tk->min_kern = shared_vals[2].u.f; + tk->max_ptsize = shared_vals[3].u.f; + tk->max_kern = shared_vals[4].u.f; + + break; + + case AFM_TOKEN_ENDTRACKKERN: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumTrackKern ) + { + FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "y" : "ies" )); + fi->NumTrackKern = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n", + tmp, + tmp == 1 ? "y" : "ies" )); + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) + + + /* compare two kerning pairs */ + FT_COMPARE_DEF( int ) + afm_compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair kp1 = (AFM_KernPair)a; + AFM_KernPair kp2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 ); + FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 ); + + + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } + + + static FT_Error + afm_parse_kern_pairs( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; + AFM_KernPair kp; + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; + + + if ( afm_parser_read_int( parser, &tmp ) ) + goto Fail; + + if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" )); + goto Fail; + } + + fi->NumKernPair = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n", + fi->NumKernPair, + fi->NumKernPair == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `KP`, */ + /* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */ + /* the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 10 < + fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " number of kern pairs exceeds stream size\n" )); + goto Fail; + } + + if ( fi->NumKernPair ) + { + FT_Memory memory = parser->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + return error; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + switch ( token ) + { + case AFM_TOKEN_KP: + case AFM_TOKEN_KPX: + case AFM_TOKEN_KPY: + { + FT_Int r; + AFM_ValueRec shared_vals[4]; + + + n++; + + if ( n >= (int)fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" )); + goto Fail; + } + + kp = fi->KernPairs + n; + + shared_vals[0].type = AFM_VALUE_TYPE_INDEX; + shared_vals[1].type = AFM_VALUE_TYPE_INDEX; + shared_vals[2].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; + r = afm_parser_read_vals( parser, shared_vals, 4 ); + if ( r < 3 ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " insufficient number of parameters for entry %d\n", + n )); + goto Fail; + } + + /* index values can't be negative */ + kp->index1 = shared_vals[0].u.u; + kp->index2 = shared_vals[1].u.u; + if ( token == AFM_TOKEN_KPY ) + { + kp->x = 0; + kp->y = shared_vals[2].u.i; + } + else + { + kp->x = shared_vals[2].u.i; + kp->y = ( token == AFM_TOKEN_KP && r == 4 ) + ? shared_vals[3].u.i : 0; + } + } + break; + + case AFM_TOKEN_ENDKERNPAIRS: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumKernPair ) + { + FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "" : "s" )); + fi->NumKernPair = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n", + tmp, + tmp == 1 ? "" : "s" )); + + ft_qsort( fi->KernPairs, fi->NumKernPair, + sizeof ( AFM_KernPairRec ), + afm_compare_kern_pairs ); + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parse_kern_data( AFM_Parser parser ) + { + FT_Error error; + char* key; + FT_Offset len; + + int have_trackkern = 0; + int have_kernpairs = 0; + + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_STARTTRACKKERN: + if ( have_trackkern ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal track kern section\n" )); + goto Fail; + } + + error = afm_parse_track_kern( parser ); + if ( error ) + return error; + + have_trackkern = 1; + break; + + case AFM_TOKEN_STARTKERNPAIRS: + case AFM_TOKEN_STARTKERNPAIRS0: + if ( have_kernpairs ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal kern pair section\n" )); + goto Fail; + } + + error = afm_parse_kern_pairs( parser ); + if ( error ) + return error; + + have_kernpairs = 1; + break; + + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + return FT_Err_Ok; + + case AFM_TOKEN_UNKNOWN: + break; + + default: + goto Fail; + } + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + static FT_Error + afm_parser_skip_section( AFM_Parser parser, + FT_Int n, + AFM_Token end_section ) + { + char* key; + FT_Offset len; + + + while ( n-- > 0 ) + { + key = afm_parser_next_key( parser, 1, NULL ); + if ( !key ) + goto Fail; + } + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + + + if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS ) + return FT_Err_Ok; + } + + Fail: + return FT_THROW( Syntax_Error ); + } + + + FT_LOCAL_DEF( FT_Error ) + afm_parser_parse( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + AFM_FontInfo fi = parser->FontInfo; + FT_Error error = FT_ERR( Syntax_Error ); + char* key; + FT_Offset len; + FT_Int metrics_sets = 0; + + + if ( !fi ) + return FT_THROW( Invalid_Argument ); + + key = afm_parser_next_key( parser, 1, &len ); + if ( !key || len != 16 || + ft_strncmp( key, "StartFontMetrics", 16 ) != 0 ) + return FT_THROW( Unknown_File_Format ); + + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[4]; + + + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_METRICSSETS: + if ( afm_parser_read_int( parser, &metrics_sets ) ) + goto Fail; + + if ( metrics_sets != 0 && metrics_sets != 2 ) + { + error = FT_THROW( Unimplemented_Feature ); + + goto Fail; + } + break; + + case AFM_TOKEN_ISCIDFONT: + shared_vals[0].type = AFM_VALUE_TYPE_BOOL; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->IsCIDFont = shared_vals[0].u.b; + break; + + case AFM_TOKEN_FONTBBOX: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 ) + goto Fail; + + fi->FontBBox.xMin = shared_vals[0].u.f; + fi->FontBBox.yMin = shared_vals[1].u.f; + fi->FontBBox.xMax = shared_vals[2].u.f; + fi->FontBBox.yMax = shared_vals[3].u.f; + break; + + case AFM_TOKEN_ASCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Ascender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_DESCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + + fi->Descender = shared_vals[0].u.f; + break; + + case AFM_TOKEN_STARTCHARMETRICS: + { + FT_Int n = 0; + + + if ( afm_parser_read_int( parser, &n ) ) + goto Fail; + + error = afm_parser_skip_section( parser, n, + AFM_TOKEN_ENDCHARMETRICS ); + if ( error ) + return error; + } + break; + + case AFM_TOKEN_STARTKERNDATA: + error = afm_parse_kern_data( parser ); + if ( error ) + goto Fail; + /* we only support kern data, so ... */ + FALL_THROUGH; + + case AFM_TOKEN_ENDFONTMETRICS: + return FT_Err_Ok; + + default: + break; + } + } + + Fail: + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + fi->IsCIDFont = 0; + + return error; + } + +#else /* T1_CONFIG_OPTION_NO_AFM */ + + /* ANSI C doesn't like empty source files */ + typedef int afm_parse_dummy_; + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/afmparse.h b/Dependencies/freetype/freetype/src/psaux/afmparse.h new file mode 100644 index 00000000..b7766372 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/afmparse.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * + * afmparse.h + * + * AFM parser (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFMPARSE_H_ +#define AFMPARSE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + + + FT_LOCAL( void ) + afm_parser_done( AFM_Parser parser ); + + + FT_LOCAL( FT_Error ) + afm_parser_parse( AFM_Parser parser ); + + + enum AFM_ValueType_ + { + AFM_VALUE_TYPE_STRING, + AFM_VALUE_TYPE_NAME, + AFM_VALUE_TYPE_FIXED, /* real number */ + AFM_VALUE_TYPE_INTEGER, + AFM_VALUE_TYPE_BOOL, + AFM_VALUE_TYPE_INDEX /* glyph index */ + }; + + + typedef struct AFM_ValueRec_ + { + enum AFM_ValueType_ type; + union + { + char* s; + FT_Fixed f; + FT_Int i; + FT_UInt u; + FT_Bool b; + + } u; + + } AFM_ValueRec, *AFM_Value; + +#define AFM_MAX_ARGUMENTS 5 + + FT_LOCAL( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_Int n ); + + /* read the next key from the next line or column */ + FT_LOCAL( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_Offset* len ); + +FT_END_HEADER + +#endif /* AFMPARSE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/cffdecode.c b/Dependencies/freetype/freetype/src/psaux/cffdecode.c new file mode 100644 index 00000000..9556e11a --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/cffdecode.c @@ -0,0 +1,2411 @@ +/**************************************************************************** + * + * cffdecode.c + * + * PostScript CFF (Type 2) decoding routines (body). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "cffdecode.h" +#include "psobjs.h" + +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cffdecode + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + + typedef enum CFF_Operator_ + { + cff_op_unknown = 0, + + cff_op_rmoveto, + cff_op_hmoveto, + cff_op_vmoveto, + + cff_op_rlineto, + cff_op_hlineto, + cff_op_vlineto, + + cff_op_rrcurveto, + cff_op_hhcurveto, + cff_op_hvcurveto, + cff_op_rcurveline, + cff_op_rlinecurve, + cff_op_vhcurveto, + cff_op_vvcurveto, + + cff_op_flex, + cff_op_hflex, + cff_op_hflex1, + cff_op_flex1, + + cff_op_endchar, + + cff_op_hstem, + cff_op_vstem, + cff_op_hstemhm, + cff_op_vstemhm, + + cff_op_hintmask, + cff_op_cntrmask, + cff_op_dotsection, /* deprecated, acts as no-op */ + + cff_op_abs, + cff_op_add, + cff_op_sub, + cff_op_div, + cff_op_neg, + cff_op_random, + cff_op_mul, + cff_op_sqrt, + + cff_op_blend, + + cff_op_drop, + cff_op_exch, + cff_op_index, + cff_op_roll, + cff_op_dup, + + cff_op_put, + cff_op_get, + cff_op_store, + cff_op_load, + + cff_op_and, + cff_op_or, + cff_op_not, + cff_op_eq, + cff_op_ifelse, + + cff_op_callsubr, + cff_op_callgsubr, + cff_op_return, + + /* Type 1 opcodes: invalid but seen in real life */ + cff_op_hsbw, + cff_op_closepath, + cff_op_callothersubr, + cff_op_pop, + cff_op_seac, + cff_op_sbw, + cff_op_setcurrentpoint, + + /* do not remove */ + cff_op_max + + } CFF_Operator; + + +#define CFF_COUNT_CHECK_WIDTH 0x80 +#define CFF_COUNT_EXACT 0x40 +#define CFF_COUNT_CLEAR_STACK 0x20 + + /* count values which have the `CFF_COUNT_CHECK_WIDTH' flag set are */ + /* used for checking the width and requested numbers of arguments */ + /* only; they are set to zero afterwards */ + + /* the other two flags are informative only and unused currently */ + + static const FT_Byte cff_argument_counts[] = + { + 0, /* unknown */ + + 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */ + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + + 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + + 13, /* flex */ + 7, + 9, + 11, + + 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */ + + 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */ + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + + 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */ + 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */ + 0, /* dotsection */ + + 1, /* abs */ + 2, + 2, + 2, + 1, + 0, + 2, + 1, + + 1, /* blend */ + + 1, /* drop */ + 2, + 1, + 2, + 1, + + 2, /* put */ + 1, + 4, + 3, + + 2, /* and */ + 2, + 1, + 2, + 4, + + 1, /* callsubr */ + 1, + 0, + + 2, /* hsbw */ + 0, + 0, + 0, + 5, /* seac */ + 4, /* sbw */ + 2 /* setcurrentpoint */ + }; + + + static FT_Error + cff_operator_seac( CFF_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + CFF_Builder* builder = &decoder->builder; + FT_Int bchar_index, achar_index; + TT_Face face = decoder->builder.face; + FT_Vector left_bearing, advance; + FT_Byte* charstring; + FT_ULong charstring_len; + FT_Pos glyph_width; + + + if ( decoder->seac ) + { + FT_ERROR(( "cff_operator_seac: invalid nested seac\n" )); + return FT_THROW( Syntax_Error ); + } + + adx = ADD_LONG( adx, decoder->builder.left_bearing.x ); + ady = ADD_LONG( ady, decoder->builder.left_bearing.y ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Incremental fonts don't necessarily have valid charsets. */ + /* They use the character code, not the glyph index, in this case. */ + if ( face->root.internal->incremental_interface ) + { + bchar_index = bchar; + achar_index = achar; + } + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + CFF_Font cff = (CFF_Font)( face->extra.data ); + + + bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar ); + achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cff_operator_seac:" + " invalid seac character code arguments\n" )); + return FT_THROW( Syntax_Error ); + } + + /* If we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( builder->no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)( adx >> 16 ); + subg->arg2 = (FT_Int)( ady >> 16 ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + } + + FT_GlyphLoader_Prepare( builder->loader ); + + /* First load `bchar' in builder */ + error = decoder->get_glyph_callback( face, (FT_UInt)bchar_index, + &charstring, &charstring_len ); + if ( !error ) + { + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len, 0 ); + decoder->seac = FALSE; + + decoder->free_glyph_callback( face, &charstring, charstring_len ); + + if ( error ) + goto Exit; + } + + /* Save the left bearing, advance and glyph width of the base */ + /* character as they will be erased by the next load. */ + + left_bearing = builder->left_bearing; + advance = builder->advance; + glyph_width = decoder->glyph_width; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + + builder->pos_x = SUB_LONG( adx, asb ); + builder->pos_y = ady; + + /* Now load `achar' on top of the base outline. */ + error = decoder->get_glyph_callback( face, (FT_UInt)achar_index, + &charstring, &charstring_len ); + if ( !error ) + { + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len, 0 ); + decoder->seac = FALSE; + + decoder->free_glyph_callback( face, &charstring, charstring_len ); + + if ( error ) + goto Exit; + } + + /* Restore the left side bearing, advance and glyph width */ + /* of the base character. */ + builder->left_bearing = left_bearing; + builder->advance = advance; + decoder->glyph_width = glyph_width; + + builder->pos_x = 0; + builder->pos_y = 0; + + Exit: + return error; + } + +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRING PARSING *********/ + /********** *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * cff_compute_bias + * + * @Description: + * Computes the bias value in dependence of the number of glyph + * subroutines. + * + * @Input: + * in_charstring_type :: + * The `CharstringType' value of the top DICT + * dictionary. + * + * num_subrs :: + * The number of glyph subroutines. + * + * @Return: + * The bias value. + */ + static FT_Int + cff_compute_bias( FT_Int in_charstring_type, + FT_UInt num_subrs ) + { + FT_Int result; + + + if ( in_charstring_type == 1 ) + result = 0; + else if ( num_subrs < 1240 ) + result = 107; + else if ( num_subrs < 33900U ) + result = 1131; + else + result = 32768U; + + return result; + } + + + FT_LOCAL_DEF( FT_Int ) + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ) + { + FT_UInt n; + FT_UShort glyph_sid; + + FT_Service_CFFLoad cffload; + + + /* CID-keyed fonts don't have glyph names */ + if ( !cff->charset.sids ) + return -1; + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + +#if 0 + /* retrieve cffload from list of current modules */ + FT_Service_CFFLoad cffload; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, cffload, CFF_LOAD ); + if ( !cffload ) + { + FT_ERROR(( "cff_lookup_glyph_by_stdcharcode:" + " the `cffload' module is not available\n" )); + return FT_THROW( Unimplemented_Feature ); + } +#endif + + cffload = (FT_Service_CFFLoad)cff->cffload; + + /* Get code to SID mapping from `cff_standard_encoding'. */ + glyph_sid = cffload->get_standard_encoding( (FT_UInt)charcode ); + + for ( n = 0; n < cff->num_glyphs; n++ ) + { + if ( cff->charset.sids[n] == glyph_sid ) + return (FT_Int)n; + } + + return -1; + } + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + + /************************************************************************** + * + * @Function: + * cff_decoder_parse_charstrings + * + * @Description: + * Parses a given Type 2 charstrings program. + * + * @InOut: + * decoder :: + * The current Type 1 decoder. + * + * @Input: + * charstring_base :: + * The base of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * in_dict :: + * Set to 1 if function is called from top or + * private DICT (needed for Multiple Master CFFs). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ) + { + FT_Error error; + CFF_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CFF_Builder* builder = &decoder->builder; + FT_Pos x, y; + FT_Fixed* stack; + FT_Int charstring_type = + decoder->cff->top_font.font_dict.charstring_type; + FT_UShort num_designs = + decoder->cff->top_font.font_dict.num_designs; + FT_UShort num_axes = + decoder->cff->top_font.font_dict.num_axes; + + T2_Hints_Funcs hinter; + + + /* set default width */ + decoder->num_hints = 0; + decoder->read_width = 1; + + /* initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + stack = decoder->top; + + hinter = (T2_Hints_Funcs)builder->hints_funcs; + + builder->path_begun = 0; + + if ( !charstring_base ) + return FT_Err_Ok; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = FT_Err_Ok; + + x = builder->pos_x; + y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + /* now execute loop */ + while ( ip < limit ) + { + CFF_Operator op; + FT_Byte v; + + + /********************************************************************* + * + * Decode operator or operand + */ + v = *ip++; + if ( v >= 32 || v == 28 ) + { + FT_Int shift = 16; + FT_Int32 val; + + + /* this is an operand, push it on the stack */ + + /* if we use shifts, all computations are done with unsigned */ + /* values; the conversion to a signed value is the last step */ + if ( v == 28 ) + { + if ( ip + 1 >= limit ) + goto Syntax_Error; + val = (FT_Short)( ( (FT_UShort)ip[0] << 8 ) | ip[1] ); + ip += 2; + } + else if ( v < 247 ) + val = (FT_Int32)v - 139; + else if ( v < 251 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108; + } + else if ( v < 255 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108; + } + else + { + if ( ip + 3 >= limit ) + goto Syntax_Error; + val = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + if ( charstring_type == 2 ) + shift = 0; + } + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + + val = (FT_Int32)( (FT_UInt32)val << shift ); + *decoder->top++ = val; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( val & 0xFFFFL ) ) + FT_TRACE4(( " %hd", (FT_Short)( (FT_UInt32)val >> 16 ) )); + else + FT_TRACE4(( " %.5f", val / 65536.0 )); +#endif + + } + else + { + /* The specification says that normally arguments are to be taken */ + /* from the bottom of the stack. However, this seems not to be */ + /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */ + /* arguments similar to a PS interpreter. */ + + FT_Fixed* args = decoder->top; + FT_Int num_args = (FT_Int)( args - decoder->stack ); + FT_Int req_args; + + + /* find operator */ + op = cff_op_unknown; + + switch ( v ) + { + case 1: + op = cff_op_hstem; + break; + case 3: + op = cff_op_vstem; + break; + case 4: + op = cff_op_vmoveto; + break; + case 5: + op = cff_op_rlineto; + break; + case 6: + op = cff_op_hlineto; + break; + case 7: + op = cff_op_vlineto; + break; + case 8: + op = cff_op_rrcurveto; + break; + case 9: + op = cff_op_closepath; + break; + case 10: + op = cff_op_callsubr; + break; + case 11: + op = cff_op_return; + break; + case 12: + if ( ip >= limit ) + goto Syntax_Error; + v = *ip++; + + switch ( v ) + { + case 0: + op = cff_op_dotsection; + break; + case 1: /* this is actually the Type1 vstem3 operator */ + op = cff_op_vstem; + break; + case 2: /* this is actually the Type1 hstem3 operator */ + op = cff_op_hstem; + break; + case 3: + op = cff_op_and; + break; + case 4: + op = cff_op_or; + break; + case 5: + op = cff_op_not; + break; + case 6: + op = cff_op_seac; + break; + case 7: + op = cff_op_sbw; + break; + case 8: + op = cff_op_store; + break; + case 9: + op = cff_op_abs; + break; + case 10: + op = cff_op_add; + break; + case 11: + op = cff_op_sub; + break; + case 12: + op = cff_op_div; + break; + case 13: + op = cff_op_load; + break; + case 14: + op = cff_op_neg; + break; + case 15: + op = cff_op_eq; + break; + case 16: + op = cff_op_callothersubr; + break; + case 17: + op = cff_op_pop; + break; + case 18: + op = cff_op_drop; + break; + case 20: + op = cff_op_put; + break; + case 21: + op = cff_op_get; + break; + case 22: + op = cff_op_ifelse; + break; + case 23: + op = cff_op_random; + break; + case 24: + op = cff_op_mul; + break; + case 26: + op = cff_op_sqrt; + break; + case 27: + op = cff_op_dup; + break; + case 28: + op = cff_op_exch; + break; + case 29: + op = cff_op_index; + break; + case 30: + op = cff_op_roll; + break; + case 33: + op = cff_op_setcurrentpoint; + break; + case 34: + op = cff_op_hflex; + break; + case 35: + op = cff_op_flex; + break; + case 36: + op = cff_op_hflex1; + break; + case 37: + op = cff_op_flex1; + break; + default: + FT_TRACE4(( " unknown op (12, %d)\n", v )); + break; + } + break; + case 13: + op = cff_op_hsbw; + break; + case 14: + op = cff_op_endchar; + break; + case 16: + op = cff_op_blend; + break; + case 18: + op = cff_op_hstemhm; + break; + case 19: + op = cff_op_hintmask; + break; + case 20: + op = cff_op_cntrmask; + break; + case 21: + op = cff_op_rmoveto; + break; + case 22: + op = cff_op_hmoveto; + break; + case 23: + op = cff_op_vstemhm; + break; + case 24: + op = cff_op_rcurveline; + break; + case 25: + op = cff_op_rlinecurve; + break; + case 26: + op = cff_op_vvcurveto; + break; + case 27: + op = cff_op_hhcurveto; + break; + case 29: + op = cff_op_callgsubr; + break; + case 30: + op = cff_op_vhcurveto; + break; + case 31: + op = cff_op_hvcurveto; + break; + default: + FT_TRACE4(( " unknown op (%d)\n", v )); + break; + } + + if ( op == cff_op_unknown ) + continue; + + /* in Multiple Master CFFs, T2 charstrings can appear in */ + /* dictionaries, but some operators are prohibited */ + if ( in_dict ) + { + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_vmoveto: + case cff_op_rlineto: + case cff_op_hlineto: + case cff_op_vlineto: + case cff_op_rrcurveto: + case cff_op_hstemhm: + case cff_op_hintmask: + case cff_op_cntrmask: + case cff_op_rmoveto: + case cff_op_hmoveto: + case cff_op_vstemhm: + case cff_op_rcurveline: + case cff_op_rlinecurve: + case cff_op_vvcurveto: + case cff_op_hhcurveto: + case cff_op_vhcurveto: + case cff_op_hvcurveto: + case cff_op_hflex: + case cff_op_flex: + case cff_op_hflex1: + case cff_op_flex1: + case cff_op_callsubr: + case cff_op_callgsubr: + /* deprecated opcodes */ + case cff_op_dotsection: + /* invalid Type 1 opcodes */ + case cff_op_hsbw: + case cff_op_closepath: + case cff_op_callothersubr: + case cff_op_seac: + case cff_op_sbw: + case cff_op_setcurrentpoint: + goto MM_Error; + + default: + break; + } + } + + /* check arguments */ + req_args = cff_argument_counts[op]; + if ( req_args & CFF_COUNT_CHECK_WIDTH ) + { + if ( num_args > 0 && decoder->read_width ) + { + /* If `nominal_width' is non-zero, the number is really a */ + /* difference against `nominal_width'. Else, the number here */ + /* is truly a width, not a difference against `nominal_width'. */ + /* If the font does not set `nominal_width', then */ + /* `nominal_width' defaults to zero, and so we can set */ + /* `glyph_width' to `nominal_width' plus number on the stack */ + /* -- for either case. */ + + FT_Int set_width_ok; + + + switch ( op ) + { + case cff_op_hmoveto: + case cff_op_vmoveto: + set_width_ok = num_args & 2; + break; + + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + case cff_op_rmoveto: + case cff_op_hintmask: + case cff_op_cntrmask: + set_width_ok = num_args & 1; + break; + + case cff_op_endchar: + /* If there is a width specified for endchar, we either have */ + /* 1 argument or 5 arguments. We like to argue. */ + set_width_ok = in_dict + ? 0 + : ( ( num_args == 5 ) || ( num_args == 1 ) ); + break; + + default: + set_width_ok = 0; + break; + } + + if ( set_width_ok ) + { + decoder->glyph_width = decoder->nominal_width + + ( stack[0] >> 16 ); + + if ( decoder->width_only ) + { + /* we only want the advance width; stop here */ + break; + } + + /* Consumed an argument. */ + num_args--; + } + } + + decoder->read_width = 0; + req_args = 0; + } + + req_args &= 0x000F; + if ( num_args < req_args ) + goto Stack_Underflow; + args -= req_args; + num_args -= req_args; + + /* At this point, `args' points to the first argument of the */ + /* operand in case `req_args' isn't zero. Otherwise, we have */ + /* to adjust `args' manually. */ + + /* Note that we only pop arguments from the stack which we */ + /* really need and can digest so that we can continue in case */ + /* of superfluous stack elements. */ + + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + /* the number of arguments is always even here */ + FT_TRACE4(( "%s\n", + op == cff_op_hstem ? " hstem" : + ( op == cff_op_vstem ? " vstem" : + ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) )); + + if ( hinter ) + hinter->stems( hinter->hints, + ( op == cff_op_hstem || op == cff_op_hstemhm ), + num_args / 2, + args - ( num_args & ~1 ) ); + + decoder->num_hints += num_args / 2; + args = stack; + break; + + case cff_op_hintmask: + case cff_op_cntrmask: + FT_TRACE4(( "%s", op == cff_op_hintmask ? " hintmask" + : " cntrmask" )); + + /* implement vstem when needed -- */ + /* the specification doesn't say it, but this also works */ + /* with the 'cntrmask' operator */ + /* */ + if ( num_args > 0 ) + { + if ( hinter ) + hinter->stems( hinter->hints, + 0, + num_args / 2, + args - ( num_args & ~1 ) ); + + decoder->num_hints += num_args / 2; + } + + /* In a valid charstring there must be at least one byte */ + /* after `hintmask' or `cntrmask' (e.g., for a `return' */ + /* instruction). Additionally, there must be space for */ + /* `num_hints' bits. */ + + if ( ( ip + ( ( decoder->num_hints + 7 ) >> 3 ) ) >= limit ) + goto Syntax_Error; + + if ( hinter ) + { + if ( op == cff_op_hintmask ) + hinter->hintmask( hinter->hints, + (FT_UInt)builder->current->n_points, + (FT_UInt)decoder->num_hints, + ip ); + else + hinter->counter( hinter->hints, + (FT_UInt)decoder->num_hints, + ip ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt maskbyte; + + + FT_TRACE4(( " (maskbytes:" )); + + for ( maskbyte = 0; + maskbyte < (FT_UInt)( ( decoder->num_hints + 7 ) >> 3 ); + maskbyte++, ip++ ) + FT_TRACE4(( " 0x%02X", *ip )); + + FT_TRACE4(( ")\n" )); + } +#else + ip += ( decoder->num_hints + 7 ) >> 3; +#endif + args = stack; + break; + + case cff_op_rmoveto: + FT_TRACE4(( " rmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x = ADD_LONG( x, args[-2] ); + y = ADD_LONG( y, args[-1] ); + args = stack; + break; + + case cff_op_vmoveto: + FT_TRACE4(( " vmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + y = ADD_LONG( y, args[-1] ); + args = stack; + break; + + case cff_op_hmoveto: + FT_TRACE4(( " hmoveto\n" )); + + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x = ADD_LONG( x, args[-1] ); + args = stack; + break; + + case cff_op_rlineto: + FT_TRACE4(( " rlineto\n" )); + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_args / 2 ) ) + goto Fail; + + if ( num_args < 2 ) + goto Stack_Underflow; + + args -= num_args & ~1; + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + } + args = stack; + break; + + case cff_op_hlineto: + case cff_op_vlineto: + { + FT_Int phase = ( op == cff_op_hlineto ); + + + FT_TRACE4(( "%s\n", op == cff_op_hlineto ? " hlineto" + : " vlineto" )); + + if ( num_args < 0 ) + goto Stack_Underflow; + + /* there exist subsetted fonts (found in PDFs) */ + /* which call `hlineto' without arguments */ + if ( num_args == 0 ) + break; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_args ) ) + goto Fail; + + args = stack; + while ( args < decoder->top ) + { + if ( phase ) + x = ADD_LONG( x, args[0] ); + else + y = ADD_LONG( y, args[0] ); + + if ( cff_builder_add_point1( builder, x, y ) ) + goto Fail; + + args++; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rrcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " rrcurveto\n" )); + + if ( num_args < 6 ) + goto Stack_Underflow; + + nargs = num_args - num_args % 6; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, nargs / 2 ) ) + goto Fail; + + args -= nargs; + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 6; + } + args = stack; + } + break; + + case cff_op_vvcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " vvcurveto\n" )); + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + + if ( nargs & 1 ) + { + x = ADD_LONG( x, args[0] ); + args++; + nargs--; + } + + if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + y = ADD_LONG( y, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 4; + } + args = stack; + } + break; + + case cff_op_hhcurveto: + { + FT_Int nargs; + + + FT_TRACE4(( " hhcurveto\n" )); + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + if ( nargs & 1 ) + { + y = ADD_LONG( y, args[0] ); + args++; + nargs--; + } + + if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 4; + } + args = stack; + } + break; + + case cff_op_vhcurveto: + case cff_op_hvcurveto: + { + FT_Int phase; + FT_Int nargs; + + + FT_TRACE4(( "%s\n", op == cff_op_vhcurveto ? " vhcurveto" + : " hvcurveto" )); + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + if ( num_args < 4 ) + goto Stack_Underflow; + + /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */ + /* we enforce it by clearing the second bit */ + + nargs = num_args & ~2; + + args -= nargs; + if ( cff_check_points( builder, ( nargs / 4 ) * 3 ) ) + goto Stack_Underflow; + + phase = ( op == cff_op_hvcurveto ); + + while ( nargs >= 4 ) + { + nargs -= 4; + if ( phase ) + { + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, args[3] ); + if ( nargs == 1 ) + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + } + else + { + y = ADD_LONG( y, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[3] ); + if ( nargs == 1 ) + y = ADD_LONG( y, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + } + args += 4; + phase ^= 1; + } + args = stack; + } + break; + + case cff_op_rlinecurve: + { + FT_Int num_lines; + FT_Int nargs; + + + FT_TRACE4(( " rlinecurve\n" )); + + if ( num_args < 8 ) + goto Stack_Underflow; + + nargs = num_args & ~1; + num_lines = ( nargs - 6 ) / 2; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_lines + 3 ) ) + goto Fail; + + args -= nargs; + + /* first, add the line segments */ + while ( num_lines > 0 ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 2; + num_lines--; + } + + /* then the curve */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + } + break; + + case cff_op_rcurveline: + { + FT_Int num_curves; + FT_Int nargs; + + + FT_TRACE4(( " rcurveline\n" )); + + if ( num_args < 8 ) + goto Stack_Underflow; + + nargs = num_args - 2; + nargs = nargs - nargs % 6 + 2; + num_curves = ( nargs - 2 ) / 6; + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, num_curves * 3 + 2 ) ) + goto Fail; + + args -= nargs; + + /* first, add the curves */ + while ( num_curves > 0 ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, args[4] ); + y = ADD_LONG( y, args[5] ); + cff_builder_add_point( builder, x, y, 1 ); + + args += 6; + num_curves--; + } + + /* then the final line */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + } + break; + + case cff_op_hflex1: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex1\n" )); + + /* adding five more points: 4 control points, 1 on-curve point */ + /* -- make sure we have enough space for the start point if it */ + /* needs to be added */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's y position for later use */ + start_y = y; + + /* first control point */ + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x = ADD_LONG( x, args[2] ); + y = ADD_LONG( y, args[3] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x = ADD_LONG( x, args[5] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x = ADD_LONG( x, args[6] ); + y = ADD_LONG( y, args[7] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start */ + x = ADD_LONG( x, args[8] ); + y = start_y; + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_hflex: + { + FT_Pos start_y; + + + FT_TRACE4(( " hflex\n" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's y-position for later use */ + start_y = y; + + /* first control point */ + x = ADD_LONG( x, args[0] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* second control point */ + x = ADD_LONG( x, args[1] ); + y = ADD_LONG( y, args[2] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* join point; on curve, with y-value the same as the last */ + /* control point's y-value */ + x = ADD_LONG( x, args[3] ); + cff_builder_add_point( builder, x, y, 1 ); + + /* third control point, with y-value the same as the join */ + /* point's y-value */ + x = ADD_LONG( x, args[4] ); + cff_builder_add_point( builder, x, y, 0 ); + + /* fourth control point */ + x = ADD_LONG( x, args[5] ); + y = start_y; + cff_builder_add_point( builder, x, y, 0 ); + + /* ending point, with y-value the same as the start point's */ + /* y-value -- we don't add this point, though */ + x = ADD_LONG( x, args[6] ); + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex1: + { + FT_Pos start_x, start_y; /* record start x, y values for */ + /* alter use */ + FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */ + /* algorithm below */ + FT_Int horizontal, count; + FT_Fixed* temp; + + + FT_TRACE4(( " flex1\n" )); + + /* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + /* record the starting point's x, y position for later use */ + start_x = x; + start_y = y; + + /* XXX: figure out whether this is supposed to be a horizontal */ + /* or vertical flex; the Type 2 specification is vague... */ + + temp = args; + + /* grab up to the last argument */ + for ( count = 5; count > 0; count-- ) + { + dx = ADD_LONG( dx, temp[0] ); + dy = ADD_LONG( dy, temp[1] ); + temp += 2; + } + + if ( dx < 0 ) + dx = NEG_LONG( dx ); + if ( dy < 0 ) + dy = NEG_LONG( dy ); + + /* strange test, but here it is... */ + horizontal = ( dx > dy ); + + for ( count = 5; count > 0; count-- ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, + FT_BOOL( count == 3 ) ); + args += 2; + } + + /* is last operand an x- or y-delta? */ + if ( horizontal ) + { + x = ADD_LONG( x, args[0] ); + y = start_y; + } + else + { + x = start_x; + y = ADD_LONG( y, args[0] ); + } + + cff_builder_add_point( builder, x, y, 1 ); + + args = stack; + break; + } + + case cff_op_flex: + { + FT_UInt count; + + + FT_TRACE4(( " flex\n" )); + + if ( cff_builder_start_point( builder, x, y ) || + cff_check_points( builder, 6 ) ) + goto Fail; + + for ( count = 6; count > 0; count-- ) + { + x = ADD_LONG( x, args[0] ); + y = ADD_LONG( y, args[1] ); + cff_builder_add_point( builder, x, y, + FT_BOOL( count == 4 || count == 1 ) ); + args += 2; + } + + args = stack; + } + break; + + case cff_op_seac: + FT_TRACE4(( " seac\n" )); + + error = cff_operator_seac( decoder, + args[0], args[1], args[2], + (FT_Int)( args[3] >> 16 ), + (FT_Int)( args[4] >> 16 ) ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n" )); + return error; + + case cff_op_endchar: + /* in dictionaries, `endchar' simply indicates end of data */ + if ( in_dict ) + return error; + + FT_TRACE4(( " endchar\n" )); + + /* We are going to emulate the seac operator. */ + if ( num_args >= 4 ) + { + /* Save glyph width so that the subglyphs don't overwrite it. */ + FT_Pos glyph_width = decoder->glyph_width; + + + error = cff_operator_seac( decoder, + 0L, args[-4], args[-3], + (FT_Int)( args[-2] >> 16 ), + (FT_Int)( args[-1] >> 16 ) ); + + decoder->glyph_width = glyph_width; + } + else + { + cff_builder_close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + (FT_UInt)builder->current->n_points ) ) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + error = hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + if ( error ) + goto Fail; + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + } + + /* return now! */ + FT_TRACE4(( "\n" )); + return error; + + case cff_op_abs: + FT_TRACE4(( " abs\n" )); + + if ( args[0] < 0 ) + { + if ( args[0] == FT_LONG_MIN ) + args[0] = FT_LONG_MAX; + else + args[0] = -args[0]; + } + args++; + break; + + case cff_op_add: + FT_TRACE4(( " add\n" )); + + args[0] = ADD_LONG( args[0], args[1] ); + args++; + break; + + case cff_op_sub: + FT_TRACE4(( " sub\n" )); + + args[0] = SUB_LONG( args[0], args[1] ); + args++; + break; + + case cff_op_div: + FT_TRACE4(( " div\n" )); + + args[0] = FT_DivFix( args[0], args[1] ); + args++; + break; + + case cff_op_neg: + FT_TRACE4(( " neg\n" )); + + if ( args[0] == FT_LONG_MIN ) + args[0] = FT_LONG_MAX; + args[0] = -args[0]; + args++; + break; + + case cff_op_random: + { + FT_UInt32* randval = in_dict ? &decoder->cff->top_font.random + : &decoder->current_subfont->random; + + + FT_TRACE4(( " random\n" )); + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + args[0] = (FT_Fixed)( ( *randval & 0xFFFF ) + 1 ); + args++; + + *randval = cff_random( *randval ); + } + break; + + case cff_op_mul: + FT_TRACE4(( " mul\n" )); + + args[0] = FT_MulFix( args[0], args[1] ); + args++; + break; + + case cff_op_sqrt: + FT_TRACE4(( " sqrt\n" )); + + /* without upper limit the loop below might not finish */ + if ( args[0] > 0x7FFFFFFFL ) + args[0] = 0xB504F4L; /* sqrt( 32768.0044 ) */ + else if ( args[0] > 0 ) + args[0] = (FT_Fixed)FT_SqrtFixed( args[0] ); + else + args[0] = 0; + args++; + break; + + case cff_op_drop: + /* nothing */ + FT_TRACE4(( " drop\n" )); + + break; + + case cff_op_exch: + { + FT_Fixed tmp; + + + FT_TRACE4(( " exch\n" )); + + tmp = args[0]; + args[0] = args[1]; + args[1] = tmp; + args += 2; + } + break; + + case cff_op_index: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " index\n" )); + + if ( idx < 0 ) + idx = 0; + else if ( idx > num_args - 2 ) + idx = num_args - 2; + args[0] = args[-( idx + 1 )]; + args++; + } + break; + + case cff_op_roll: + { + FT_Int count = (FT_Int)( args[0] >> 16 ); + FT_Int idx = (FT_Int)( args[1] >> 16 ); + + + FT_TRACE4(( " roll\n" )); + + if ( count <= 0 ) + count = 1; + + args -= count; + if ( args < stack ) + goto Stack_Underflow; + + if ( idx >= 0 ) + { + idx = idx % count; + while ( idx > 0 ) + { + FT_Fixed tmp = args[count - 1]; + FT_Int i; + + + for ( i = count - 2; i >= 0; i-- ) + args[i + 1] = args[i]; + args[0] = tmp; + idx--; + } + } + else + { + /* before C99 it is implementation-defined whether */ + /* the result of `%' is negative if the first operand */ + /* is negative */ + idx = -( NEG_INT( idx ) % count ); + while ( idx < 0 ) + { + FT_Fixed tmp = args[0]; + FT_Int i; + + + for ( i = 0; i < count - 1; i++ ) + args[i] = args[i + 1]; + args[count - 1] = tmp; + idx++; + } + } + args += count; + } + break; + + case cff_op_dup: + FT_TRACE4(( " dup\n" )); + + args[1] = args[0]; + args += 2; + break; + + case cff_op_put: + { + FT_Fixed val = args[0]; + FT_UInt idx = (FT_UInt)( args[1] >> 16 ); + + + FT_TRACE4(( " put\n" )); + + /* the Type2 specification before version 16-March-2000 */ + /* didn't give a hard-coded size limit of the temporary */ + /* storage array; instead, an argument of the */ + /* `MultipleMaster' operator set the size */ + if ( idx < CFF_MAX_TRANS_ELEMENTS ) + decoder->buildchar[idx] = val; + } + break; + + case cff_op_get: + { + FT_UInt idx = (FT_UInt)( args[0] >> 16 ); + FT_Fixed val = 0; + + + FT_TRACE4(( " get\n" )); + + if ( idx < CFF_MAX_TRANS_ELEMENTS ) + val = decoder->buildchar[idx]; + + args[0] = val; + args++; + } + break; + + case cff_op_store: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, this is a no-op */ + FT_TRACE4(( " store\n" )); + break; + + case cff_op_load: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + { + FT_UInt reg_idx = (FT_UInt)args[0]; + FT_UInt idx = (FT_UInt)args[1]; + FT_UInt count = (FT_UInt)args[2]; + + + FT_TRACE4(( " load\n" )); + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, we store a vector [1 0 0 ...] in the */ + /* temporary storage array regardless of the Registry index */ + if ( reg_idx <= 2 && + idx < CFF_MAX_TRANS_ELEMENTS && + count <= num_axes ) + { + FT_UInt end, i; + + + end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS ); + + if ( idx < end ) + decoder->buildchar[idx] = 1 << 16; + + for ( i = idx + 1; i < end; i++ ) + decoder->buildchar[i] = 0; + } + } + break; + + case cff_op_blend: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + if ( num_designs ) + { + FT_Int num_results = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " blend\n" )); + + if ( num_results < 0 ) + goto Syntax_Error; + + if ( num_results > num_args || + num_results * (FT_Int)num_designs > num_args ) + goto Stack_Underflow; + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, return the `num_results' values of the */ + /* first master */ + args -= num_results * ( num_designs - 1 ); + num_args -= num_results * ( num_designs - 1 ); + } + else + goto Syntax_Error; + break; + + case cff_op_dotsection: + /* this operator is deprecated and ignored by the parser */ + FT_TRACE4(( " dotsection\n" )); + break; + + case cff_op_closepath: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " closepath (invalid op)\n" )); + + args = stack; + break; + + case cff_op_hsbw: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " hsbw (invalid op)\n" )); + + decoder->glyph_width = + ADD_LONG( decoder->nominal_width, ( args[1] >> 16 ) ); + + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = 0; + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = decoder->builder.pos_y; + args = stack; + break; + + case cff_op_sbw: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " sbw (invalid op)\n" )); + + decoder->glyph_width = + ADD_LONG( decoder->nominal_width, ( args[2] >> 16 ) ); + + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = args[1]; + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = ADD_LONG( decoder->builder.pos_y, args[1] ); + args = stack; + break; + + case cff_op_setcurrentpoint: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " setcurrentpoint (invalid op)\n" )); + + x = ADD_LONG( decoder->builder.pos_x, args[0] ); + y = ADD_LONG( decoder->builder.pos_y, args[1] ); + args = stack; + break; + + case cff_op_callothersubr: + { + FT_Fixed arg; + + + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from */ + /* probably Type 1 to CFF, and some parsers seem to accept */ + /* it */ + + FT_TRACE4(( " callothersubr (invalid op)\n" )); + + /* subsequent `pop' operands should add the arguments, */ + /* this is the implementation described for `unknown' */ + /* other subroutines in the Type1 spec. */ + /* */ + /* XXX Fix return arguments (see discussion below). */ + + arg = 2 + ( args[-2] >> 16 ); + if ( arg >= CFF_MAX_OPERANDS ) + goto Stack_Underflow; + + args -= arg; + if ( args < stack ) + goto Stack_Underflow; + } + break; + + case cff_op_pop: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " pop (invalid op)\n" )); + + /* XXX Increasing `args' is wrong: After a certain number of */ + /* `pop's we get a stack overflow. Reason for doing it is */ + /* code like this (actually found in a CFF font): */ + /* */ + /* 17 1 3 callothersubr */ + /* pop */ + /* callsubr */ + /* */ + /* Since we handle `callothersubr' as a no-op, and */ + /* `callsubr' needs at least one argument, `pop' can't be a */ + /* no-op too as it basically should be. */ + /* */ + /* The right solution would be to provide real support for */ + /* `callothersubr' as done in `t1decode.c', however, given */ + /* the fact that CFF fonts with `pop' are invalid, it is */ + /* questionable whether it is worth the time. */ + args++; + break; + + case cff_op_and: + { + FT_Fixed cond = ( args[0] && args[1] ); + + + FT_TRACE4(( " and\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_or: + { + FT_Fixed cond = ( args[0] || args[1] ); + + + FT_TRACE4(( " or\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_not: + { + FT_Fixed cond = !args[0]; + + + FT_TRACE4(( " not\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_eq: + { + FT_Fixed cond = ( args[0] == args[1] ); + + + FT_TRACE4(( " eq\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_ifelse: + { + FT_Fixed cond = ( args[2] <= args[3] ); + + + FT_TRACE4(( " ifelse\n" )); + + if ( !cond ) + args[0] = args[1]; + args++; + } + break; + + case cff_op_callsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->locals_bias ); + + + FT_TRACE4(( " callsubr (idx %d, entering level %td)\n", + idx, + zone - decoder->zones + 1 )); + + if ( idx >= decoder->num_locals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid local subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->locals[idx]; + zone->limit = decoder->locals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_callgsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->globals_bias ); + + + FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n", + idx, + zone - decoder->zones + 1 )); + + if ( idx >= decoder->num_globals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid global subr index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->globals[idx]; + zone->limit = decoder->globals[idx + 1]; + zone->cursor = zone->base; + + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + + case cff_op_return: + FT_TRACE4(( " return (leaving level %td)\n", + decoder->zone - decoder->zones )); + + if ( decoder->zone <= decoder->zones ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + + decoder->zone--; + zone = decoder->zone; + ip = zone->cursor; + limit = zone->limit; + break; + + default: + FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); + + if ( ip[-1] == 12 ) + FT_ERROR(( " %d", ip[0] )); + FT_ERROR(( "\n" )); + + return FT_THROW( Unimplemented_Feature ); + } + + decoder->top = args; + + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + Fail: + return error; + + MM_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings:" + " invalid opcode found in top DICT charstring\n")); + return FT_THROW( Invalid_File_Format ); + + Syntax_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" )); + return FT_THROW( Invalid_File_Format ); + + Stack_Underflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" )); + return FT_THROW( Too_Few_Arguments ); + + Stack_Overflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" )); + return FT_THROW( Stack_Overflow ); + } + +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ + + + /************************************************************************** + * + * @Function: + * cff_decoder_init + * + * @Description: + * Initializes a given glyph decoder. + * + * @InOut: + * decoder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * slot :: + * The current glyph object. + * + * hinting :: + * Whether hinting is active. + * + * hint_mode :: + * The hinting mode. + */ + FT_LOCAL_DEF( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + + + /* clear everything */ + FT_ZERO( decoder ); + + /* initialize builder */ + cff_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* initialize Type2 decoder */ + decoder->cff = cff; + decoder->num_globals = cff->global_subrs_index.count; + decoder->globals = cff->global_subrs; + decoder->globals_bias = cff_compute_bias( + cff->top_font.font_dict.charstring_type, + decoder->num_globals ); + + decoder->hint_mode = hint_mode; + + decoder->get_glyph_callback = get_callback; + decoder->free_glyph_callback = free_callback; + } + + + /* this function is used to select the subfont */ + /* and the locals subrs array */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ) + { + CFF_Builder *builder = &decoder->builder; + CFF_Font cff = (CFF_Font)builder->face->extra.data; + CFF_SubFont sub = &cff->top_font; + FT_Error error = FT_Err_Ok; + + FT_Service_CFFLoad cffload = (FT_Service_CFFLoad)cff->cffload; + + + /* manage CID fonts */ + if ( cff->num_subfonts ) + { + FT_Byte fd_index = cffload->fd_select_get( &cff->fd_select, + glyph_index ); + + + if ( fd_index >= cff->num_subfonts ) + { + FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE3(( " in subfont %d:\n", fd_index )); + + sub = cff->subfonts[fd_index]; + + if ( builder->hints_funcs && size ) + { + FT_Size ftsize = FT_SIZE( size ); + CFF_Internal internal = (CFF_Internal)ftsize->internal->module_data; + + + /* for CFFs without subfonts, this value has already been set */ + builder->hints_globals = (void *)internal->subfonts[fd_index]; + } + } + + decoder->num_locals = sub->local_subrs_index.count; + decoder->locals = sub->local_subrs; + decoder->locals_bias = cff_compute_bias( + decoder->cff->top_font.font_dict.charstring_type, + decoder->num_locals ); + + decoder->glyph_width = sub->private_dict.default_width; + decoder->nominal_width = sub->private_dict.nominal_width; + + decoder->current_subfont = sub; + + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/cffdecode.h b/Dependencies/freetype/freetype/src/psaux/cffdecode.h new file mode 100644 index 00000000..038f7235 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/cffdecode.h @@ -0,0 +1,63 @@ +/**************************************************************************** + * + * cffdecode.h + * + * PostScript CFF (Type 2) decoding routines (specification). + * + * Copyright (C) 2017-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef CFFDECODE_H_ +#define CFFDECODE_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + cff_decoder_init( CFF_Decoder* decoder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot slot, + FT_Bool hinting, + FT_Render_Mode hint_mode, + CFF_Decoder_Get_Glyph_Callback get_callback, + CFF_Decoder_Free_Glyph_Callback free_callback ); + + FT_LOCAL( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ); + + + FT_LOCAL( FT_Int ) + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ); + + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + FT_LOCAL( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len, + FT_Bool in_dict ); +#endif + + +FT_END_HEADER + +#endif + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psarrst.c b/Dependencies/freetype/freetype/src/psaux/psarrst.c new file mode 100644 index 00000000..70313d28 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psarrst.c @@ -0,0 +1,240 @@ +/**************************************************************************** + * + * psarrst.c + * + * Adobe's code for Array Stacks (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psarrst.h" + +#include "pserror.h" + + + /* + * CF2_ArrStack uses an error pointer, to enable shared errors. + * Shared errors are necessary when multiple objects allow the program + * to continue after detecting errors. Only the first error should be + * recorded. + */ + + FT_LOCAL_DEF( void ) + cf2_arrstack_init( CF2_ArrStack arrstack, + FT_Memory memory, + FT_Error* error, + size_t sizeItem ) + { + FT_ASSERT( arrstack ); + + /* initialize the structure */ + arrstack->memory = memory; + arrstack->error = error; + arrstack->sizeItem = sizeItem; + arrstack->allocated = 0; + arrstack->count = 0; + arrstack->totalSize = 0; + arrstack->ptr = NULL; + } + + + FT_LOCAL_DEF( void ) + cf2_arrstack_finalize( CF2_ArrStack arrstack ) + { + FT_Memory memory = arrstack->memory; /* for FT_FREE */ + + + FT_ASSERT( arrstack ); + + arrstack->allocated = 0; + arrstack->count = 0; + arrstack->totalSize = 0; + + /* free the data buffer */ + FT_FREE( arrstack->ptr ); + } + + + /* allocate or reallocate the buffer size; */ + /* return false on memory error */ + static FT_Bool + cf2_arrstack_setNumElements( CF2_ArrStack arrstack, + size_t numElements ) + { + FT_ASSERT( arrstack ); + + { + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + FT_Memory memory = arrstack->memory; /* for FT_REALLOC */ + + size_t newSize = numElements * arrstack->sizeItem; + + + if ( numElements > FT_LONG_MAX / arrstack->sizeItem ) + goto exit; + + + FT_ASSERT( newSize > 0 ); /* avoid realloc with zero size */ + + if ( !FT_QREALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) + { + arrstack->allocated = numElements; + arrstack->totalSize = newSize; + + if ( arrstack->count > numElements ) + { + /* we truncated the list! */ + CF2_SET_ERROR( arrstack->error, Stack_Overflow ); + arrstack->count = numElements; + return FALSE; + } + + return TRUE; /* success */ + } + } + + exit: + /* if there's not already an error, store this one */ + CF2_SET_ERROR( arrstack->error, Out_Of_Memory ); + + return FALSE; + } + + + /* set the count, ensuring allocation is sufficient */ + FT_LOCAL_DEF( void ) + cf2_arrstack_setCount( CF2_ArrStack arrstack, + size_t numElements ) + { + FT_ASSERT( arrstack ); + + if ( numElements > arrstack->allocated ) + { + /* expand the allocation first */ + if ( !cf2_arrstack_setNumElements( arrstack, numElements ) ) + return; + } + + arrstack->count = numElements; + } + + + /* clear the count */ + FT_LOCAL_DEF( void ) + cf2_arrstack_clear( CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + arrstack->count = 0; + } + + + /* current number of items */ + FT_LOCAL_DEF( size_t ) + cf2_arrstack_size( const CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + return arrstack->count; + } + + + FT_LOCAL_DEF( void* ) + cf2_arrstack_getBuffer( const CF2_ArrStack arrstack ) + { + FT_ASSERT( arrstack ); + + return arrstack->ptr; + } + + + /* return pointer to the given element */ + FT_LOCAL_DEF( void* ) + cf2_arrstack_getPointer( const CF2_ArrStack arrstack, + size_t idx ) + { + void* newPtr; + + + FT_ASSERT( arrstack ); + + if ( idx >= arrstack->count ) + { + /* overflow */ + CF2_SET_ERROR( arrstack->error, Stack_Overflow ); + idx = 0; /* choose safe default */ + } + + newPtr = (FT_Byte*)arrstack->ptr + idx * arrstack->sizeItem; + + return newPtr; + } + + + /* push (append) an element at the end of the list; */ + /* return false on memory error */ + /* TODO: should there be a length param for extra checking? */ + FT_LOCAL_DEF( void ) + cf2_arrstack_push( CF2_ArrStack arrstack, + const void* ptr ) + { + FT_ASSERT( arrstack ); + + if ( arrstack->count == arrstack->allocated ) + { + /* increase the buffer size */ + if ( !cf2_arrstack_setNumElements( + arrstack, arrstack->allocated * 2 + 16 ) ) + { + /* on error, ignore the push */ + return; + } + } + + FT_ASSERT( ptr ); + + { + size_t offset = arrstack->count * arrstack->sizeItem; + void* newPtr = (FT_Byte*)arrstack->ptr + offset; + + + FT_MEM_COPY( newPtr, ptr, arrstack->sizeItem ); + arrstack->count += 1; + } + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psarrst.h b/Dependencies/freetype/freetype/src/psaux/psarrst.h new file mode 100644 index 00000000..31e5330c --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psarrst.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * + * psarrst.h + * + * Adobe's code for Array Stacks (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSARRST_H_ +#define PSARRST_H_ + + +#include "pserror.h" + + +FT_BEGIN_HEADER + + + /* need to define the struct here (not opaque) so it can be allocated by */ + /* clients */ + typedef struct CF2_ArrStackRec_ + { + FT_Memory memory; + FT_Error* error; + + size_t sizeItem; /* bytes per element */ + size_t allocated; /* items allocated */ + size_t count; /* number of elements allocated */ + size_t totalSize; /* total bytes allocated */ + + void* ptr; /* ptr to data */ + + } CF2_ArrStackRec, *CF2_ArrStack; + + + FT_LOCAL( void ) + cf2_arrstack_init( CF2_ArrStack arrstack, + FT_Memory memory, + FT_Error* error, + size_t sizeItem ); + FT_LOCAL( void ) + cf2_arrstack_finalize( CF2_ArrStack arrstack ); + + FT_LOCAL( void ) + cf2_arrstack_setCount( CF2_ArrStack arrstack, + size_t numElements ); + FT_LOCAL( void ) + cf2_arrstack_clear( CF2_ArrStack arrstack ); + FT_LOCAL( size_t ) + cf2_arrstack_size( const CF2_ArrStack arrstack ); + + FT_LOCAL( void* ) + cf2_arrstack_getBuffer( const CF2_ArrStack arrstack ); + FT_LOCAL( void* ) + cf2_arrstack_getPointer( const CF2_ArrStack arrstack, + size_t idx ); + + FT_LOCAL( void ) + cf2_arrstack_push( CF2_ArrStack arrstack, + const void* ptr ); + + +FT_END_HEADER + + +#endif /* PSARRST_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psaux.c b/Dependencies/freetype/freetype/src/psaux/psaux.c new file mode 100644 index 00000000..ffe89cd6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psaux.c @@ -0,0 +1,40 @@ +/**************************************************************************** + * + * psaux.c + * + * FreeType auxiliary PostScript driver component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "afmparse.c" +#include "psauxmod.c" +#include "psconv.c" +#include "psobjs.c" +#include "t1cmap.c" +#include "t1decode.c" +#include "cffdecode.c" + +#include "psarrst.c" +#include "psblues.c" +#include "pserror.c" +#include "psfont.c" +#include "psft.c" +#include "pshints.c" +#include "psintrp.c" +#include "psread.c" +#include "psstack.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psauxerr.h b/Dependencies/freetype/freetype/src/psaux/psauxerr.h new file mode 100644 index 00000000..18428c40 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psauxerr.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * psauxerr.h + * + * PS auxiliary module error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PS auxiliary module error enumeration + * constants. + * + */ + +#ifndef PSAUXERR_H_ +#define PSAUXERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSaux_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSaux + +#include + +#endif /* PSAUXERR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psauxmod.c b/Dependencies/freetype/freetype/src/psaux/psauxmod.c new file mode 100644 index 00000000..6826f9d8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psauxmod.c @@ -0,0 +1,190 @@ +/**************************************************************************** + * + * psauxmod.c + * + * FreeType auxiliary PostScript module implementation (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "psauxmod.h" +#include "psobjs.h" +#include "t1decode.h" +#include "t1cmap.h" +#include "psft.h" +#include "cffdecode.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "afmparse.h" +#endif + + + FT_CALLBACK_TABLE_DEF + const PS_Table_FuncsRec ps_table_funcs = + { + ps_table_new, /* init */ + ps_table_done, /* done */ + ps_table_add, /* add */ + ps_table_release /* release */ + }; + + + FT_CALLBACK_TABLE_DEF + const PS_Parser_FuncsRec ps_parser_funcs = + { + ps_parser_init, /* init */ + ps_parser_done, /* done */ + + ps_parser_skip_spaces, /* skip_spaces */ + ps_parser_skip_PS_token, /* skip_PS_token */ + + ps_parser_to_int, /* to_int */ + ps_parser_to_fixed, /* to_fixed */ + ps_parser_to_bytes, /* to_bytes */ + ps_parser_to_coord_array, /* to_coord_array */ + ps_parser_to_fixed_array, /* to_fixed_array */ + ps_parser_to_token, /* to_token */ + ps_parser_to_token_array, /* to_token_array */ + + ps_parser_load_field, /* load_field */ + ps_parser_load_field_table /* load_field_table */ + }; + + + FT_CALLBACK_TABLE_DEF + const PS_Builder_FuncsRec ps_builder_funcs = + { + ps_builder_init, /* init */ + ps_builder_done /* done */ + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Builder_FuncsRec t1_builder_funcs = + { + t1_builder_init, /* init */ + t1_builder_done, /* done */ + + t1_builder_check_points, /* check_points */ + t1_builder_add_point, /* add_point */ + t1_builder_add_point1, /* add_point1 */ + t1_builder_add_contour, /* add_contour */ + t1_builder_start_point, /* start_point */ + t1_builder_close_contour /* close_contour */ + }; + + + FT_CALLBACK_TABLE_DEF + const T1_Decoder_FuncsRec t1_decoder_funcs = + { + t1_decoder_init, /* init */ + t1_decoder_done, /* done */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + t1_decoder_parse_charstrings, /* parse_charstrings_old */ +#else + t1_decoder_parse_metrics, /* parse_metrics */ +#endif + cf2_decoder_parse_charstrings /* parse_charstrings */ + }; + + +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE_DEF + const AFM_Parser_FuncsRec afm_parser_funcs = + { + afm_parser_init, /* init */ + afm_parser_done, /* done */ + afm_parser_parse /* parse */ + }; +#endif + + + FT_CALLBACK_TABLE_DEF + const T1_CMap_ClassesRec t1_cmap_classes = + { + &t1_cmap_standard_class_rec, + &t1_cmap_expert_class_rec, + &t1_cmap_custom_class_rec, + &t1_cmap_unicode_class_rec + }; + + + FT_CALLBACK_TABLE_DEF + const CFF_Builder_FuncsRec cff_builder_funcs = + { + cff_builder_init, /* init */ + cff_builder_done, /* done */ + + cff_check_points, /* check_points */ + cff_builder_add_point, /* add_point */ + cff_builder_add_point1, /* add_point1 */ + cff_builder_add_contour, /* add_contour */ + cff_builder_start_point, /* start_point */ + cff_builder_close_contour /* close_contour */ + }; + + + FT_CALLBACK_TABLE_DEF + const CFF_Decoder_FuncsRec cff_decoder_funcs = + { + cff_decoder_init, /* init */ + cff_decoder_prepare, /* prepare */ + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + cff_decoder_parse_charstrings, /* parse_charstrings_old */ +#endif + cf2_decoder_parse_charstrings /* parse_charstrings */ + }; + + + static + const PSAux_Interface psaux_interface = + { + &ps_table_funcs, + &ps_parser_funcs, + &t1_builder_funcs, + &t1_decoder_funcs, + t1_decrypt, + cff_random, + ps_decoder_init, + t1_make_subfont, + + (const T1_CMap_ClassesRec*) &t1_cmap_classes, + +#ifndef T1_CONFIG_OPTION_NO_AFM + &afm_parser_funcs, +#else + 0, +#endif + + &cff_decoder_funcs, + }; + + + FT_DEFINE_MODULE( + psaux_module_class, + + 0, + sizeof ( FT_ModuleRec ), + "psaux", + 0x20000L, + 0x20000L, + + &psaux_interface, /* module-specific interface */ + + (FT_Module_Constructor)NULL, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) NULL /* get_interface */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psauxmod.h b/Dependencies/freetype/freetype/src/psaux/psauxmod.h new file mode 100644 index 00000000..82d7e348 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psauxmod.h @@ -0,0 +1,60 @@ +/**************************************************************************** + * + * psauxmod.h + * + * FreeType auxiliary PostScript module implementation (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSAUXMOD_H_ +#define PSAUXMOD_H_ + + +#include + +#include + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const CFF_Builder_FuncsRec cff_builder_funcs; + + FT_CALLBACK_TABLE + const PS_Builder_FuncsRec ps_builder_funcs; + +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE + const AFM_Parser_FuncsRec afm_parser_funcs; +#endif + + FT_CALLBACK_TABLE + const T1_CMap_ClassesRec t1_cmap_classes; + + FT_CALLBACK_TABLE + const CFF_Decoder_FuncsRec cff_decoder_funcs; + + + FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; + + + FT_DECLARE_MODULE( psaux_module_class ) + + +FT_END_HEADER + +#endif /* PSAUXMOD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psblues.c b/Dependencies/freetype/freetype/src/psaux/psblues.c new file mode 100644 index 00000000..213b943b --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psblues.c @@ -0,0 +1,571 @@ +/**************************************************************************** + * + * psblues.c + * + * Adobe's code for handling Blue Zones (body). + * + * Copyright 2009-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psblues.h" +#include "pshints.h" +#include "psfont.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2blues + + + FT_LOCAL_DEF( void ) + cf2_blues_init( CF2_Blues blues, + CF2_Font font ) + { + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + CF2_Fixed zoneHeight; + CF2_Fixed maxZoneHeight = 0; + CF2_Fixed csUnitsPerPixel; + + size_t numBlueValues; + size_t numOtherBlues; + size_t numFamilyBlues; + size_t numFamilyOtherBlues; + + FT_Fixed* blueValues; + FT_Fixed* otherBlues; + FT_Fixed* familyBlues; + FT_Fixed* familyOtherBlues; + + size_t i; + CF2_Fixed emBoxBottom, emBoxTop; + +#if 0 + CF2_Int unitsPerEm = font->unitsPerEm; + + + if ( unitsPerEm == 0 ) + unitsPerEm = 1000; +#endif + + FT_ZERO( blues ); + blues->scale = font->innerTransform.d; + + cf2_getBlueMetrics( decoder, + &blues->blueScale, + &blues->blueShift, + &blues->blueFuzz ); + + cf2_getBlueValues( decoder, &numBlueValues, &blueValues ); + cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues ); + cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues ); + cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues ); + + /* + * synthetic em box hint heuristic + * + * Apply this when ideographic dictionary (LanguageGroup 1) has no + * real alignment zones. Adobe tools generate dummy zones at -250 and + * 1100 for a 1000 unit em. Fonts with ICF-based alignment zones + * should not enable the heuristic. When the heuristic is enabled, + * the font's blue zones are ignored. + * + */ + + /* get em box from OS/2 typoAscender/Descender */ + /* TODO: FreeType does not parse these metrics. Skip them for now. */ +#if 0 + FCM_getHorizontalLineMetrics( &e, + font->font, + &ascender, + &descender, + &linegap ); + if ( ascender - descender == unitsPerEm ) + { + emBoxBottom = cf2_intToFixed( descender ); + emBoxTop = cf2_intToFixed( ascender ); + } + else +#endif + { + emBoxBottom = CF2_ICF_Bottom; + emBoxTop = CF2_ICF_Top; + } + + if ( cf2_getLanguageGroup( decoder ) == 1 && + ( numBlueValues == 0 || + ( numBlueValues == 4 && + blueValues[0] < emBoxBottom && + blueValues[1] < emBoxBottom && + blueValues[2] > emBoxTop && + blueValues[3] > emBoxTop ) ) ) + { + /* + * Construct hint edges suitable for synthetic ghost hints at top + * and bottom of em box. +-CF2_MIN_COUNTER allows for unhinted + * features above or below the last hinted edge. This also gives a + * net 1 pixel boost to the height of ideographic glyphs. + * + * Note: Adjust synthetic hints outward by epsilon (0x.0001) to + * avoid interference. E.g., some fonts have real hints at + * 880 and -120. + */ + + blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON; + blues->emBoxBottomEdge.dsCoord = cf2_fixedRound( + FT_MulFix( + blues->emBoxBottomEdge.csCoord, + blues->scale ) ) - + CF2_MIN_COUNTER; + blues->emBoxBottomEdge.scale = blues->scale; + blues->emBoxBottomEdge.flags = CF2_GhostBottom | + CF2_Locked | + CF2_Synthetic; + + blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON + + 2 * font->darkenY; + blues->emBoxTopEdge.dsCoord = cf2_fixedRound( + FT_MulFix( + blues->emBoxTopEdge.csCoord, + blues->scale ) ) + + CF2_MIN_COUNTER; + blues->emBoxTopEdge.scale = blues->scale; + blues->emBoxTopEdge.flags = CF2_GhostTop | + CF2_Locked | + CF2_Synthetic; + + blues->doEmBoxHints = TRUE; /* enable the heuristic */ + + return; + } + + /* copy `BlueValues' and `OtherBlues' to a combined array of top and */ + /* bottom zones */ + for ( i = 0; i < numBlueValues; i += 2 ) + { + blues->zone[blues->count].csBottomEdge = blueValues[i]; + blues->zone[blues->count].csTopEdge = blueValues[i + 1]; + + zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, + blues->zone[blues->count].csBottomEdge ); + + if ( zoneHeight < 0 ) + { + FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); + continue; /* reject this zone */ + } + + if ( zoneHeight > maxZoneHeight ) + { + /* take maximum before darkening adjustment */ + /* so overshoot suppression point doesn't change */ + maxZoneHeight = zoneHeight; + } + + /* adjust both edges of top zone upward by twice darkening amount */ + if ( i != 0 ) + { + blues->zone[blues->count].csTopEdge += 2 * font->darkenY; + blues->zone[blues->count].csBottomEdge += 2 * font->darkenY; + } + + /* first `BlueValue' is bottom zone; others are top */ + if ( i == 0 ) + { + blues->zone[blues->count].bottomZone = + TRUE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csTopEdge; + } + else + { + blues->zone[blues->count].bottomZone = + FALSE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csBottomEdge; + } + + blues->count += 1; + } + + for ( i = 0; i < numOtherBlues; i += 2 ) + { + blues->zone[blues->count].csBottomEdge = otherBlues[i]; + blues->zone[blues->count].csTopEdge = otherBlues[i + 1]; + + zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, + blues->zone[blues->count].csBottomEdge ); + + if ( zoneHeight < 0 ) + { + FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); + continue; /* reject this zone */ + } + + if ( zoneHeight > maxZoneHeight ) + { + /* take maximum before darkening adjustment */ + /* so overshoot suppression point doesn't change */ + maxZoneHeight = zoneHeight; + } + + /* Note: bottom zones are not adjusted for darkening amount */ + + /* all OtherBlues are bottom zone */ + blues->zone[blues->count].bottomZone = + TRUE; + blues->zone[blues->count].csFlatEdge = + blues->zone[blues->count].csTopEdge; + + blues->count += 1; + } + + /* Adjust for FamilyBlues */ + + /* Search for the nearest flat edge in `FamilyBlues' or */ + /* `FamilyOtherBlues'. According to the Black Book, any matching edge */ + /* must be within one device pixel */ + + csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale ); + + /* loop on all zones in this font */ + for ( i = 0; i < blues->count; i++ ) + { + size_t j; + CF2_Fixed minDiff; + CF2_Fixed flatFamilyEdge, diff; + /* value for this font */ + CF2_Fixed flatEdge = blues->zone[i].csFlatEdge; + + + if ( blues->zone[i].bottomZone ) + { + /* In a bottom zone, the top edge is the flat edge. */ + /* Search `FamilyOtherBlues' for bottom zones; look for closest */ + /* Family edge that is within the one pixel threshold. */ + + minDiff = CF2_FIXED_MAX; + + for ( j = 0; j < numFamilyOtherBlues; j += 2 ) + { + /* top edge */ + flatFamilyEdge = familyOtherBlues[j + 1]; + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + { + blues->zone[i].csFlatEdge = flatFamilyEdge; + minDiff = diff; + + if ( diff == 0 ) + break; + } + } + + /* check the first member of FamilyBlues, which is a bottom zone */ + if ( numFamilyBlues >= 2 ) + { + /* top edge */ + flatFamilyEdge = familyBlues[1]; + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + blues->zone[i].csFlatEdge = flatFamilyEdge; + } + } + else + { + /* In a top zone, the bottom edge is the flat edge. */ + /* Search `FamilyBlues' for top zones; skip first zone, which is a */ + /* bottom zone; look for closest Family edge that is within the */ + /* one pixel threshold */ + + minDiff = CF2_FIXED_MAX; + + for ( j = 2; j < numFamilyBlues; j += 2 ) + { + /* bottom edge */ + flatFamilyEdge = familyBlues[j]; + + /* adjust edges of top zone upward by twice darkening amount */ + flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ + + diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); + + if ( diff < minDiff && diff < csUnitsPerPixel ) + { + blues->zone[i].csFlatEdge = flatFamilyEdge; + minDiff = diff; + + if ( diff == 0 ) + break; + } + } + } + } + + /* TODO: enforce separation of zones, including BlueFuzz */ + + /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */ + /* `bcsetup.c'. */ + + if ( maxZoneHeight > 0 ) + { + if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ), + maxZoneHeight ) ) + { + /* clamp at maximum scale */ + blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ), + maxZoneHeight ); + } + + /* + * TODO: Revisit the bug fix for 613448. The minimum scale + * requirement catches a number of library fonts. For + * example, with default BlueScale (.039625) and 0.4 minimum, + * the test below catches any font with maxZoneHeight < 10.1. + * There are library fonts ranging from 2 to 10 that get + * caught, including e.g., Eurostile LT Std Medium with + * maxZoneHeight of 6. + * + */ +#if 0 + if ( blueScale < .4 / maxZoneHeight ) + { + tetraphilia_assert( 0 ); + /* clamp at minimum scale, per bug 0613448 fix */ + blueScale = .4 / maxZoneHeight; + } +#endif + + } + + /* + * Suppress overshoot and boost blue zones at small sizes. Boost + * amount varies linearly from 0.5 pixel near 0 to 0 pixel at + * blueScale cutoff. + * Note: This boost amount is different from the coretype heuristic. + * + */ + + if ( blues->scale < blues->blueScale ) + { + blues->suppressOvershoot = TRUE; + + /* Change rounding threshold for `dsFlatEdge'. */ + /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */ + /* 10ppem Arial */ + + blues->boost = cf2_doubleToFixed( .6 ) - + FT_MulDiv( cf2_doubleToFixed ( .6 ), + blues->scale, + blues->blueScale ); + if ( blues->boost > 0x7FFF ) + { + /* boost must remain less than 0.5, or baseline could go negative */ + blues->boost = 0x7FFF; + } + } + + /* boost and darkening have similar effects; don't do both */ + if ( font->stemDarkened ) + blues->boost = 0; + + /* set device space alignment for each zone; */ + /* apply boost amount before rounding flat edge */ + + for ( i = 0; i < blues->count; i++ ) + { + if ( blues->zone[i].bottomZone ) + blues->zone[i].dsFlatEdge = cf2_fixedRound( + FT_MulFix( + blues->zone[i].csFlatEdge, + blues->scale ) - + blues->boost ); + else + blues->zone[i].dsFlatEdge = cf2_fixedRound( + FT_MulFix( + blues->zone[i].csFlatEdge, + blues->scale ) + + blues->boost ); + } + } + + + /* + * Check whether `stemHint' is captured by one of the blue zones. + * + * Zero, one or both edges may be valid; only valid edges can be + * captured. For compatibility with CoolType, search top and bottom + * zones in the same pass (see `BlueLock'). If a hint is captured, + * return true and position the edge(s) in one of 3 ways: + * + * 1) If `BlueScale' suppresses overshoot, position the captured edge + * at the flat edge of the zone. + * 2) If overshoot is not suppressed and `BlueShift' requires + * overshoot, position the captured edge a minimum of 1 device pixel + * from the flat edge. + * 3) If overshoot is not suppressed or required, position the captured + * edge at the nearest device pixel. + * + */ + FT_LOCAL_DEF( FT_Bool ) + cf2_blues_capture( const CF2_Blues blues, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ) + { + /* TODO: validate? */ + CF2_Fixed csFuzz = blues->blueFuzz; + + /* new position of captured edge */ + CF2_Fixed dsNew; + + /* amount that hint is moved when positioned */ + CF2_Fixed dsMove = 0; + + FT_Bool captured = FALSE; + CF2_UInt i; + + + /* assert edge flags are consistent */ + FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) && + !cf2_hint_isBottom( topHintEdge ) ); + + /* TODO: search once without blue fuzz for compatibility with coretype? */ + for ( i = 0; i < blues->count; i++ ) + { + if ( blues->zone[i].bottomZone && + cf2_hint_isBottom( bottomHintEdge ) ) + { + if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <= + bottomHintEdge->csCoord && + bottomHintEdge->csCoord <= + ADD_INT32( blues->zone[i].csTopEdge, csFuzz ) ) + { + /* bottom edge captured by bottom zone */ + + if ( blues->suppressOvershoot ) + dsNew = blues->zone[i].dsFlatEdge; + + else if ( SUB_INT32( blues->zone[i].csTopEdge, + bottomHintEdge->csCoord ) >= + blues->blueShift ) + { + /* guarantee minimum of 1 pixel overshoot */ + dsNew = FT_MIN( + cf2_fixedRound( bottomHintEdge->dsCoord ), + SUB_INT32( blues->zone[i].dsFlatEdge, + cf2_intToFixed( 1 ) ) ); + } + + else + { + /* simply round captured edge */ + dsNew = cf2_fixedRound( bottomHintEdge->dsCoord ); + } + + dsMove = SUB_INT32( dsNew, bottomHintEdge->dsCoord ); + captured = TRUE; + + break; + } + } + + if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) ) + { + if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <= + topHintEdge->csCoord && + topHintEdge->csCoord <= + ADD_INT32( blues->zone[i].csTopEdge, csFuzz ) ) + { + /* top edge captured by top zone */ + + if ( blues->suppressOvershoot ) + dsNew = blues->zone[i].dsFlatEdge; + + else if ( SUB_INT32( topHintEdge->csCoord, + blues->zone[i].csBottomEdge ) >= + blues->blueShift ) + { + /* guarantee minimum of 1 pixel overshoot */ + dsNew = FT_MAX( + cf2_fixedRound( topHintEdge->dsCoord ), + blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) ); + } + + else + { + /* simply round captured edge */ + dsNew = cf2_fixedRound( topHintEdge->dsCoord ); + } + + dsMove = SUB_INT32( dsNew, topHintEdge->dsCoord ); + captured = TRUE; + + break; + } + } + } + + if ( captured ) + { + /* move both edges and flag them `locked' */ + if ( cf2_hint_isValid( bottomHintEdge ) ) + { + bottomHintEdge->dsCoord = ADD_INT32( bottomHintEdge->dsCoord, + dsMove ); + cf2_hint_lock( bottomHintEdge ); + } + + if ( cf2_hint_isValid( topHintEdge ) ) + { + topHintEdge->dsCoord = ADD_INT32( topHintEdge->dsCoord, dsMove ); + cf2_hint_lock( topHintEdge ); + } + } + + return captured; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psblues.h b/Dependencies/freetype/freetype/src/psaux/psblues.h new file mode 100644 index 00000000..55fb88ec --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psblues.h @@ -0,0 +1,185 @@ +/**************************************************************************** + * + * psblues.h + * + * Adobe's code for handling Blue Zones (specification). + * + * Copyright 2009-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + + /* + * A `CF2_Blues' object stores the blue zones (horizontal alignment + * zones) of a font. These are specified in the CFF private dictionary + * by `BlueValues', `OtherBlues', `FamilyBlues', and `FamilyOtherBlues'. + * Each zone is defined by a top and bottom edge in character space. + * Further, each zone is either a top zone or a bottom zone, as recorded + * by `bottomZone'. + * + * The maximum number of `BlueValues' and `FamilyBlues' is 7 each. + * However, these are combined to produce a total of 7 zones. + * Similarly, the maximum number of `OtherBlues' and `FamilyOtherBlues' + * is 5 and these are combined to produce an additional 5 zones. + * + * Blue zones are used to `capture' hints and force them to a common + * alignment point. This alignment is recorded in device space in + * `dsFlatEdge'. Except for this value, a `CF2_Blues' object could be + * constructed independently of scaling. Construction may occur once + * the matrix is known. Other features implemented in the Capture + * method are overshoot suppression, overshoot enforcement, and Blue + * Boost. + * + * Capture is determined by `BlueValues' and `OtherBlues', but the + * alignment point may be adjusted to the scaled flat edge of + * `FamilyBlues' or `FamilyOtherBlues'. No alignment is done to the + * curved edge of a zone. + * + */ + + +#ifndef PSBLUES_H_ +#define PSBLUES_H_ + + +#include "psglue.h" + + +FT_BEGIN_HEADER + + + /* + * `CF2_Hint' is shared by `cf2hints.h' and + * `cf2blues.h', but `cf2blues.h' depends on + * `cf2hints.h', so define it here. Note: The typedef is in + * `cf2glue.h'. + * + */ + enum + { + CF2_GhostBottom = 0x1, /* a single bottom edge */ + CF2_GhostTop = 0x2, /* a single top edge */ + CF2_PairBottom = 0x4, /* the bottom edge of a stem hint */ + CF2_PairTop = 0x8, /* the top edge of a stem hint */ + CF2_Locked = 0x10, /* this edge has been aligned */ + /* by a blue zone */ + CF2_Synthetic = 0x20 /* this edge was synthesized */ + }; + + + /* + * Default value for OS/2 typoAscender/Descender when their difference + * is not equal to `unitsPerEm'. The default is based on -250 and 1100 + * in `CF2_Blues', assuming 1000 units per em here. + * + */ + enum + { + CF2_ICF_Top = cf2_intToFixed( 880 ), + CF2_ICF_Bottom = cf2_intToFixed( -120 ) + }; + + + /* + * Constant used for hint adjustment and for synthetic em box hint + * placement. + */ +#define CF2_MIN_COUNTER cf2_doubleToFixed( 0.5 ) + + + /* shared typedef is in cf2glue.h */ + struct CF2_HintRec_ + { + CF2_UInt flags; /* attributes of the edge */ + size_t index; /* index in original stem hint array */ + /* (if not synthetic) */ + CF2_Fixed csCoord; + CF2_Fixed dsCoord; + CF2_Fixed scale; + }; + + + typedef struct CF2_BlueRec_ + { + CF2_Fixed csBottomEdge; + CF2_Fixed csTopEdge; + CF2_Fixed csFlatEdge; /* may be from either local or Family zones */ + CF2_Fixed dsFlatEdge; /* top edge of bottom zone or bottom edge */ + /* of top zone (rounded) */ + FT_Bool bottomZone; + + } CF2_BlueRec; + + + /* max total blue zones is 12 */ + enum + { + CF2_MAX_BLUES = 7, + CF2_MAX_OTHERBLUES = 5 + }; + + + typedef struct CF2_BluesRec_ + { + CF2_Fixed scale; + CF2_UInt count; + FT_Bool suppressOvershoot; + FT_Bool doEmBoxHints; + + CF2_Fixed blueScale; + CF2_Fixed blueShift; + CF2_Fixed blueFuzz; + + CF2_Fixed boost; + + CF2_HintRec emBoxTopEdge; + CF2_HintRec emBoxBottomEdge; + + CF2_BlueRec zone[CF2_MAX_BLUES + CF2_MAX_OTHERBLUES]; + + } CF2_BluesRec, *CF2_Blues; + + + FT_LOCAL( void ) + cf2_blues_init( CF2_Blues blues, + CF2_Font font ); + FT_LOCAL( FT_Bool ) + cf2_blues_capture( const CF2_Blues blues, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ); + + +FT_END_HEADER + + +#endif /* PSBLUES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psconv.c b/Dependencies/freetype/freetype/src/psaux/psconv.c new file mode 100644 index 00000000..56c0ecd1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psconv.c @@ -0,0 +1,610 @@ +/**************************************************************************** + * + * psconv.c + * + * Some convenience conversions (body). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include + +#include "psconv.h" +#include "psauxerr.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psconv + + + /* The following array is used by various functions to quickly convert */ + /* digits (both decimal and non-decimal) into numbers. */ + +#if 'A' == 65 + /* ASCII */ + + static const FT_Char ft_char_table[128] = + { + /* 0x00 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + }; + + /* no character >= 0x80 can represent a valid number */ +#define OP >= + +#endif /* 'A' == 65 */ + +#if 'A' == 193 + /* EBCDIC */ + + static const FT_Char ft_char_table[128] = + { + /* 0x80 */ + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + }; + + /* no character < 0x80 can represent a valid number */ +#define OP < + +#endif /* 'A' == 193 */ + + + FT_LOCAL_DEF( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ) + { + FT_Byte* p = *cursor; + + FT_Long num = 0; + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + + FT_Long num_limit; + FT_Char c_limit; + + + if ( p >= limit ) + goto Bad; + + if ( base < 2 || base > 36 ) + { + FT_TRACE4(( "!!!INVALID BASE:!!!" )); + return 0; + } + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + goto Bad; + + /* only a single sign is allowed */ + if ( *p == '-' || *p == '+' ) + return 0; + } + + num_limit = 0x7FFFFFFFL / base; + c_limit = (FT_Char)( 0x7FFFFFFFL % base ); + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( c < 0 || c >= base ) + break; + + if ( num > num_limit || ( num == num_limit && c > c_limit ) ) + have_overflow = 1; + else + num = num * base + c; + } + + *cursor = p; + + if ( have_overflow ) + { + num = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + } + + if ( sign ) + num = -num; + + return num; + + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + } + + + FT_LOCAL_DEF( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ) + + { + FT_Byte* p = *cursor; + FT_Byte* curp; + + FT_Long num; + + + curp = p; + num = PS_Conv_Strtol( &p, limit, 10 ); + + if ( p == curp ) + return 0; + + if ( p < limit && *p == '#' ) + { + p++; + + curp = p; + num = PS_Conv_Strtol( &p, limit, num ); + + if ( p == curp ) + return 0; + } + + *cursor = p; + + return num; + } + + + FT_LOCAL_DEF( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* p = *cursor; + FT_Byte* curp; + + FT_Fixed integral = 0; + FT_Long decimal = 0; + FT_Long divider = 1; + + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + FT_Bool have_underflow = 0; + + + if ( p >= limit ) + goto Bad; + + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + + p++; + if ( p == limit ) + goto Bad; + + /* only a single sign is allowed */ + if ( *p == '-' || *p == '+' ) + return 0; + } + + /* read the integer part */ + if ( *p != '.' ) + { + curp = p; + integral = PS_Conv_ToInt( &p, limit ); + + if ( p == curp ) + return 0; + + if ( integral > 0x7FFF ) + have_overflow = 1; + else + integral = (FT_Fixed)( (FT_UInt32)integral << 16 ); + } + + /* read the decimal part */ + if ( p < limit && *p == '.' ) + { + p++; + + for ( ; p < limit; p++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( c < 0 || c >= 10 ) + break; + + /* only add digit if we don't overflow */ + if ( divider < 0xCCCCCCCL && decimal < 0xCCCCCCCL ) + { + decimal = decimal * 10 + c; + + if ( !integral && power_ten > 0 ) + power_ten--; + else + divider *= 10; + } + } + } + + /* read exponent, if any */ + if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) ) + { + FT_Long exponent; + + + p++; + + curp = p; + exponent = PS_Conv_ToInt( &p, limit ); + + if ( curp == p ) + return 0; + + /* arbitrarily limit exponent */ + if ( exponent > 1000 ) + have_overflow = 1; + else if ( exponent < -1000 ) + have_underflow = 1; + else + power_ten += exponent; + } + + *cursor = p; + + if ( !integral && !decimal ) + return 0; + + if ( have_overflow ) + goto Overflow; + if ( have_underflow ) + goto Underflow; + + while ( power_ten > 0 ) + { + if ( integral >= 0xCCCCCCCL ) + goto Overflow; + integral *= 10; + + if ( decimal >= 0xCCCCCCCL ) + { + if ( divider == 1 ) + goto Overflow; + divider /= 10; + } + else + decimal *= 10; + + power_ten--; + } + + while ( power_ten < 0 ) + { + integral /= 10; + if ( divider < 0xCCCCCCCL ) + divider *= 10; + else + decimal /= 10; + + if ( !integral && !decimal ) + goto Underflow; + + power_ten++; + } + + if ( decimal ) + { + decimal = FT_DivFix( decimal, divider ); + /* it's not necessary to check this addition for overflow */ + /* due to the structure of the real number representation */ + integral += decimal; + } + + Exit: + if ( sign ) + integral = -integral; + + return integral; + + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + + Overflow: + integral = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + + Underflow: + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + return 0; + } + + +#if 0 + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + + + for ( p = *cursor; r < n && p < limit; p++ ) + { + FT_Byte b; + + + if ( *p != '\\' ) + { + buffer[r++] = *p; + + continue; + } + + p++; + + switch ( *p ) + { + case 'n': + b = '\n'; + break; + case 'r': + b = '\r'; + break; + case 't': + b = '\t'; + break; + case 'b': + b = '\b'; + break; + case 'f': + b = '\f'; + break; + case '\r': + p++; + if ( *p != '\n' ) + { + b = *p; + + break; + } + /* no break */ + case '\n': + continue; + break; + default: + if ( IS_PS_DIGIT( *p ) ) + { + b = *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + { + b = b * 8 + *p - '0'; + + p++; + + if ( IS_PS_DIGIT( *p ) ) + b = b * 8 + *p - '0'; + else + { + buffer[r++] = b; + b = *p; + } + } + else + { + buffer[r++] = b; + b = *p; + } + } + else + b = *p; + break; + } + + buffer[r++] = b; + } + + *cursor = p; + + return r; + } +#endif /* 0 */ + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + FT_UInt w = 0; + FT_UInt pad = 0x01; + + + n *= 2; + +#if 1 + + p = *cursor; + + if ( p >= limit ) + return 0; + + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); + + /* we try to process two nibbles at a time to be as fast as possible */ + for ( ; r < n; r++ ) + { + FT_UInt c = p[r]; + + + if ( IS_PS_SPACE( c ) ) + continue; + + if ( c OP 0x80 ) + break; + + c = (FT_UInt)ft_char_table[c & 0x7F]; + if ( c >= 16 ) + break; + + pad = ( pad << 4 ) | c; + if ( pad & 0x100 ) + { + buffer[w++] = (FT_Byte)pad; + pad = 0x01; + } + } + + if ( pad != 0x01 ) + buffer[w++] = (FT_Byte)( pad << 4 ); + + *cursor = p + r; + + return w; + +#else /* 0 */ + + for ( r = 0; r < n; r++ ) + { + FT_Char c; + + + if ( IS_PS_SPACE( *p ) ) + continue; + + if ( *p OP 0x80 ) + break; + + c = ft_char_table[*p & 0x7F]; + + if ( (unsigned)c >= 16 ) + break; + + if ( r & 1 ) + { + *buffer = (FT_Byte)( *buffer + c ); + buffer++; + } + else + *buffer = (FT_Byte)( c << 4 ); + + r++; + } + + *cursor = p; + + return ( r + 1 ) / 2; + +#endif /* 0 */ + + } + + + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ) + { + FT_Byte* p; + FT_UInt r; + FT_UInt s = *seed; + + +#if 1 + + p = *cursor; + + if ( p >= limit ) + return 0; + + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); + + for ( r = 0; r < n; r++ ) + { + FT_UInt val = p[r]; + FT_UInt b = ( val ^ ( s >> 8 ) ); + + + s = ( (val + s)*52845U + 22719 ) & 0xFFFFU; + buffer[r] = (FT_Byte) b; + } + + *cursor = p + n; + *seed = (FT_UShort)s; + +#else /* 0 */ + + for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ ) + { + FT_Byte b = (FT_Byte)( *p ^ ( s >> 8 ) ); + + + s = (FT_UShort)( ( *p + s ) * 52845U + 22719 ); + *buffer++ = b; + } + *cursor = p; + *seed = s; + +#endif /* 0 */ + + return r; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psconv.h b/Dependencies/freetype/freetype/src/psaux/psconv.h new file mode 100644 index 00000000..91fcd15a --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psconv.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * + * psconv.h + * + * Some convenience conversions (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSCONV_H_ +#define PSCONV_H_ + + +#include + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ); + + + FT_LOCAL( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ); + + FT_LOCAL( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ); + +#if 0 + FT_LOCAL( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); +#endif + + FT_LOCAL( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); + + FT_LOCAL( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ); + + +FT_END_HEADER + +#endif /* PSCONV_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/pserror.c b/Dependencies/freetype/freetype/src/psaux/pserror.c new file mode 100644 index 00000000..98cebcf7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/pserror.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * pserror.c + * + * Adobe's code for error handling (body). + * + * Copyright 2006-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include "pserror.h" + + + FT_LOCAL_DEF( void ) + cf2_setError( FT_Error* error, + FT_Error value ) + { + if ( error && !*error ) + *error = value; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/pserror.h b/Dependencies/freetype/freetype/src/psaux/pserror.h new file mode 100644 index 00000000..5738853f --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/pserror.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * + * pserror.h + * + * Adobe's code for error handling (specification). + * + * Copyright 2006-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSERROR_H_ +#define PSERROR_H_ + + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CF2_Err_ +#define FT_ERR_BASE FT_Mod_Err_CF2 + + +#include +#include +#include "psft.h" + + +FT_BEGIN_HEADER + + + /* + * A poor-man error facility. + * + * This code being written in vanilla C, doesn't have the luxury of a + * language-supported exception mechanism such as the one available in + * Java. Instead, we are stuck with using error codes that must be + * carefully managed and preserved. However, it is convenient for us to + * model our error mechanism on a Java-like exception mechanism. + * When we assign an error code we are thus `throwing' an error. + * + * The preservation of an error code is done by coding convention. + * Upon a function call if the error code is anything other than + * `FT_Err_Ok', which is guaranteed to be zero, we + * will return without altering that error. This will allow the + * error to propagate and be handled at the appropriate location in + * the code. + * + * This allows a style of code where the error code is initialized + * up front and a block of calls are made with the error code only + * being checked after the block. If a new error occurs, the original + * error will be preserved and a functional no-op should result in any + * subsequent function that has an initial error code not equal to + * `FT_Err_Ok'. + * + * Errors are encoded by calling the `FT_THROW' macro. For example, + * + * { + * FT_Error e; + * + * + * ... + * e = FT_THROW( Out_Of_Memory ); + * } + * + */ + + + /* Set error code to a particular value. */ + FT_LOCAL( void ) + cf2_setError( FT_Error* error, + FT_Error value ); + + + /* + * A macro that conditionally sets an error code. + * + * This macro will first check whether `error' is set; + * if not, it will set it to `e'. + * + */ +#define CF2_SET_ERROR( error, e ) \ + cf2_setError( error, FT_THROW( e ) ) + + +FT_END_HEADER + + +#endif /* PSERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psfixed.h b/Dependencies/freetype/freetype/src/psaux/psfixed.h new file mode 100644 index 00000000..299d0763 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psfixed.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * + * psfixed.h + * + * Adobe's code for Fixed-Point Mathematics (specification only). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFIXED_H_ +#define PSFIXED_H_ + + +FT_BEGIN_HEADER + + + /* rasterizer integer and fixed-point arithmetic must be 32-bit */ + +#define CF2_Fixed CF2_F16Dot16 + typedef FT_Int32 CF2_Frac; /* 2.30 fixed-point */ + + +#define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL ) +#define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L ) +#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L ) +#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 ) + + /* in C 89, left and right shift of negative numbers is */ + /* implementation specific behaviour in the general case */ + +#define cf2_intToFixed( i ) \ + ( (CF2_Fixed)( (FT_UInt32)(i) << 16 ) ) +#define cf2_fixedToInt( x ) \ + ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) +#define cf2_fixedRound( x ) \ + ( (CF2_Fixed)( ( (FT_UInt32)(x) + 0x8000U ) & 0xFFFF0000UL ) ) +#define cf2_doubleToFixed( f ) \ + ( (CF2_Fixed)( (f) * 65536.0 + 0.5 ) ) +#define cf2_fixedAbs( x ) \ + ( (x) < 0 ? NEG_INT32( x ) : (x) ) +#define cf2_fixedFloor( x ) \ + ( (CF2_Fixed)( (FT_UInt32)(x) & 0xFFFF0000UL ) ) +#define cf2_fixedFraction( x ) \ + ( (x) - cf2_fixedFloor( x ) ) +#define cf2_fracToFixed( x ) \ + ( ( (x) + 0x2000 - ( (x) < 0 ) ) >> 14 ) + + + /* signed numeric types */ + typedef enum CF2_NumberType_ + { + CF2_NumberFixed, /* 16.16 */ + CF2_NumberFrac, /* 2.30 */ + CF2_NumberInt /* 32.0 */ + + } CF2_NumberType; + + +FT_END_HEADER + + +#endif /* PSFIXED_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psfont.c b/Dependencies/freetype/freetype/src/psaux/psfont.c new file mode 100644 index 00000000..0db1f0c5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psfont.c @@ -0,0 +1,566 @@ +/**************************************************************************** + * + * psfont.c + * + * Adobe's code for font instances (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include + +#include "psft.h" + +#include "psglue.h" +#include "psfont.h" +#include "pserror.h" +#include "psintrp.h" + + + /* Compute a stem darkening amount in character space. */ + static void + cf2_computeDarkening( CF2_Fixed emRatio, + CF2_Fixed ppem, + CF2_Fixed stemWidth, + CF2_Fixed* darkenAmount, + CF2_Fixed boldenAmount, + FT_Bool stemDarkened, + FT_Int* darkenParams ) + { + /* + * Total darkening amount is computed in 1000 unit character space + * using the modified 5 part curve as Adobe's Avalon rasterizer. + * The darkening amount is smaller for thicker stems. + * It becomes zero when the stem is thicker than 2.333 pixels. + * + * By default, we use + * + * darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels, + * darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels, + * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels, + * + * and piecewise linear in-between: + * + * + * darkening + * ^ + * | + * | (x1,y1) + * |--------+ + * | \ + * | \ + * | \ (x3,y3) + * | +----------+ + * | (x2,y2) \ + * | \ + * | \ + * | +----------------- + * | (x4,y4) + * +---------------------------------------------> stem + * thickness + * + * + * This corresponds to the following values for the + * `darkening-parameters' property: + * + * (x1, y1) = (500, 400) + * (x2, y2) = (1000, 275) + * (x3, y3) = (1667, 275) + * (x4, y4) = (2333, 0) + * + */ + + /* Internal calculations are done in units per thousand for */ + /* convenience. The x axis is scaled stem width in */ + /* thousandths of a pixel. That is, 1000 is 1 pixel. */ + /* The y axis is darkening amount in thousandths of a pixel.*/ + /* In the code, below, dividing by ppem and */ + /* adjusting for emRatio converts darkenAmount to character */ + /* space (font units). */ + CF2_Fixed stemWidthPer1000, scaledStem; + FT_Int logBase2; + + + *darkenAmount = 0; + + if ( boldenAmount == 0 && !stemDarkened ) + return; + + /* protect against range problems and divide by zero */ + if ( emRatio < cf2_doubleToFixed( .01 ) ) + return; + + if ( stemDarkened ) + { + FT_Int x1 = darkenParams[0]; + FT_Int y1 = darkenParams[1]; + FT_Int x2 = darkenParams[2]; + FT_Int y2 = darkenParams[3]; + FT_Int x3 = darkenParams[4]; + FT_Int y3 = darkenParams[5]; + FT_Int x4 = darkenParams[6]; + FT_Int y4 = darkenParams[7]; + + + /* convert from true character space to 1000 unit character space; */ + /* add synthetic emboldening effect */ + + /* `stemWidthPer1000' will not overflow for a legitimate font */ + + stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio ); + + /* `scaledStem' can easily overflow, so we must clamp its maximum */ + /* value; the test doesn't need to be precise, but must be */ + /* conservative. The clamp value (default 2333) where */ + /* `darkenAmount' is zero is well below the overflow value of */ + /* 32767. */ + /* */ + /* FT_MSB computes the integer part of the base 2 logarithm. The */ + /* number of bits for the product is 1 or 2 more than the sum of */ + /* logarithms; remembering that the 16 lowest bits of the fraction */ + /* are dropped this is correct to within a factor of almost 4. */ + /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and */ + /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */ + /* 0xFFFF.FE00 is also 23+23. */ + + logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) + + FT_MSB( (FT_UInt32)ppem ); + + if ( logBase2 >= 46 ) + /* possible overflow */ + scaledStem = cf2_intToFixed( x4 ); + else + scaledStem = FT_MulFix( stemWidthPer1000, ppem ); + + /* now apply the darkening parameters */ + + if ( scaledStem < cf2_intToFixed( x1 ) ) + *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem ); + + else if ( scaledStem < cf2_intToFixed( x2 ) ) + { + FT_Int xdelta = x2 - x1; + FT_Int ydelta = y2 - y1; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x1 ), ppem ); + + + if ( !xdelta ) + goto Try_x3; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y1 ), ppem ); + } + + else if ( scaledStem < cf2_intToFixed( x3 ) ) + { + Try_x3: + { + FT_Int xdelta = x3 - x2; + FT_Int ydelta = y3 - y2; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x2 ), ppem ); + + + if ( !xdelta ) + goto Try_x4; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y2 ), ppem ); + } + } + + else if ( scaledStem < cf2_intToFixed( x4 ) ) + { + Try_x4: + { + FT_Int xdelta = x4 - x3; + FT_Int ydelta = y4 - y3; + FT_Int x = stemWidthPer1000 - + FT_DivFix( cf2_intToFixed( x3 ), ppem ); + + + if ( !xdelta ) + goto Use_y4; + + *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + + FT_DivFix( cf2_intToFixed( y3 ), ppem ); + } + } + + else + { + Use_y4: + *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem ); + } + + /* use half the amount on each side and convert back to true */ + /* character space */ + *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio ); + } + + /* add synthetic emboldening effect in character space */ + *darkenAmount += boldenAmount / 2; + } + + + /* set up values for the current FontDict and matrix; */ + /* called for each glyph to be rendered */ + + /* caller's transform is adjusted for subpixel positioning */ + static void + cf2_font_setup( CF2_Font font, + const CF2_Matrix* transform ) + { + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + FT_Bool needExtraSetup = FALSE; + + CFF_VStoreRec* vstore; + FT_Bool hasVariations = FALSE; + + /* character space units */ + CF2_Fixed boldenX = font->syntheticEmboldeningAmountX; + CF2_Fixed boldenY = font->syntheticEmboldeningAmountY; + + CFF_SubFont subFont; + CF2_Fixed ppem; + + CF2_UInt lenNormalizedV = 0; + FT_Fixed* normalizedV = NULL; + + /* clear previous error */ + font->error = FT_Err_Ok; + + /* if a CID fontDict has changed, we need to recompute some cached */ + /* data */ + subFont = cf2_getSubfont( decoder ); + if ( font->lastSubfont != subFont ) + { + font->lastSubfont = subFont; + needExtraSetup = TRUE; + } + + if ( !font->isT1 ) + { + /* check for variation vectors */ + vstore = cf2_getVStore( decoder ); + hasVariations = ( vstore->dataCount != 0 ); + + if ( hasVariations ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Service_CFFLoad cffload = (FT_Service_CFFLoad)font->cffload; + + + /* check whether Private DICT in this subfont needs to be reparsed */ + font->error = cf2_getNormalizedVector( decoder, + &lenNormalizedV, + &normalizedV ); + if ( font->error ) + return; + + if ( cffload->blend_check_vector( &subFont->blend, + subFont->private_dict.vsindex, + lenNormalizedV, + normalizedV ) ) + { + /* blend has changed, reparse */ + cffload->load_private_dict( decoder->cff, + subFont, + lenNormalizedV, + normalizedV ); + needExtraSetup = TRUE; + } +#endif + + /* copy from subfont */ + font->blend.font = subFont->blend.font; + + /* clear state of charstring blend */ + font->blend.usedBV = FALSE; + + /* initialize value for charstring */ + font->vsindex = subFont->private_dict.vsindex; + + /* store vector inputs for blends in charstring */ + font->lenNDV = lenNormalizedV; + font->NDV = normalizedV; + } + } + + /* if ppem has changed, we need to recompute some cached data */ + /* note: because of CID font matrix concatenation, ppem and transform */ + /* do not necessarily track. */ + ppem = cf2_getPpemY( decoder ); + if ( font->ppem != ppem ) + { + font->ppem = ppem; + needExtraSetup = TRUE; + } + + /* copy hinted flag on each call */ + font->hinted = FT_BOOL( font->renderingFlags & CF2_FlagsHinted ); + + /* determine if transform has changed; */ + /* include Fontmatrix but ignore translation */ + if ( ft_memcmp( transform, + &font->currentTransform, + 4 * sizeof ( CF2_Fixed ) ) != 0 ) + { + /* save `key' information for `cache of one' matrix data; */ + /* save client transform, without the translation */ + font->currentTransform = *transform; + font->currentTransform.tx = + font->currentTransform.ty = cf2_intToFixed( 0 ); + + /* TODO: FreeType transform is simple scalar; for now, use identity */ + /* for outer */ + font->innerTransform = *transform; + font->outerTransform.a = + font->outerTransform.d = cf2_intToFixed( 1 ); + font->outerTransform.b = + font->outerTransform.c = cf2_intToFixed( 0 ); + + needExtraSetup = TRUE; + } + + /* + * font->darkened is set to true if there is a stem darkening request or + * the font is synthetic emboldened. + * font->darkened controls whether to adjust blue zones, winding order, + * and hinting. + * + */ + if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) ) + { + font->stemDarkened = + FT_BOOL( font->renderingFlags & CF2_FlagsDarkened ); + + /* blue zones depend on darkened flag */ + needExtraSetup = TRUE; + } + + /* recompute variables that are dependent on transform or FontDict or */ + /* darken flag */ + if ( needExtraSetup ) + { + /* StdVW is found in the private dictionary; */ + /* recompute darkening amounts whenever private dictionary or */ + /* transform change */ + /* Note: a rendering flag turns darkening on or off, so we want to */ + /* store the `on' amounts; */ + /* darkening amount is computed in character space */ + /* TODO: testing size-dependent darkening here; */ + /* what to do for rotations? */ + + CF2_Fixed emRatio; + CF2_Fixed stdHW; + CF2_Int unitsPerEm = font->unitsPerEm; + + + if ( unitsPerEm == 0 ) + unitsPerEm = 1000; + + ppem = FT_MAX( cf2_intToFixed( 4 ), + font->ppem ); /* use minimum ppem of 4 */ + +#if 0 + /* since vstem is measured in the x-direction, we use the `a' member */ + /* of the fontMatrix */ + emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a ); +#endif + + /* Freetype does not preserve the fontMatrix when parsing; use */ + /* unitsPerEm instead. */ + /* TODO: check precision of this */ + emRatio = cf2_intToFixed( 1000 ) / unitsPerEm; + font->stdVW = cf2_getStdVW( decoder ); + + if ( font->stdVW <= 0 ) + font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); + + if ( boldenX > 0 ) + { + /* Ensure that boldenX is at least 1 pixel for synthetic bold font */ + /* (similar to what Avalon does) */ + boldenX = FT_MAX( boldenX, + FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) ); + + /* Synthetic emboldening adds at least 1 pixel to darkenX, while */ + /* stem darkening adds at most half pixel. Since the purpose of */ + /* stem darkening (readability at small sizes) is met with */ + /* synthetic emboldening, no need to add stem darkening for a */ + /* synthetic bold font. */ + cf2_computeDarkening( emRatio, + ppem, + font->stdVW, + &font->darkenX, + boldenX, + FALSE, + font->darkenParams ); + } + else + cf2_computeDarkening( emRatio, + ppem, + font->stdVW, + &font->darkenX, + 0, + font->stemDarkened, + font->darkenParams ); + +#if 0 + /* since hstem is measured in the y-direction, we use the `d' member */ + /* of the fontMatrix */ + /* TODO: use the same units per em as above; check this */ + emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d ); +#endif + + /* set the default stem width, because it must be the same for all */ + /* family members; */ + /* choose a constant for StdHW that depends on font contrast */ + stdHW = cf2_getStdHW( decoder ); + + if ( stdHW > 0 && font->stdVW > MUL_INT32( 2, stdHW ) ) + font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio ); + else + { + /* low contrast font gets less hstem darkening */ + font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio ); + } + + cf2_computeDarkening( emRatio, + ppem, + font->stdHW, + &font->darkenY, + boldenY, + font->stemDarkened, + font->darkenParams ); + + if ( font->darkenX != 0 || font->darkenY != 0 ) + font->darkened = TRUE; + else + font->darkened = FALSE; + + font->reverseWinding = FALSE; /* initial expectation is CCW */ + + /* compute blue zones for this instance */ + cf2_blues_init( &font->blues, font ); + + } /* needExtraSetup */ + } + + + /* equivalent to AdobeGetOutline */ + FT_LOCAL_DEF( FT_Error ) + cf2_getGlyphOutline( CF2_Font font, + CF2_Buffer charstring, + const CF2_Matrix* transform, + CF2_F16Dot16* glyphWidth ) + { + FT_Error lastError = FT_Err_Ok; + + FT_Vector translation; + +#if 0 + FT_Vector advancePoint; +#endif + + CF2_Fixed advWidth = 0; + FT_Bool needWinding; + + + /* Note: use both integer and fraction for outlines. This allows bbox */ + /* to come out directly. */ + + translation.x = transform->tx; + translation.y = transform->ty; + + /* set up values based on transform */ + cf2_font_setup( font, transform ); + if ( font->error ) + goto exit; /* setup encountered an error */ + + /* reset darken direction */ + font->reverseWinding = FALSE; + + /* winding order only affects darkening */ + needWinding = font->darkened; + + while ( 1 ) + { + /* reset output buffer */ + cf2_outline_reset( &font->outline ); + + /* build the outline, passing the full translation */ + cf2_interpT2CharString( font, + charstring, + (CF2_OutlineCallbacks)&font->outline, + &translation, + FALSE, + 0, + 0, + &advWidth ); + + if ( font->error ) + goto exit; + + if ( !needWinding ) + break; + + /* check winding order */ + if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */ + break; + + /* invert darkening and render again */ + /* TODO: this should be a parameter to getOutline-computeOffset */ + font->reverseWinding = TRUE; + + needWinding = FALSE; /* exit after next iteration */ + } + + /* finish storing client outline */ + cf2_outline_close( &font->outline ); + + exit: + /* FreeType just wants the advance width; there is no translation */ + *glyphWidth = advWidth; + + /* free resources and collect errors from objects we've used */ + cf2_setError( &font->error, lastError ); + + return font->error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psfont.h b/Dependencies/freetype/freetype/src/psaux/psfont.h new file mode 100644 index 00000000..836fce4e --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psfont.h @@ -0,0 +1,134 @@ +/**************************************************************************** + * + * psfont.h + * + * Adobe's code for font instances (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFONT_H_ +#define PSFONT_H_ + + +#include + +#include "psft.h" +#include "psblues.h" + + +FT_BEGIN_HEADER + + +#define CF2_OPERAND_STACK_SIZE 48 +#define CF2_MAX_SUBR 16 /* maximum subroutine nesting; */ + /* only 10 are allowed but there exist */ + /* fonts like `HiraKakuProN-W3.ttf' */ + /* (Hiragino Kaku Gothic ProN W3; */ + /* 8.2d6e1; 2014-12-19) that exceed */ + /* this limit */ +#define CF2_STORAGE_SIZE 32 + + + /* typedef is in `cf2glue.h' */ + struct CF2_FontRec_ + { + FT_Memory memory; + FT_Error error; /* shared error for this instance */ + + FT_Bool isT1; + FT_Bool isCFF2; + CF2_RenderingFlags renderingFlags; + + /* variables that depend on Transform: */ + /* the following have zero translation; */ + /* inner * outer = font * original */ + + CF2_Matrix currentTransform; /* original client matrix */ + CF2_Matrix innerTransform; /* for hinting; erect, scaled */ + CF2_Matrix outerTransform; /* post hinting; includes rotations */ + CF2_Fixed ppem; /* transform-dependent */ + + /* variation data */ + CFF_BlendRec blend; /* cached charstring blend vector */ + CF2_UInt vsindex; /* current vsindex */ + CF2_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + + CF2_Int unitsPerEm; + + CF2_Fixed syntheticEmboldeningAmountX; /* character space units */ + CF2_Fixed syntheticEmboldeningAmountY; /* character space units */ + + /* FreeType related members */ + CF2_OutlineRec outline; /* freetype glyph outline functions */ + PS_Decoder* decoder; + CFF_SubFont lastSubfont; /* FreeType parsed data; */ + /* top font or subfont */ + + /* these flags can vary from one call to the next */ + FT_Bool hinted; + FT_Bool darkened; /* true if stemDarkened or synthetic bold */ + /* i.e. darkenX != 0 || darkenY != 0 */ + FT_Bool stemDarkened; + + FT_Int darkenParams[8]; /* 1000 unit character space */ + + /* variables that depend on both FontDict and Transform */ + CF2_Fixed stdVW; /* in character space; depends on dict entry */ + CF2_Fixed stdHW; /* in character space; depends on dict entry */ + CF2_Fixed darkenX; /* character space units */ + CF2_Fixed darkenY; /* depends on transform */ + /* and private dict (StdVW) */ + FT_Bool reverseWinding; /* darken assuming */ + /* counterclockwise winding */ + + CF2_BluesRec blues; /* computed zone data */ + + FT_Service_CFFLoad cffload; /* pointer to cff functions */ + }; + + + FT_LOCAL( FT_Error ) + cf2_getGlyphOutline( CF2_Font font, + CF2_Buffer charstring, + const CF2_Matrix* transform, + CF2_F16Dot16* glyphWidth ); + + +FT_END_HEADER + + +#endif /* PSFONT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psft.c b/Dependencies/freetype/freetype/src/psaux/psft.c new file mode 100644 index 00000000..fd0abe17 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psft.c @@ -0,0 +1,895 @@ +/**************************************************************************** + * + * psft.c + * + * FreeType Glue Component to Adobe's Interpreter (body). + * + * Copyright 2013-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psfont.h" +#include "pserror.h" +#include "psobjs.h" +#include "cffdecode.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include + + +#define CF2_MAX_SIZE cf2_intToFixed( 2000 ) /* max ppem */ + + + /* + * This check should avoid most internal overflow cases. Clients should + * generally respond to `Glyph_Too_Big' by getting a glyph outline + * at EM size, scaling it and filling it as a graphics operation. + * + */ + static FT_Error + cf2_checkTransform( const CF2_Matrix* transform, + CF2_Int unitsPerEm ) + { + CF2_Fixed maxScale; + + + if ( transform->a <= 0 || transform->d <= 0 ) + return FT_THROW( Invalid_Size_Handle ); + + FT_ASSERT( unitsPerEm > 0 ); + FT_ASSERT( transform->b == 0 && transform->c == 0 ); + FT_ASSERT( transform->tx == 0 && transform->ty == 0 ); + + if ( unitsPerEm > 0x7FFF ) + return FT_THROW( Glyph_Too_Big ); + + maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) ); + + if ( transform->a > maxScale || transform->d > maxScale ) + return FT_THROW( Glyph_Too_Big ); + + return FT_Err_Ok; + } + + + static void + cf2_setGlyphWidth( CF2_Outline outline, + CF2_Fixed width ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + if ( !decoder->builder.is_t1 ) + *decoder->glyph_width = cf2_fixedToInt( width ); + } + + + /* Clean up font instance. */ + static void + cf2_free_instance( void* ptr ) + { + CF2_Font font = (CF2_Font)ptr; + + + if ( font ) + { + FT_Memory memory = font->memory; + + + FT_FREE( font->blend.lastNDV ); + FT_FREE( font->blend.BV ); + } + } + + + /********************************************* + * + * functions for handling client outline; + * FreeType uses coordinates in 26.6 format + * + */ + + static void + cf2_builder_moveTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + (void)params; /* only used in debug mode */ + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpMoveTo ); + + builder = &outline->decoder->builder; + + /* note: two successive moves simply close the contour twice */ + ps_builder_close_contour( builder ); + builder->path_begun = 0; + } + + + static void + cf2_builder_lineTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + FT_Error error; + + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpLineTo ); + + builder = &outline->decoder->builder; + + if ( !builder->path_begun ) + { + /* record the move before the line; also check points and set */ + /* `path_begun' */ + error = ps_builder_start_point( builder, + params->pt0.x, + params->pt0.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + /* `ps_builder_add_point1' includes a check_points call for one point */ + error = ps_builder_add_point1( builder, + params->pt1.x, + params->pt1.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + + static void + cf2_builder_cubeTo( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ) + { + FT_Error error; + + /* downcast the object pointer */ + CF2_Outline outline = (CF2_Outline)callbacks; + PS_Builder* builder; + + + FT_ASSERT( outline && outline->decoder ); + FT_ASSERT( params->op == CF2_PathOpCubeTo ); + + builder = &outline->decoder->builder; + + if ( !builder->path_begun ) + { + /* record the move before the line; also check points and set */ + /* `path_begun' */ + error = ps_builder_start_point( builder, + params->pt0.x, + params->pt0.y ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + } + + /* prepare room for 3 points: 2 off-curve, 1 on-curve */ + error = ps_builder_check_points( builder, 3 ); + if ( error ) + { + if ( !*callbacks->error ) + *callbacks->error = error; + return; + } + + ps_builder_add_point( builder, + params->pt1.x, + params->pt1.y, 0 ); + ps_builder_add_point( builder, + params->pt2.x, + params->pt2.y, 0 ); + ps_builder_add_point( builder, + params->pt3.x, + params->pt3.y, 1 ); + } + + + static void + cf2_outline_init( CF2_Outline outline, + FT_Memory memory, + FT_Error* error ) + { + FT_ZERO( outline ); + + outline->root.memory = memory; + outline->root.error = error; + + outline->root.moveTo = cf2_builder_moveTo; + outline->root.lineTo = cf2_builder_lineTo; + outline->root.cubeTo = cf2_builder_cubeTo; + } + + + /* get scaling and hint flag from GlyphSlot */ + static void + cf2_getScaleAndHintFlag( PS_Decoder* decoder, + CF2_Fixed* x_scale, + CF2_Fixed* y_scale, + FT_Bool* hinted, + FT_Bool* scaled ) + { + FT_ASSERT( decoder && decoder->builder.glyph ); + + /* note: FreeType scale includes a factor of 64 */ + *hinted = decoder->builder.glyph->hint; + *scaled = decoder->builder.glyph->scaled; + + if ( *hinted ) + { + *x_scale = ADD_INT32( decoder->builder.glyph->x_scale, 32 ) / 64; + *y_scale = ADD_INT32( decoder->builder.glyph->y_scale, 32 ) / 64; + } + else + { + /* for unhinted outlines, `cff_slot_load' does the scaling, */ + /* thus render at `unity' scale */ + + *x_scale = 0x0400; /* 1/64 as 16.16 */ + *y_scale = 0x0400; + } + } + + + /* get units per em from `FT_Face' */ + /* TODO: should handle font matrix concatenation? */ + static FT_UShort + cf2_getUnitsPerEm( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->builder.face ); + + return decoder->builder.face->units_per_EM; + } + + + /* Main entry point: Render one glyph. */ + FT_LOCAL_DEF( FT_Error ) + cf2_decoder_parse_charstrings( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ) + { + FT_Memory memory; + FT_Error error = FT_Err_Ok; + CF2_Font font; + + FT_Bool is_t1 = decoder->builder.is_t1; + + + FT_ASSERT( decoder && + ( is_t1 || decoder->cff ) ); + + if ( is_t1 && !decoder->current_subfont ) + { + FT_ERROR(( "cf2_decoder_parse_charstrings (Type 1): " + "SubFont missing. Use `t1_make_subfont' first\n" )); + return FT_THROW( Invalid_Table ); + } + + memory = decoder->builder.memory; + + /* CF2 data is saved here across glyphs */ + font = (CF2_Font)decoder->cf2_instance->data; + + /* on first glyph, allocate instance structure */ + if ( !decoder->cf2_instance->data ) + { + decoder->cf2_instance->finalizer = + (FT_Generic_Finalizer)cf2_free_instance; + + if ( FT_ALLOC( decoder->cf2_instance->data, + sizeof ( CF2_FontRec ) ) ) + return FT_THROW( Out_Of_Memory ); + + font = (CF2_Font)decoder->cf2_instance->data; + + font->memory = memory; + + if ( !is_t1 ) + font->cffload = (FT_Service_CFFLoad)decoder->cff->cffload; + + /* initialize a client outline, to be shared by each glyph rendered */ + cf2_outline_init( &font->outline, font->memory, &font->error ); + } + + /* save decoder; it is a stack variable and will be different on each */ + /* call */ + font->decoder = decoder; + font->outline.decoder = decoder; + + { + /* build parameters for Adobe engine */ + + PS_Builder* builder = &decoder->builder; + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + FT_Bool no_stem_darkening_driver = + driver->no_stem_darkening; + FT_Char no_stem_darkening_font = + builder->face->internal->no_stem_darkening; + + /* local error */ + FT_Error error2 = FT_Err_Ok; + CF2_BufferRec buf; + CF2_Matrix transform; + CF2_F16Dot16 glyphWidth; + + FT_Bool hinted; + FT_Bool scaled; + + + /* FreeType has already looked up the GID; convert to */ + /* `RegionBuffer', assuming that the input has been validated */ + FT_ASSERT( charstring_base + charstring_len >= charstring_base ); + + FT_ZERO( &buf ); + buf.start = + buf.ptr = charstring_base; + buf.end = FT_OFFSET( charstring_base, charstring_len ); + + FT_ZERO( &transform ); + + cf2_getScaleAndHintFlag( decoder, + &transform.a, + &transform.d, + &hinted, + &scaled ); + + if ( is_t1 ) + font->isCFF2 = FALSE; + else + { + /* copy isCFF2 boolean from TT_Face to CF2_Font */ + font->isCFF2 = ((TT_Face)builder->face)->is_cff2; + } + font->isT1 = is_t1; + + font->renderingFlags = 0; + if ( hinted ) + font->renderingFlags |= CF2_FlagsHinted; + if ( scaled && ( !no_stem_darkening_font || + ( no_stem_darkening_font < 0 && + !no_stem_darkening_driver ) ) ) + font->renderingFlags |= CF2_FlagsDarkened; + + font->darkenParams[0] = driver->darken_params[0]; + font->darkenParams[1] = driver->darken_params[1]; + font->darkenParams[2] = driver->darken_params[2]; + font->darkenParams[3] = driver->darken_params[3]; + font->darkenParams[4] = driver->darken_params[4]; + font->darkenParams[5] = driver->darken_params[5]; + font->darkenParams[6] = driver->darken_params[6]; + font->darkenParams[7] = driver->darken_params[7]; + + /* now get an outline for this glyph; */ + /* also get units per em to validate scale */ + font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder ); + + if ( scaled ) + { + error2 = cf2_checkTransform( &transform, font->unitsPerEm ); + if ( error2 ) + return error2; + } + + error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth ); + if ( error2 ) + return FT_ERR( Invalid_File_Format ); + + cf2_setGlyphWidth( &font->outline, glyphWidth ); + + return FT_Err_Ok; + } + } + + + /* get pointer to current FreeType subfont (based on current glyphID) */ + FT_LOCAL_DEF( CFF_SubFont ) + cf2_getSubfont( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return decoder->current_subfont; + } + + + /* get pointer to VStore structure */ + FT_LOCAL_DEF( CFF_VStore ) + cf2_getVStore( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->cff ); + + return &decoder->cff->vstore; + } + + + /* get maxstack value from CFF2 Top DICT */ + FT_LOCAL_DEF( FT_UInt ) + cf2_getMaxstack( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->cff ); + + return decoder->cff->top_font.font_dict.maxstack; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Get normalized design vector for current render request; */ + /* return pointer and length. */ + /* */ + /* Note: Uses FT_Fixed not CF2_Fixed for the vector. */ + FT_LOCAL_DEF( FT_Error ) + cf2_getNormalizedVector( PS_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ) + { + TT_Face face; + FT_Service_MultiMasters mm; + + + FT_ASSERT( decoder && decoder->builder.face ); + FT_ASSERT( vec && len ); + FT_ASSERT( !decoder->builder.is_t1 ); + + face = (TT_Face)decoder->builder.face; + mm = (FT_Service_MultiMasters)face->mm; + + return mm->get_var_blend( FT_FACE( face ), len, NULL, vec, NULL ); + } +#endif + + + /* get `y_ppem' from `CFF_Size' */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getPpemY( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && + decoder->builder.face && + decoder->builder.face->size ); + + /* + * Note that `y_ppem' can be zero if there wasn't a call to + * `FT_Set_Char_Size' or something similar. However, this isn't a + * problem since we come to this place in the code only if + * FT_LOAD_NO_SCALE is set (the other case gets caught by + * `cf2_checkTransform'). The ppem value is needed to compute the stem + * darkening, which is disabled for getting the unscaled outline. + * + */ + return cf2_intToFixed( + decoder->builder.face->size->metrics.y_ppem ); + } + + + /* get standard stem widths for the current subfont; */ + /* FreeType stores these as integer font units */ + /* (note: variable names seem swapped) */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getStdVW( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.standard_height ); + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getStdHW( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.standard_width ); + } + + + /* note: FreeType stores 1000 times the actual value for `BlueScale' */ + FT_LOCAL_DEF( void ) + cf2_getBlueMetrics( PS_Decoder* decoder, + CF2_Fixed* blueScale, + CF2_Fixed* blueShift, + CF2_Fixed* blueFuzz ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *blueScale = FT_DivFix( + decoder->current_subfont->private_dict.blue_scale, + cf2_intToFixed( 1000 ) ); + *blueShift = cf2_intToFixed( + decoder->current_subfont->private_dict.blue_shift ); + *blueFuzz = cf2_intToFixed( + decoder->current_subfont->private_dict.blue_fuzz ); + } + + + /* get blue values counts and arrays; the FreeType parser has validated */ + /* the counts and verified that each is an even number */ + FT_LOCAL_DEF( void ) + cf2_getBlueValues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_blue_values; + *data = (FT_Fixed*) + &decoder->current_subfont->private_dict.blue_values; + } + + + FT_LOCAL_DEF( void ) + cf2_getOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_other_blues; + *data = (FT_Fixed*) + &decoder->current_subfont->private_dict.other_blues; + } + + + FT_LOCAL_DEF( void ) + cf2_getFamilyBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_family_blues; + *data = (FT_Fixed*) + &decoder->current_subfont->private_dict.family_blues; + } + + + FT_LOCAL_DEF( void ) + cf2_getFamilyOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + *count = decoder->current_subfont->private_dict.num_family_other_blues; + *data = (FT_Fixed*) + &decoder->current_subfont->private_dict.family_other_blues; + } + + + FT_LOCAL_DEF( CF2_Int ) + cf2_getLanguageGroup( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return decoder->current_subfont->private_dict.language_group; + } + + + /* convert unbiased subroutine index to `CF2_Buffer' and */ + /* return 0 on success */ + FT_LOCAL_DEF( CF2_Int ) + cf2_initGlobalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ) + { + CF2_UInt idx; + + + FT_ASSERT( decoder ); + + FT_ZERO( buf ); + + idx = (CF2_UInt)( subrNum + decoder->globals_bias ); + if ( idx >= decoder->num_globals ) + return TRUE; /* error */ + + FT_ASSERT( decoder->globals ); + + buf->start = + buf->ptr = decoder->globals[idx]; + buf->end = decoder->globals[idx + 1]; + + return FALSE; /* success */ + } + + + /* convert AdobeStandardEncoding code to CF2_Buffer; */ + /* used for seac component */ + FT_LOCAL_DEF( FT_Error ) + cf2_getSeacComponent( PS_Decoder* decoder, + CF2_Int code, + CF2_Buffer buf ) + { + CF2_Int gid; + FT_Byte* charstring; + FT_ULong len; + FT_Error error; + + + FT_ASSERT( decoder ); + FT_ASSERT( !decoder->builder.is_t1 ); + + FT_ZERO( buf ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* Incremental fonts don't necessarily have valid charsets. */ + /* They use the character code, not the glyph index, in this case. */ + if ( decoder->builder.face->internal->incremental_interface ) + gid = code; + else +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code ); + if ( gid < 0 ) + return FT_THROW( Invalid_Glyph_Format ); + } + + error = decoder->get_glyph_callback( (TT_Face)decoder->builder.face, + (CF2_UInt)gid, + &charstring, + &len ); + /* TODO: for now, just pass the FreeType error through */ + if ( error ) + return error; + + /* assume input has been validated */ + FT_ASSERT( charstring + len >= charstring ); + + buf->start = charstring; + buf->end = FT_OFFSET( charstring, len ); + buf->ptr = buf->start; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + cf2_freeSeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ) + { + FT_ASSERT( decoder ); + FT_ASSERT( !decoder->builder.is_t1 ); + + decoder->free_glyph_callback( (TT_Face)decoder->builder.face, + (FT_Byte**)&buf->start, + (FT_ULong)( buf->end - buf->start ) ); + } + + + FT_LOCAL_DEF( FT_Error ) + cf2_getT1SeacComponent( PS_Decoder* decoder, + FT_UInt glyph_index, + CF2_Buffer buf ) + { + FT_Data glyph_data; + FT_Error error = FT_Err_Ok; + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; + + + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( inc ) + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, &glyph_data ); + else +#endif + /* For ordinary fonts get the character data stored in the face record. */ + { + glyph_data.pointer = type1->charstrings[glyph_index]; + glyph_data.length = type1->charstrings_len[glyph_index]; + } + + if ( !error ) + { + FT_Byte* charstring_base = (FT_Byte*)glyph_data.pointer; + FT_ULong charstring_len = glyph_data.length; + + + FT_ASSERT( charstring_base + charstring_len >= charstring_base ); + + FT_ZERO( buf ); + buf->start = + buf->ptr = charstring_base; + buf->end = charstring_base + charstring_len; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + cf2_freeT1SeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + T1_Face face; + FT_Data data; + + + FT_ASSERT( decoder ); + + face = (T1_Face)decoder->builder.face; + + data.pointer = buf->start; + data.length = (FT_UInt)( buf->end - buf->start ); + + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &data ); + +#else /* !FT_CONFIG_OPTION_INCREMENTAL */ + + FT_UNUSED( decoder ); + FT_UNUSED( buf ); + +#endif /* !FT_CONFIG_OPTION_INCREMENTAL */ + } + + + FT_LOCAL_DEF( CF2_Int ) + cf2_initLocalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ) + { + CF2_UInt idx; + + + FT_ASSERT( decoder ); + + FT_ZERO( buf ); + + idx = (CF2_UInt)( subrNum + decoder->locals_bias ); + if ( idx >= decoder->num_locals ) + return TRUE; /* error */ + + FT_ASSERT( decoder->locals ); + + buf->start = decoder->locals[idx]; + + if ( decoder->builder.is_t1 ) + { + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + if ( decoder->locals_len ) + buf->end = FT_OFFSET( buf->start, decoder->locals_len[idx] ); + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + buf->start += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + buf->end = decoder->locals[idx + 1]; + } + + if ( !buf->start ) + { + FT_ERROR(( "cf2_initLocalRegionBuffer (Type 1 mode):" + " invoking empty subrs\n" )); + } + } + else + { + buf->end = decoder->locals[idx + 1]; + } + + buf->ptr = buf->start; + + return FALSE; /* success */ + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getDefaultWidthX( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.default_width ); + } + + + FT_LOCAL_DEF( CF2_Fixed ) + cf2_getNominalWidthX( PS_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->current_subfont ); + + return cf2_intToFixed( + decoder->current_subfont->private_dict.nominal_width ); + } + + + FT_LOCAL_DEF( void ) + cf2_outline_reset( CF2_Outline outline ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + outline->root.windingMomentum = 0; + + FT_GlyphLoader_Rewind( decoder->builder.loader ); + } + + + FT_LOCAL_DEF( void ) + cf2_outline_close( CF2_Outline outline ) + { + PS_Decoder* decoder = outline->decoder; + + + FT_ASSERT( decoder ); + + ps_builder_close_contour( &decoder->builder ); + + FT_GlyphLoader_Add( decoder->builder.loader ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psft.h b/Dependencies/freetype/freetype/src/psaux/psft.h new file mode 100644 index 00000000..d9082f3a --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psft.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * + * psft.h + * + * FreeType Glue Component to Adobe's Interpreter (specification). + * + * Copyright 2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSFT_H_ +#define PSFT_H_ + + +#include +#include "pstypes.h" + + /* TODO: disable asserts for now */ +#define CF2_NDEBUG + + +#include + +#include "psglue.h" +#include /* for PS_Decoder */ + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + cf2_decoder_parse_charstrings( PS_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + + FT_LOCAL( CFF_SubFont ) + cf2_getSubfont( PS_Decoder* decoder ); + + FT_LOCAL( CFF_VStore ) + cf2_getVStore( PS_Decoder* decoder ); + + FT_LOCAL( FT_UInt ) + cf2_getMaxstack( PS_Decoder* decoder ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cf2_getNormalizedVector( PS_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ); +#endif + + FT_LOCAL( CF2_Fixed ) + cf2_getPpemY( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getStdVW( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getStdHW( PS_Decoder* decoder ); + + FT_LOCAL( void ) + cf2_getBlueMetrics( PS_Decoder* decoder, + CF2_Fixed* blueScale, + CF2_Fixed* blueShift, + CF2_Fixed* blueFuzz ); + FT_LOCAL( void ) + cf2_getBlueValues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ); + FT_LOCAL( void ) + cf2_getOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ); + FT_LOCAL( void ) + cf2_getFamilyBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ); + FT_LOCAL( void ) + cf2_getFamilyOtherBlues( PS_Decoder* decoder, + size_t* count, + FT_Fixed* *data ); + + FT_LOCAL( CF2_Int ) + cf2_getLanguageGroup( PS_Decoder* decoder ); + + FT_LOCAL( CF2_Int ) + cf2_initGlobalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ); + FT_LOCAL( FT_Error ) + cf2_getSeacComponent( PS_Decoder* decoder, + CF2_Int code, + CF2_Buffer buf ); + FT_LOCAL( void ) + cf2_freeSeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ); + FT_LOCAL( CF2_Int ) + cf2_initLocalRegionBuffer( PS_Decoder* decoder, + CF2_Int subrNum, + CF2_Buffer buf ); + + FT_LOCAL( CF2_Fixed ) + cf2_getDefaultWidthX( PS_Decoder* decoder ); + FT_LOCAL( CF2_Fixed ) + cf2_getNominalWidthX( PS_Decoder* decoder ); + + + FT_LOCAL( FT_Error ) + cf2_getT1SeacComponent( PS_Decoder* decoder, + FT_UInt glyph_index, + CF2_Buffer buf ); + FT_LOCAL( void ) + cf2_freeT1SeacComponent( PS_Decoder* decoder, + CF2_Buffer buf ); + + /* + * FreeType client outline + * + * process output from the charstring interpreter + */ + typedef struct CF2_OutlineRec_ + { + CF2_OutlineCallbacksRec root; /* base class must be first */ + PS_Decoder* decoder; + + } CF2_OutlineRec, *CF2_Outline; + + + FT_LOCAL( void ) + cf2_outline_reset( CF2_Outline outline ); + FT_LOCAL( void ) + cf2_outline_close( CF2_Outline outline ); + + +FT_END_HEADER + + +#endif /* PSFT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psglue.h b/Dependencies/freetype/freetype/src/psaux/psglue.h new file mode 100644 index 00000000..63085d71 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psglue.h @@ -0,0 +1,144 @@ +/**************************************************************************** + * + * psglue.h + * + * Adobe's code for shared stuff (specification only). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSGLUE_H_ +#define PSGLUE_H_ + + +/* common includes for other modules */ +#include "pserror.h" +#include "psfixed.h" +#include "psarrst.h" +#include "psread.h" + + +FT_BEGIN_HEADER + + + /* rendering parameters */ + + /* apply hints to rendered glyphs */ +#define CF2_FlagsHinted 1 + /* for testing */ +#define CF2_FlagsDarkened 2 + + /* type for holding the flags */ + typedef CF2_Int CF2_RenderingFlags; + + + /* elements of a glyph outline */ + typedef enum CF2_PathOp_ + { + CF2_PathOpMoveTo = 1, /* change the current point */ + CF2_PathOpLineTo = 2, /* line */ + CF2_PathOpQuadTo = 3, /* quadratic curve */ + CF2_PathOpCubeTo = 4 /* cubic curve */ + + } CF2_PathOp; + + + /* a matrix of fixed-point values */ + typedef struct CF2_Matrix_ + { + CF2_F16Dot16 a; + CF2_F16Dot16 b; + CF2_F16Dot16 c; + CF2_F16Dot16 d; + CF2_F16Dot16 tx; + CF2_F16Dot16 ty; + + } CF2_Matrix; + + + /* these typedefs are needed by more than one header file */ + /* and gcc compiler doesn't allow redefinition */ + typedef struct CF2_FontRec_ CF2_FontRec, *CF2_Font; + typedef struct CF2_HintRec_ CF2_HintRec, *CF2_Hint; + + + /* A common structure for all callback parameters. */ + /* */ + /* Some members may be unused. For example, `pt0' is not used for */ + /* `moveTo' and `pt3' is not used for `quadTo'. The initial point `pt0' */ + /* is included for each path element for generality; curve conversions */ + /* need it. The `op' parameter allows one function to handle multiple */ + /* element types. */ + + typedef struct CF2_CallbackParamsRec_ + { + FT_Vector pt0; + FT_Vector pt1; + FT_Vector pt2; + FT_Vector pt3; + + CF2_Int op; + + } CF2_CallbackParamsRec, *CF2_CallbackParams; + + + /* forward reference */ + typedef struct CF2_OutlineCallbacksRec_ CF2_OutlineCallbacksRec, + *CF2_OutlineCallbacks; + + /* callback function pointers */ + typedef void + (*CF2_Callback_Type)( CF2_OutlineCallbacks callbacks, + const CF2_CallbackParams params ); + + + struct CF2_OutlineCallbacksRec_ + { + CF2_Callback_Type moveTo; + CF2_Callback_Type lineTo; + CF2_Callback_Type quadTo; + CF2_Callback_Type cubeTo; + + CF2_Int windingMomentum; /* for winding order detection */ + + FT_Memory memory; + FT_Error* error; + }; + + +FT_END_HEADER + + +#endif /* PSGLUE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/pshints.c b/Dependencies/freetype/freetype/src/psaux/pshints.c new file mode 100644 index 00000000..7bd08a9c --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/pshints.c @@ -0,0 +1,1952 @@ +/**************************************************************************** + * + * pshints.c + * + * Adobe's code for handling CFF hints (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psfont.h" +#include "pshints.h" +#include "psintrp.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2hints + + + typedef struct CF2_HintMoveRec_ + { + size_t j; /* index of upper hint map edge */ + CF2_Fixed moveUp; /* adjustment to optimum position */ + + } CF2_HintMoveRec, *CF2_HintMove; + + + /* Compute angular momentum for winding order detection. It is called */ + /* for all lines and curves, but not necessarily in element order. */ + static CF2_Int + cf2_getWindingMomentum( CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2 ) + { + /* cross product of pt1 position from origin with pt2 position from */ + /* pt1; we reduce the precision so that the result fits into 32 bits */ + + return ( x1 >> 16 ) * ( SUB_INT32( y2, y1 ) >> 16 ) - + ( y1 >> 16 ) * ( SUB_INT32( x2, x1 ) >> 16 ); + } + + + /* + * Construct from a StemHint; this is used as a parameter to + * `cf2_blues_capture'. + * `hintOrigin' is the character space displacement of a seac accent. + * Adjust stem hint for darkening here. + * + */ + static void + cf2_hint_init( CF2_Hint hint, + const CF2_ArrStack stemHintArray, + size_t indexStemHint, + const CF2_Font font, + CF2_Fixed hintOrigin, + CF2_Fixed scale, + FT_Bool bottom ) + { + CF2_Fixed width; + const CF2_StemHintRec* stemHint; + + + FT_ZERO( hint ); + + stemHint = (const CF2_StemHintRec*)cf2_arrstack_getPointer( + stemHintArray, + indexStemHint ); + + width = SUB_INT32( stemHint->max, stemHint->min ); + + if ( width == cf2_intToFixed( -21 ) ) + { + /* ghost bottom */ + + if ( bottom ) + { + hint->csCoord = stemHint->max; + hint->flags = CF2_GhostBottom; + } + else + hint->flags = 0; + } + + else if ( width == cf2_intToFixed( -20 ) ) + { + /* ghost top */ + + if ( bottom ) + hint->flags = 0; + else + { + hint->csCoord = stemHint->min; + hint->flags = CF2_GhostTop; + } + } + + else if ( width < 0 ) + { + /* inverted pair */ + + /* + * Hints with negative widths were produced by an early version of a + * non-Adobe font tool. The Type 2 spec allows edge (ghost) hints + * with negative widths, but says + * + * All other negative widths have undefined meaning. + * + * CoolType has a silent workaround that negates the hint width; for + * permissive mode, we do the same here. + * + * Note: Such fonts cannot use ghost hints, but should otherwise work. + * Note: Some poor hints in our faux fonts can produce negative + * widths at some blends. For example, see a light weight of + * `u' in ASerifMM. + * + */ + if ( bottom ) + { + hint->csCoord = stemHint->max; + hint->flags = CF2_PairBottom; + } + else + { + hint->csCoord = stemHint->min; + hint->flags = CF2_PairTop; + } + } + + else + { + /* normal pair */ + + if ( bottom ) + { + hint->csCoord = stemHint->min; + hint->flags = CF2_PairBottom; + } + else + { + hint->csCoord = stemHint->max; + hint->flags = CF2_PairTop; + } + } + + /* Now that ghost hints have been detected, adjust this edge for */ + /* darkening. Bottoms are not changed; tops are incremented by twice */ + /* `darkenY'. */ + if ( cf2_hint_isTop( hint ) ) + hint->csCoord = ADD_INT32( hint->csCoord, 2 * font->darkenY ); + + hint->csCoord = ADD_INT32( hint->csCoord, hintOrigin ); + hint->scale = scale; + hint->index = indexStemHint; /* index in original stem hint array */ + + /* if original stem hint has been used, use the same position */ + if ( hint->flags != 0 && stemHint->used ) + { + if ( cf2_hint_isTop( hint ) ) + hint->dsCoord = stemHint->maxDS; + else + hint->dsCoord = stemHint->minDS; + + cf2_hint_lock( hint ); + } + else + hint->dsCoord = FT_MulFix( hint->csCoord, scale ); + } + + + /* initialize an invalid hint map element */ + static void + cf2_hint_initZero( CF2_Hint hint ) + { + FT_ZERO( hint ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isValid( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags ); + } + + + static FT_Bool + cf2_hint_isPair( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_PairTop ) ); + } + + + static FT_Bool + cf2_hint_isPairTop( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_PairTop ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isTop( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairTop | CF2_GhostTop ) ); + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hint_isBottom( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_GhostBottom ) ); + } + + + static FT_Bool + cf2_hint_isLocked( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_Locked ); + } + + + static FT_Bool + cf2_hint_isSynthetic( const CF2_Hint hint ) + { + return FT_BOOL( hint->flags & CF2_Synthetic ); + } + + + FT_LOCAL_DEF( void ) + cf2_hint_lock( CF2_Hint hint ) + { + hint->flags |= CF2_Locked; + } + + + FT_LOCAL_DEF( void ) + cf2_hintmap_init( CF2_HintMap hintmap, + CF2_Font font, + CF2_HintMap initialMap, + CF2_ArrStack hintMoves, + CF2_Fixed scale ) + { + FT_ZERO( hintmap ); + + /* copy parameters from font instance */ + hintmap->hinted = font->hinted; + hintmap->scale = scale; + hintmap->font = font; + hintmap->initialHintMap = initialMap; + /* will clear in `cf2_hintmap_adjustHints' */ + hintmap->hintMoves = hintMoves; + } + + + static FT_Bool + cf2_hintmap_isValid( const CF2_HintMap hintmap ) + { + return hintmap->isValid; + } + + + static void + cf2_hintmap_dump( CF2_HintMap hintmap ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + CF2_UInt i; + + + FT_TRACE6(( " index csCoord dsCoord scale flags\n" )); + + for ( i = 0; i < hintmap->count; i++ ) + { + CF2_Hint hint = &hintmap->edge[i]; + + + FT_TRACE6(( " %3zu %7.2f %7.2f %5d %s%s%s%s\n", + hint->index, + hint->csCoord / 65536.0, + hint->dsCoord / ( hint->scale * 1.0 ), + hint->scale, + ( cf2_hint_isPair( hint ) ? "p" : "g" ), + ( cf2_hint_isTop( hint ) ? "t" : "b" ), + ( cf2_hint_isLocked( hint ) ? "L" : ""), + ( cf2_hint_isSynthetic( hint ) ? "S" : "" ) )); + } +#else + FT_UNUSED( hintmap ); +#endif + } + + + /* transform character space coordinate to device space using hint map */ + static CF2_Fixed + cf2_hintmap_map( CF2_HintMap hintmap, + CF2_Fixed csCoord ) + { + if ( hintmap->count == 0 || !hintmap->hinted ) + { + /* there are no hints; use uniform scale and zero offset */ + return FT_MulFix( csCoord, hintmap->scale ); + } + else + { + /* start linear search from last hit */ + CF2_UInt i = hintmap->lastIndex; + + + FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES ); + + /* search up */ + while ( i < hintmap->count - 1 && + csCoord >= hintmap->edge[i + 1].csCoord ) + i += 1; + + /* search down */ + while ( i > 0 && csCoord < hintmap->edge[i].csCoord ) + i -= 1; + + hintmap->lastIndex = i; + + if ( i == 0 && csCoord < hintmap->edge[0].csCoord ) + { + /* special case for points below first edge: use uniform scale */ + return ADD_INT32( FT_MulFix( SUB_INT32( csCoord, + hintmap->edge[0].csCoord ), + hintmap->scale ), + hintmap->edge[0].dsCoord ); + } + else + { + /* + * Note: entries with duplicate csCoord are allowed. + * Use edge[i], the highest entry where csCoord >= entry[i].csCoord + */ + return ADD_INT32( FT_MulFix( SUB_INT32( csCoord, + hintmap->edge[i].csCoord ), + hintmap->edge[i].scale ), + hintmap->edge[i].dsCoord ); + } + } + } + + + /* + * This hinting policy moves a hint pair in device space so that one of + * its two edges is on a device pixel boundary (its fractional part is + * zero). `cf2_hintmap_insertHint' guarantees no overlap in CS + * space. Ensure here that there is no overlap in DS. + * + * In the first pass, edges are adjusted relative to adjacent hints. + * Those that are below have already been adjusted. Those that are + * above have not yet been adjusted. If a hint above blocks an + * adjustment to an optimal position, we will try again in a second + * pass. The second pass is top-down. + * + */ + + static void + cf2_hintmap_adjustHints( CF2_HintMap hintmap ) + { + size_t i, j; + + + cf2_arrstack_clear( hintmap->hintMoves ); /* working storage */ + + /* + * First pass is bottom-up (font hint order) without look-ahead. + * Locked edges are already adjusted. + * Unlocked edges begin with dsCoord from `initialHintMap'. + * Save edges that are not optimally adjusted in `hintMoves' array, + * and process them in second pass. + */ + + for ( i = 0; i < hintmap->count; i++ ) + { + FT_Bool isPair = cf2_hint_isPair( &hintmap->edge[i] ); + + /* final amount to move edge or edge pair */ + CF2_Fixed move = 0; + + CF2_Fixed dsCoord_i; + CF2_Fixed dsCoord_j; + + + /* index of upper edge (same value for ghost hint) */ + j = isPair ? i + 1 : i; + + FT_ASSERT( j < hintmap->count ); + FT_ASSERT( cf2_hint_isValid( &hintmap->edge[i] ) ); + FT_ASSERT( cf2_hint_isValid( &hintmap->edge[j] ) ); + FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) == + cf2_hint_isLocked( &hintmap->edge[j] ) ); + + dsCoord_i = hintmap->edge[i].dsCoord; + dsCoord_j = hintmap->edge[j].dsCoord; + + if ( !cf2_hint_isLocked( &hintmap->edge[i] ) ) + { + /* hint edge is not locked, we can adjust it */ + CF2_Fixed fracDown = cf2_fixedFraction( dsCoord_i ); + CF2_Fixed fracUp = cf2_fixedFraction( dsCoord_j ); + + /* calculate all four possibilities; moves down are negative */ + CF2_Fixed downMoveDown = 0 - fracDown; + CF2_Fixed upMoveDown = 0 - fracUp; + CF2_Fixed downMoveUp = ( fracDown == 0 ) + ? 0 + : cf2_intToFixed( 1 ) - fracDown; + CF2_Fixed upMoveUp = ( fracUp == 0 ) + ? 0 + : cf2_intToFixed( 1 ) - fracUp; + + /* smallest move up */ + CF2_Fixed moveUp = FT_MIN( downMoveUp, upMoveUp ); + /* smallest move down */ + CF2_Fixed moveDown = FT_MAX( downMoveDown, upMoveDown ); + + CF2_Fixed downMinCounter = CF2_MIN_COUNTER; + CF2_Fixed upMinCounter = CF2_MIN_COUNTER; + FT_Bool saveEdge = FALSE; + + + /* minimum counter constraint doesn't apply when adjacent edges */ + /* are synthetic */ + /* TODO: doesn't seem a big effect; for now, reduce the code */ +#if 0 + if ( i == 0 || + cf2_hint_isSynthetic( &hintmap->edge[i - 1] ) ) + downMinCounter = 0; + + if ( j >= hintmap->count - 1 || + cf2_hint_isSynthetic( &hintmap->edge[j + 1] ) ) + upMinCounter = 0; +#endif + + /* is there room to move up? */ + /* there is if we are at top of array or the next edge is at or */ + /* beyond proposed move up? */ + if ( j >= hintmap->count - 1 || + hintmap->edge[j + 1].dsCoord >= + ADD_INT32( dsCoord_j, moveUp + upMinCounter ) ) + { + /* there is room to move up; is there also room to move down? */ + if ( i == 0 || + hintmap->edge[i - 1].dsCoord <= + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) + { + /* move smaller absolute amount */ + move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */ + } + else + move = moveUp; + } + else + { + /* is there room to move down? */ + if ( i == 0 || + hintmap->edge[i - 1].dsCoord <= + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) + { + move = moveDown; + /* true if non-optimum move */ + saveEdge = FT_BOOL( moveUp < -moveDown ); + } + else + { + /* no room to move either way without overlapping or reducing */ + /* the counter too much */ + move = 0; + saveEdge = TRUE; + } + } + + /* Identify non-moves and moves down that aren't optimal, and save */ + /* them for second pass. */ + /* Do this only if there is an unlocked edge above (which could */ + /* possibly move). */ + if ( saveEdge && + j < hintmap->count - 1 && + !cf2_hint_isLocked( &hintmap->edge[j + 1] ) ) + { + CF2_HintMoveRec savedMove; + + + savedMove.j = j; + /* desired adjustment in second pass */ + savedMove.moveUp = moveUp - move; + + cf2_arrstack_push( hintmap->hintMoves, &savedMove ); + } + + /* move the edge(s) */ + hintmap->edge[i].dsCoord = ADD_INT32( dsCoord_i, move ); + if ( isPair ) + hintmap->edge[j].dsCoord = ADD_INT32( dsCoord_j, move ); + } + + /* assert there are no overlaps in device space; */ + /* ignore tests if there was overflow (that is, if */ + /* operands have the same sign but the sum does not) */ + FT_ASSERT( i == 0 || + ( ( dsCoord_i ^ move ) >= 0 && + ( dsCoord_i ^ hintmap->edge[i].dsCoord ) < 0 ) || + hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord ); + FT_ASSERT( i < j || + ( ( dsCoord_j ^ move ) >= 0 && + ( dsCoord_j ^ hintmap->edge[j].dsCoord ) < 0 ) || + hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord ); + + /* adjust the scales, avoiding divide by zero */ + if ( i > 0 ) + { + if ( hintmap->edge[i].csCoord != hintmap->edge[i - 1].csCoord ) + hintmap->edge[i - 1].scale = + FT_DivFix( SUB_INT32( hintmap->edge[i].dsCoord, + hintmap->edge[i - 1].dsCoord ), + SUB_INT32( hintmap->edge[i].csCoord, + hintmap->edge[i - 1].csCoord ) ); + } + + if ( isPair ) + { + if ( hintmap->edge[j].csCoord != hintmap->edge[j - 1].csCoord ) + hintmap->edge[j - 1].scale = + FT_DivFix( SUB_INT32( hintmap->edge[j].dsCoord, + hintmap->edge[j - 1].dsCoord ), + SUB_INT32( hintmap->edge[j].csCoord, + hintmap->edge[j - 1].csCoord ) ); + + i += 1; /* skip upper edge on next loop */ + } + } + + /* second pass tries to move non-optimal hints up, in case there is */ + /* room now */ + for ( i = cf2_arrstack_size( hintmap->hintMoves ); i > 0; i-- ) + { + CF2_HintMove hintMove = (CF2_HintMove) + cf2_arrstack_getPointer( hintmap->hintMoves, i - 1 ); + + + j = hintMove->j; + + /* this was tested before the push, above */ + FT_ASSERT( j < hintmap->count - 1 ); + + /* is there room to move up? */ + if ( hintmap->edge[j + 1].dsCoord >= + ADD_INT32( hintmap->edge[j].dsCoord, + hintMove->moveUp + CF2_MIN_COUNTER ) ) + { + /* there is more room now, move edge up */ + hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord, + hintMove->moveUp ); + + if ( cf2_hint_isPair( &hintmap->edge[j] ) ) + { + FT_ASSERT( j > 0 ); + hintmap->edge[j - 1].dsCoord = + ADD_INT32( hintmap->edge[j - 1].dsCoord, hintMove->moveUp ); + } + } + } + } + + + /* insert hint edges into map, sorted by csCoord */ + static void + cf2_hintmap_insertHint( CF2_HintMap hintmap, + CF2_Hint bottomHintEdge, + CF2_Hint topHintEdge ) + { + CF2_UInt indexInsert; + + /* set default values, then check for edge hints */ + FT_Bool isPair = TRUE; + CF2_Hint firstHintEdge = bottomHintEdge; + CF2_Hint secondHintEdge = topHintEdge; + + + /* one or none of the input params may be invalid when dealing with */ + /* edge hints; at least one edge must be valid */ + FT_ASSERT( cf2_hint_isValid( bottomHintEdge ) || + cf2_hint_isValid( topHintEdge ) ); + + /* determine how many and which edges to insert */ + if ( !cf2_hint_isValid( bottomHintEdge ) ) + { + /* insert only the top edge */ + firstHintEdge = topHintEdge; + isPair = FALSE; + } + else if ( !cf2_hint_isValid( topHintEdge ) ) + { + /* insert only the bottom edge */ + isPair = FALSE; + } + + /* paired edges must be in proper order */ + if ( isPair && + topHintEdge->csCoord < bottomHintEdge->csCoord ) + return; + + /* linear search to find index value of insertion point */ + indexInsert = 0; + for ( ; indexInsert < hintmap->count; indexInsert++ ) + { + if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord ) + break; + } + + FT_TRACE7(( " Got hint at %.2f (%.2f)\n", + firstHintEdge->csCoord / 65536.0, + firstHintEdge->dsCoord / 65536.0 )); + if ( isPair ) + FT_TRACE7(( " Got hint at %.2f (%.2f)\n", + secondHintEdge->csCoord / 65536.0, + secondHintEdge->dsCoord / 65536.0 )); + + /* + * Discard any hints that overlap in character space. Most often, this + * is while building the initial map, where captured hints from all + * zones are combined. Define overlap to include hints that `touch' + * (overlap zero). Hiragino Sans/Gothic fonts have numerous hints that + * touch. Some fonts have non-ideographic glyphs that overlap our + * synthetic hints. + * + * Overlap also occurs when darkening stem hints that are close. + * + */ + if ( indexInsert < hintmap->count ) + { + /* we are inserting before an existing edge: */ + /* verify that an existing edge is not the same */ + if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord ) + return; /* ignore overlapping stem hint */ + + /* verify that a new pair does not straddle the next edge */ + if ( isPair && + hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord ) + return; /* ignore overlapping stem hint */ + + /* verify that we are not inserting between paired edges */ + if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) ) + return; /* ignore overlapping stem hint */ + } + + /* recompute device space locations using initial hint map */ + if ( cf2_hintmap_isValid( hintmap->initialHintMap ) && + !cf2_hint_isLocked( firstHintEdge ) ) + { + if ( isPair ) + { + /* Use hint map to position the center of stem, and nominal scale */ + /* to position the two edges. This preserves the stem width. */ + CF2_Fixed midpoint = + cf2_hintmap_map( + hintmap->initialHintMap, + ADD_INT32( + firstHintEdge->csCoord, + SUB_INT32 ( secondHintEdge->csCoord, + firstHintEdge->csCoord ) / 2 ) ); + CF2_Fixed halfWidth = + FT_MulFix( SUB_INT32( secondHintEdge->csCoord, + firstHintEdge->csCoord ) / 2, + hintmap->scale ); + + + firstHintEdge->dsCoord = SUB_INT32( midpoint, halfWidth ); + secondHintEdge->dsCoord = ADD_INT32( midpoint, halfWidth ); + } + else + firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap, + firstHintEdge->csCoord ); + } + + /* + * Discard any hints that overlap in device space; this can occur + * because locked hints have been moved to align with blue zones. + * + * TODO: Although we might correct this later during adjustment, we + * don't currently have a way to delete a conflicting hint once it has + * been inserted. See v2.030 MinionPro-Regular, 12 ppem darkened, + * initial hint map for second path, glyph 945 (the perispomeni (tilde) + * in U+1F6E, Greek omega with psili and perispomeni). Darkening is + * 25. Pair 667,747 initially conflicts in design space with top edge + * 660. This is because 667 maps to 7.87, and the top edge was + * captured by a zone at 8.0. The pair is later successfully inserted + * in a zone without the top edge. In this zone it is adjusted to 8.0, + * and no longer conflicts with the top edge in design space. This + * means it can be included in yet a later zone which does have the top + * edge hint. This produces a small mismatch between the first and + * last points of this path, even though the hint masks are the same. + * The density map difference is tiny (1/256). + * + */ + + if ( indexInsert > 0 ) + { + /* we are inserting after an existing edge */ + if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord ) + return; + } + + if ( indexInsert < hintmap->count ) + { + /* we are inserting before an existing edge */ + if ( isPair ) + { + if ( secondHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord ) + return; + } + else + { + if ( firstHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord ) + return; + } + } + + /* make room to insert */ + { + CF2_UInt iSrc = hintmap->count - 1; + CF2_UInt iDst = isPair ? hintmap->count + 1 : hintmap->count; + + CF2_UInt count = hintmap->count - indexInsert; + + + if ( iDst >= CF2_MAX_HINT_EDGES ) + { + FT_TRACE4(( "cf2_hintmap_insertHint: too many hintmaps\n" )); + return; + } + + while ( count-- ) + hintmap->edge[iDst--] = hintmap->edge[iSrc--]; + + /* insert first edge */ + hintmap->edge[indexInsert] = *firstHintEdge; /* copy struct */ + hintmap->count += 1; + + FT_TRACE7(( " Inserting hint %.2f (%.2f)\n", + firstHintEdge->csCoord / 65536.0, + firstHintEdge->dsCoord / 65536.0 )); + + if ( isPair ) + { + /* insert second edge */ + hintmap->edge[indexInsert + 1] = *secondHintEdge; /* copy struct */ + hintmap->count += 1; + + FT_TRACE7(( " Inserting hint %.2f (%.2f)\n", + secondHintEdge->csCoord / 65536.0, + secondHintEdge->dsCoord / 65536.0 )); + + } + } + + return; + } + + + /* + * Build a map from hints and mask. + * + * This function may recur one level if `hintmap->initialHintMap' is not yet + * valid. + * If `initialMap' is true, simply build initial map. + * + * Synthetic hints are used in two ways. A hint at zero is inserted, if + * needed, in the initial hint map, to prevent translations from + * propagating across the origin. If synthetic em box hints are enabled + * for ideographic dictionaries, then they are inserted in all hint + * maps, including the initial one. + * + */ + FT_LOCAL_DEF( void ) + cf2_hintmap_build( CF2_HintMap hintmap, + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + FT_Bool initialMap ) + { + FT_Byte* maskPtr; + + CF2_Font font = hintmap->font; + CF2_HintMaskRec tempHintMask; + + size_t bitCount, i; + FT_Byte maskByte; + + + /* check whether initial map is constructed */ + if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) ) + { + /* make recursive call with initialHintMap and temporary mask; */ + /* temporary mask will get all bits set, below */ + cf2_hintmask_init( &tempHintMask, hintMask->error ); + cf2_hintmap_build( hintmap->initialHintMap, + hStemHintArray, + vStemHintArray, + &tempHintMask, + hintOrigin, + TRUE ); + } + + if ( !cf2_hintmask_isValid( hintMask ) ) + { + /* without a hint mask, assume all hints are active */ + cf2_hintmask_setAll( hintMask, + cf2_arrstack_size( hStemHintArray ) + + cf2_arrstack_size( vStemHintArray ) ); + if ( !cf2_hintmask_isValid( hintMask ) ) + { + if ( font->isT1 ) + { + /* no error, just continue unhinted */ + *hintMask->error = FT_Err_Ok; + hintmap->hinted = FALSE; + } + return; /* too many stem hints */ + } + } + + /* begin by clearing the map */ + hintmap->count = 0; + hintmap->lastIndex = 0; + + /* make a copy of the hint mask so we can modify it */ + tempHintMask = *hintMask; + maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); + + /* use the hStem hints only, which are first in the mask */ + bitCount = cf2_arrstack_size( hStemHintArray ); + + /* Defense-in-depth. Should never return here. */ + if ( bitCount > hintMask->bitCount ) + return; + + /* synthetic embox hints get highest priority */ + if ( font->blues.doEmBoxHints ) + { + CF2_HintRec dummy; + + + cf2_hint_initZero( &dummy ); /* invalid hint map element */ + + /* ghost bottom */ + cf2_hintmap_insertHint( hintmap, + &font->blues.emBoxBottomEdge, + &dummy ); + /* ghost top */ + cf2_hintmap_insertHint( hintmap, + &dummy, + &font->blues.emBoxTopEdge ); + } + + /* insert hints captured by a blue zone or already locked (higher */ + /* priority) */ + for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) + { + if ( maskByte & *maskPtr ) + { + /* expand StemHint into two `CF2_Hint' elements */ + CF2_HintRec bottomHintEdge, topHintEdge; + + + cf2_hint_init( &bottomHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + TRUE /* bottom */ ); + cf2_hint_init( &topHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + FALSE /* top */ ); + + if ( cf2_hint_isLocked( &bottomHintEdge ) || + cf2_hint_isLocked( &topHintEdge ) || + cf2_blues_capture( &font->blues, + &bottomHintEdge, + &topHintEdge ) ) + { + /* insert captured hint into map */ + cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); + + *maskPtr &= ~maskByte; /* turn off the bit for this hint */ + } + } + + if ( ( i & 7 ) == 7 ) + { + /* move to next mask byte */ + maskPtr++; + maskByte = 0x80; + } + else + maskByte >>= 1; + } + + /* initial hint map includes only captured hints plus maybe one at 0 */ + + /* + * TODO: There is a problem here because we are trying to build a + * single hint map containing all captured hints. It is + * possible for there to be conflicts between captured hints, + * either because of darkening or because the hints are in + * separate hint zones (we are ignoring hint zones for the + * initial map). An example of the latter is MinionPro-Regular + * v2.030 glyph 883 (Greek Capital Alpha with Psili) at 15ppem. + * A stem hint for the psili conflicts with the top edge hint + * for the base character. The stem hint gets priority because + * of its sort order. In glyph 884 (Greek Capital Alpha with + * Psili and Oxia), the top of the base character gets a stem + * hint, and the psili does not. This creates different initial + * maps for the two glyphs resulting in different renderings of + * the base character. Will probably defer this either as not + * worth the cost or as a font bug. I don't think there is any + * good reason for an accent to be captured by an alignment + * zone. -darnold 2/12/10 + */ + + if ( initialMap ) + { + /* Apply a heuristic that inserts a point for (0,0), unless it's */ + /* already covered by a mapping. This locks the baseline for glyphs */ + /* that have no baseline hints. */ + + if ( hintmap->count == 0 || + hintmap->edge[0].csCoord > 0 || + hintmap->edge[hintmap->count - 1].csCoord < 0 ) + { + /* all edges are above 0 or all edges are below 0; */ + /* construct a locked edge hint at 0 */ + + CF2_HintRec edge, invalid; + + + cf2_hint_initZero( &edge ); + + edge.flags = CF2_GhostBottom | + CF2_Locked | + CF2_Synthetic; + edge.scale = hintmap->scale; + + cf2_hint_initZero( &invalid ); + cf2_hintmap_insertHint( hintmap, &edge, &invalid ); + } + } + else + { + /* insert remaining hints */ + + maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask ); + + for ( i = 0, maskByte = 0x80; i < bitCount; i++ ) + { + if ( maskByte & *maskPtr ) + { + CF2_HintRec bottomHintEdge, topHintEdge; + + + cf2_hint_init( &bottomHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + TRUE /* bottom */ ); + cf2_hint_init( &topHintEdge, + hStemHintArray, + i, + font, + hintOrigin, + hintmap->scale, + FALSE /* top */ ); + + cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge ); + } + + if ( ( i & 7 ) == 7 ) + { + /* move to next mask byte */ + maskPtr++; + maskByte = 0x80; + } + else + maskByte >>= 1; + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( initialMap ) + { + FT_TRACE6(( "flags: [p]air [g]host [t]op" + " [b]ottom [L]ocked [S]ynthetic\n" )); + FT_TRACE6(( "Initial hintmap:\n" )); + } + else + FT_TRACE6(( "Hints:\n" )); +#endif + + cf2_hintmap_dump( hintmap ); + + /* + * Note: The following line is a convenient place to break when + * debugging hinting. Examine `hintmap->edge' for the list of + * enabled hints, then step over the call to see the effect of + * adjustment. We stop here first on the recursive call that + * creates the initial map, and then on each counter group and + * hint zone. + */ + + /* adjust positions of hint edges that are not locked to blue zones */ + cf2_hintmap_adjustHints( hintmap ); + + FT_TRACE6(( "Hints adjusted:\n" )); + cf2_hintmap_dump( hintmap ); + + /* save the position of all hints that were used in this hint map; */ + /* if we use them again, we'll locate them in the same position */ + if ( !initialMap ) + { + for ( i = 0; i < hintmap->count; i++ ) + { + if ( !cf2_hint_isSynthetic( &hintmap->edge[i] ) ) + { + /* Note: include both valid and invalid edges */ + /* Note: top and bottom edges are copied back separately */ + CF2_StemHint stemhint = (CF2_StemHint) + cf2_arrstack_getPointer( hStemHintArray, + hintmap->edge[i].index ); + + + if ( cf2_hint_isTop( &hintmap->edge[i] ) ) + stemhint->maxDS = hintmap->edge[i].dsCoord; + else + stemhint->minDS = hintmap->edge[i].dsCoord; + + stemhint->used = TRUE; + } + } + } + + /* hint map is ready to use */ + hintmap->isValid = TRUE; + + /* remember this mask has been used */ + cf2_hintmask_setNew( hintMask, FALSE ); + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_init( CF2_GlyphPath glyphpath, + CF2_Font font, + CF2_OutlineCallbacks callbacks, + CF2_Fixed scaleY, + /* CF2_Fixed hShift, */ + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOriginY, + const CF2_Blues blues, + const FT_Vector* fractionalTranslation ) + { + FT_ZERO( glyphpath ); + + glyphpath->font = font; + glyphpath->callbacks = callbacks; + + cf2_arrstack_init( &glyphpath->hintMoves, + font->memory, + &font->error, + sizeof ( CF2_HintMoveRec ) ); + + cf2_hintmap_init( &glyphpath->initialHintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + cf2_hintmap_init( &glyphpath->firstHintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + cf2_hintmap_init( &glyphpath->hintMap, + font, + &glyphpath->initialHintMap, + &glyphpath->hintMoves, + scaleY ); + + glyphpath->scaleX = font->innerTransform.a; + glyphpath->scaleC = font->innerTransform.c; + glyphpath->scaleY = font->innerTransform.d; + + glyphpath->fractionalTranslation = *fractionalTranslation; + +#if 0 + glyphpath->hShift = hShift; /* for fauxing */ +#endif + + glyphpath->hStemHintArray = hStemHintArray; + glyphpath->vStemHintArray = vStemHintArray; + glyphpath->hintMask = hintMask; /* ptr to current mask */ + glyphpath->hintOriginY = hintOriginY; + glyphpath->blues = blues; + glyphpath->darken = font->darkened; /* TODO: should we make copies? */ + glyphpath->xOffset = font->darkenX; + glyphpath->yOffset = font->darkenY; + glyphpath->miterLimit = 2 * FT_MAX( + cf2_fixedAbs( glyphpath->xOffset ), + cf2_fixedAbs( glyphpath->yOffset ) ); + + /* .1 character space unit */ + glyphpath->snapThreshold = cf2_doubleToFixed( 0.1 ); + + glyphpath->moveIsPending = TRUE; + glyphpath->pathIsOpen = FALSE; + glyphpath->pathIsClosing = FALSE; + glyphpath->elemIsQueued = FALSE; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ) + { + cf2_arrstack_finalize( &glyphpath->hintMoves ); + } + + + /* + * Hint point in y-direction and apply outerTransform. + * Input `current' hint map (which is actually delayed by one element). + * Input x,y point in Character Space. + * Output x,y point in Device Space, including translation. + */ + static void + cf2_glyphpath_hintPoint( CF2_GlyphPath glyphpath, + CF2_HintMap hintmap, + FT_Vector* ppt, + CF2_Fixed x, + CF2_Fixed y ) + { + FT_Vector pt; /* hinted point in upright DS */ + + + pt.x = ADD_INT32( FT_MulFix( glyphpath->scaleX, x ), + FT_MulFix( glyphpath->scaleC, y ) ); + pt.y = cf2_hintmap_map( hintmap, y ); + + ppt->x = ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.a, pt.x ), + ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.c, pt.y ), + glyphpath->fractionalTranslation.x ) ); + ppt->y = ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.b, pt.x ), + ADD_INT32( + FT_MulFix( glyphpath->font->outerTransform.d, pt.y ), + glyphpath->fractionalTranslation.y ) ); + } + + + /* + * From two line segments, (u1,u2) and (v1,v2), compute a point of + * intersection on the corresponding lines. + * Return false if no intersection is found, or if the intersection is + * too far away from the ends of the line segments, u2 and v1. + * + */ + static FT_Bool + cf2_glyphpath_computeIntersection( CF2_GlyphPath glyphpath, + const FT_Vector* u1, + const FT_Vector* u2, + const FT_Vector* v1, + const FT_Vector* v2, + FT_Vector* intersection ) + { + /* + * Let `u' be a zero-based vector from the first segment, `v' from the + * second segment. + * Let `w 'be the zero-based vector from `u1' to `v1'. + * `perp' is the `perpendicular dot product'; see + * https://mathworld.wolfram.com/PerpDotProduct.html. + * `s' is the parameter for the parametric line for the first segment + * (`u'). + * + * See notation in + * http://geomalgorithms.com/a05-_intersect-1.html. + * Calculations are done in 16.16, but must handle the squaring of + * line lengths in character space. We scale all vectors by 1/32 to + * avoid overflow. This allows values up to 4095 to be squared. The + * scale factor cancels in the divide. + * + * TODO: the scale factor could be computed from UnitsPerEm. + * + */ + +#define cf2_perp( a, b ) \ + ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) ) + + /* round and divide by 32 */ +#define CF2_CS_SCALE( x ) \ + ( ( (x) + 0x10 ) >> 5 ) + + FT_Vector u, v, w; /* scaled vectors */ + CF2_Fixed denominator, s; + + + u.x = CF2_CS_SCALE( SUB_INT32( u2->x, u1->x ) ); + u.y = CF2_CS_SCALE( SUB_INT32( u2->y, u1->y ) ); + v.x = CF2_CS_SCALE( SUB_INT32( v2->x, v1->x ) ); + v.y = CF2_CS_SCALE( SUB_INT32( v2->y, v1->y ) ); + w.x = CF2_CS_SCALE( SUB_INT32( v1->x, u1->x ) ); + w.y = CF2_CS_SCALE( SUB_INT32( v1->y, u1->y ) ); + + denominator = cf2_perp( u, v ); + + if ( denominator == 0 ) + return FALSE; /* parallel or coincident lines */ + + s = FT_DivFix( cf2_perp( w, v ), denominator ); + + intersection->x = ADD_INT32( u1->x, + FT_MulFix( s, SUB_INT32( u2->x, u1->x ) ) ); + intersection->y = ADD_INT32( u1->y, + FT_MulFix( s, SUB_INT32( u2->y, u1->y ) ) ); + + + /* + * Special case snapping for horizontal and vertical lines. + * This cleans up intersections and reduces problems with winding + * order detection. + * Sample case is sbc cd KozGoPr6N-Medium.otf 20 16685. + * Note: these calculations are in character space. + * + */ + + if ( u1->x == u2->x && + cf2_fixedAbs( SUB_INT32( intersection->x, + u1->x ) ) < glyphpath->snapThreshold ) + intersection->x = u1->x; + if ( u1->y == u2->y && + cf2_fixedAbs( SUB_INT32( intersection->y, + u1->y ) ) < glyphpath->snapThreshold ) + intersection->y = u1->y; + + if ( v1->x == v2->x && + cf2_fixedAbs( SUB_INT32( intersection->x, + v1->x ) ) < glyphpath->snapThreshold ) + intersection->x = v1->x; + if ( v1->y == v2->y && + cf2_fixedAbs( SUB_INT32( intersection->y, + v1->y ) ) < glyphpath->snapThreshold ) + intersection->y = v1->y; + + /* limit the intersection distance from midpoint of u2 and v1 */ + if ( cf2_fixedAbs( intersection->x - ADD_INT32( u2->x, v1->x ) / 2 ) > + glyphpath->miterLimit || + cf2_fixedAbs( intersection->y - ADD_INT32( u2->y, v1->y ) / 2 ) > + glyphpath->miterLimit ) + return FALSE; + + return TRUE; + } + + + /* + * Push the cached element (glyphpath->prevElem*) to the outline + * consumer. When a darkening offset is used, the end point of the + * cached element may be adjusted to an intersection point or we may + * synthesize a connecting line to the current element. If we are + * closing a subpath, we may also generate a connecting line to the start + * point. + * + * This is where Character Space (CS) is converted to Device Space (DS) + * using a hint map. This calculation must use a HintMap that was valid + * at the time the element was saved. For the first point in a subpath, + * that is a saved HintMap. For most elements, it just means the caller + * has delayed building a HintMap from the current HintMask. + * + * Transform each point with outerTransform and call the outline + * callbacks. This is a general 3x3 transform: + * + * x' = a*x + c*y + tx, y' = b*x + d*y + ty + * + * but it uses 4 elements from CF2_Font and the translation part + * from CF2_GlyphPath. + * + */ + static void + cf2_glyphpath_pushPrevElem( CF2_GlyphPath glyphpath, + CF2_HintMap hintmap, + FT_Vector* nextP0, + FT_Vector nextP1, + FT_Bool close ) + { + CF2_CallbackParamsRec params; + + FT_Vector* prevP0; + FT_Vector* prevP1; + + FT_Vector intersection = { 0, 0 }; + FT_Bool useIntersection = FALSE; + + + FT_ASSERT( glyphpath->prevElemOp == CF2_PathOpLineTo || + glyphpath->prevElemOp == CF2_PathOpCubeTo ); + + if ( glyphpath->prevElemOp == CF2_PathOpLineTo ) + { + prevP0 = &glyphpath->prevElemP0; + prevP1 = &glyphpath->prevElemP1; + } + else + { + prevP0 = &glyphpath->prevElemP2; + prevP1 = &glyphpath->prevElemP3; + } + + /* optimization: if previous and next elements are offset by the same */ + /* amount, then there will be no gap, and no need to compute an */ + /* intersection. */ + if ( prevP1->x != nextP0->x || prevP1->y != nextP0->y ) + { + /* previous element does not join next element: */ + /* adjust end point of previous element to the intersection */ + useIntersection = cf2_glyphpath_computeIntersection( glyphpath, + prevP0, + prevP1, + nextP0, + &nextP1, + &intersection ); + if ( useIntersection ) + { + /* modify the last point of the cached element (either line or */ + /* curve) */ + *prevP1 = intersection; + } + } + + params.pt0 = glyphpath->currentDS; + + switch( glyphpath->prevElemOp ) + { + case CF2_PathOpLineTo: + params.op = CF2_PathOpLineTo; + + /* note: pt2 and pt3 are unused */ + + if ( close ) + { + /* use first hint map if closing */ + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->firstHintMap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + } + else + { + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + } + + /* output only non-zero length lines */ + if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y ) + { + glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + } + break; + + case CF2_PathOpCubeTo: + params.op = CF2_PathOpCubeTo; + + /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */ + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + glyphpath->prevElemP1.x, + glyphpath->prevElemP1.y ); + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt2, + glyphpath->prevElemP2.x, + glyphpath->prevElemP2.y ); + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt3, + glyphpath->prevElemP3.x, + glyphpath->prevElemP3.y ); + + glyphpath->callbacks->cubeTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt3; + + break; + } + + if ( !useIntersection || close ) + { + /* insert connecting line between end of previous element and start */ + /* of current one */ + /* note: at the end of a subpath, we might do both, so use `nextP0' */ + /* before we change it, below */ + + if ( close ) + { + /* if we are closing the subpath, then nextP0 is in the first */ + /* hint zone */ + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->firstHintMap, + ¶ms.pt1, + nextP0->x, + nextP0->y ); + } + else + { + cf2_glyphpath_hintPoint( glyphpath, + hintmap, + ¶ms.pt1, + nextP0->x, + nextP0->y ); + } + + if ( params.pt1.x != glyphpath->currentDS.x || + params.pt1.y != glyphpath->currentDS.y ) + { + /* length is nonzero */ + params.op = CF2_PathOpLineTo; + params.pt0 = glyphpath->currentDS; + + /* note: pt2 and pt3 are unused */ + glyphpath->callbacks->lineTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + } + } + + if ( useIntersection ) + { + /* return intersection point to caller */ + *nextP0 = intersection; + } + } + + + /* push a MoveTo element based on current point and offset of current */ + /* element */ + static void + cf2_glyphpath_pushMove( CF2_GlyphPath glyphpath, + FT_Vector start ) + { + CF2_CallbackParamsRec params; + + + params.op = CF2_PathOpMoveTo; + params.pt0 = glyphpath->currentDS; + + /* Test if move has really happened yet; it would have called */ + /* `cf2_hintmap_build' to set `isValid'. */ + if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) ) + { + /* we are here iff first subpath is missing a moveto operator: */ + /* synthesize first moveTo to finish initialization of hintMap */ + cf2_glyphpath_moveTo( glyphpath, + glyphpath->start.x, + glyphpath->start.y ); + } + + cf2_glyphpath_hintPoint( glyphpath, + &glyphpath->hintMap, + ¶ms.pt1, + start.x, + start.y ); + + /* note: pt2 and pt3 are unused */ + glyphpath->callbacks->moveTo( glyphpath->callbacks, ¶ms ); + + glyphpath->currentDS = params.pt1; + glyphpath->offsetStart0 = start; + } + + + /* + * All coordinates are in character space. + * On input, (x1, y1) and (x2, y2) give line segment. + * On output, (x, y) give offset vector. + * We use a piecewise approximation to trig functions. + * + * TODO: Offset true perpendicular and proper length + * supply the y-translation for hinting here, too, + * that adds yOffset unconditionally to *y. + */ + static void + cf2_glyphpath_computeOffset( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed* x, + CF2_Fixed* y ) + { + CF2_Fixed dx = SUB_INT32( x2, x1 ); + CF2_Fixed dy = SUB_INT32( y2, y1 ); + + + /* note: negative offsets don't work here; negate deltas to change */ + /* quadrants, below */ + if ( glyphpath->font->reverseWinding ) + { + dx = NEG_INT32( dx ); + dy = NEG_INT32( dy ); + } + + *x = *y = 0; + + if ( !glyphpath->darken ) + return; + + /* add momentum for this path element */ + glyphpath->callbacks->windingMomentum = + ADD_INT32( glyphpath->callbacks->windingMomentum, + cf2_getWindingMomentum( x1, y1, x2, y2 ) ); + + /* note: allow mixed integer and fixed multiplication here */ + if ( dx >= 0 ) + { + if ( dy >= 0 ) + { + /* first quadrant, +x +y */ + + if ( dx > MUL_INT32( 2, dy ) ) + { + /* +x */ + *x = 0; + *y = 0; + } + else if ( dy > MUL_INT32( 2, dx ) ) + { + /* +y */ + *x = glyphpath->xOffset; + *y = glyphpath->yOffset; + } + else + { + /* +x +y */ + *x = FT_MulFix( cf2_doubleToFixed( 0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ), + glyphpath->yOffset ); + } + } + else + { + /* fourth quadrant, +x -y */ + + if ( dx > MUL_INT32( -2, dy ) ) + { + /* +x */ + *x = 0; + *y = 0; + } + else if ( NEG_INT32( dy ) > MUL_INT32( 2, dx ) ) + { + /* -y */ + *x = NEG_INT32( glyphpath->xOffset ); + *y = glyphpath->yOffset; + } + else + { + /* +x -y */ + *x = FT_MulFix( cf2_doubleToFixed( -0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ), + glyphpath->yOffset ); + } + } + } + else + { + if ( dy >= 0 ) + { + /* second quadrant, -x +y */ + + if ( NEG_INT32( dx ) > MUL_INT32( 2, dy ) ) + { + /* -x */ + *x = 0; + *y = MUL_INT32( 2, glyphpath->yOffset ); + } + else if ( dy > MUL_INT32( -2, dx ) ) + { + /* +y */ + *x = glyphpath->xOffset; + *y = glyphpath->yOffset; + } + else + { + /* -x +y */ + *x = FT_MulFix( cf2_doubleToFixed( 0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ), + glyphpath->yOffset ); + } + } + else + { + /* third quadrant, -x -y */ + + if ( NEG_INT32( dx ) > MUL_INT32( -2, dy ) ) + { + /* -x */ + *x = 0; + *y = MUL_INT32( 2, glyphpath->yOffset ); + } + else if ( NEG_INT32( dy ) > MUL_INT32( -2, dx ) ) + { + /* -y */ + *x = NEG_INT32( glyphpath->xOffset ); + *y = glyphpath->yOffset; + } + else + { + /* -x -y */ + *x = FT_MulFix( cf2_doubleToFixed( -0.7 ), + glyphpath->xOffset ); + *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ), + glyphpath->yOffset ); + } + } + } + } + + + /* + * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are + * called by the interpreter with Character Space (CS) coordinates. Each + * path element is placed into a queue of length one to await the + * calculation of the following element. At that time, the darkening + * offset of the following element is known and joins can be computed, + * including possible modification of this element, before mapping to + * Device Space (DS) and passing it on to the outline consumer. + * + */ + FT_LOCAL_DEF( void ) + cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ) + { + cf2_glyphpath_closeOpenPath( glyphpath ); + + /* save the parameters of the move for later, when we'll know how to */ + /* offset it; */ + /* also save last move point */ + glyphpath->currentCS.x = glyphpath->start.x = x; + glyphpath->currentCS.y = glyphpath->start.y = y; + + glyphpath->moveIsPending = TRUE; + + /* ensure we have a valid map with current mask */ + if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) || + cf2_hintmask_isNew( glyphpath->hintMask ) ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + /* save a copy of current HintMap to use when drawing initial point */ + glyphpath->firstHintMap = glyphpath->hintMap; /* structure copy */ + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ) + { + CF2_Fixed xOffset, yOffset; + FT_Vector P0, P1; + FT_Bool newHintMap; + + /* + * New hints will be applied after cf2_glyphpath_pushPrevElem has run. + * In case this is a synthesized closing line, any new hints should be + * delayed until this path is closed (`cf2_hintmask_isNew' will be + * called again before the next line or curve). + */ + + /* true if new hint map not on close */ + newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) && + !glyphpath->pathIsClosing; + + /* + * Zero-length lines may occur in the charstring. Because we cannot + * compute darkening offsets or intersections from zero-length lines, + * it is best to remove them and avoid artifacts. However, zero-length + * lines in CS at the start of a new hint map can generate non-zero + * lines in DS due to hint substitution. We detect a change in hint + * map here and pass those zero-length lines along. + */ + + /* + * Note: Find explicitly closed paths here with a conditional + * breakpoint using + * + * !gp->pathIsClosing && gp->start.x == x && gp->start.y == y + * + */ + + if ( glyphpath->currentCS.x == x && + glyphpath->currentCS.y == y && + !newHintMap ) + /* + * Ignore zero-length lines in CS where the hint map is the same + * because the line in DS will also be zero length. + * + * Ignore zero-length lines when we synthesize a closing line because + * the close will be handled in cf2_glyphPath_pushPrevElem. + */ + return; + + cf2_glyphpath_computeOffset( glyphpath, + glyphpath->currentCS.x, + glyphpath->currentCS.y, + x, + y, + &xOffset, + &yOffset ); + + /* construct offset points */ + P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset ); + P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset ); + P1.x = ADD_INT32( x, xOffset ); + P1.y = ADD_INT32( y, yOffset ); + + if ( glyphpath->moveIsPending ) + { + /* emit offset 1st point as MoveTo */ + cf2_glyphpath_pushMove( glyphpath, P0 ); + + glyphpath->moveIsPending = FALSE; /* adjust state machine */ + glyphpath->pathIsOpen = TRUE; + + glyphpath->offsetStart1 = P1; /* record second point */ + } + + if ( glyphpath->elemIsQueued ) + { + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || + glyphpath->hintMap.count == 0 ); + + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &P0, + P1, + FALSE ); + } + + /* queue the current element with offset points */ + glyphpath->elemIsQueued = TRUE; + glyphpath->prevElemOp = CF2_PathOpLineTo; + glyphpath->prevElemP0 = P0; + glyphpath->prevElemP1 = P1; + + /* update current map */ + if ( newHintMap ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + glyphpath->currentCS.x = x; /* pre-offset current point */ + glyphpath->currentCS.y = y; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_curveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed x3, + CF2_Fixed y3 ) + { + CF2_Fixed xOffset1, yOffset1, xOffset3, yOffset3; + FT_Vector P0, P1, P2, P3; + + + /* TODO: ignore zero length portions of curve?? */ + cf2_glyphpath_computeOffset( glyphpath, + glyphpath->currentCS.x, + glyphpath->currentCS.y, + x1, + y1, + &xOffset1, + &yOffset1 ); + cf2_glyphpath_computeOffset( glyphpath, + x2, + y2, + x3, + y3, + &xOffset3, + &yOffset3 ); + + /* add momentum from the middle segment */ + glyphpath->callbacks->windingMomentum = + ADD_INT32( glyphpath->callbacks->windingMomentum, + cf2_getWindingMomentum( x1, y1, x2, y2 ) ); + + /* construct offset points */ + P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset1 ); + P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset1 ); + P1.x = ADD_INT32( x1, xOffset1 ); + P1.y = ADD_INT32( y1, yOffset1 ); + /* note: preserve angle of final segment by using offset3 at both ends */ + P2.x = ADD_INT32( x2, xOffset3 ); + P2.y = ADD_INT32( y2, yOffset3 ); + P3.x = ADD_INT32( x3, xOffset3 ); + P3.y = ADD_INT32( y3, yOffset3 ); + + if ( glyphpath->moveIsPending ) + { + /* emit offset 1st point as MoveTo */ + cf2_glyphpath_pushMove( glyphpath, P0 ); + + glyphpath->moveIsPending = FALSE; + glyphpath->pathIsOpen = TRUE; + + glyphpath->offsetStart1 = P1; /* record second point */ + } + + if ( glyphpath->elemIsQueued ) + { + FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) || + glyphpath->hintMap.count == 0 ); + + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &P0, + P1, + FALSE ); + } + + /* queue the current element with offset points */ + glyphpath->elemIsQueued = TRUE; + glyphpath->prevElemOp = CF2_PathOpCubeTo; + glyphpath->prevElemP0 = P0; + glyphpath->prevElemP1 = P1; + glyphpath->prevElemP2 = P2; + glyphpath->prevElemP3 = P3; + + /* update current map */ + if ( cf2_hintmask_isNew( glyphpath->hintMask ) ) + cf2_hintmap_build( &glyphpath->hintMap, + glyphpath->hStemHintArray, + glyphpath->vStemHintArray, + glyphpath->hintMask, + glyphpath->hintOriginY, + FALSE ); + + glyphpath->currentCS.x = x3; /* pre-offset current point */ + glyphpath->currentCS.y = y3; + } + + + FT_LOCAL_DEF( void ) + cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ) + { + if ( glyphpath->pathIsOpen ) + { + /* + * A closing line in Character Space line is always generated below + * with `cf2_glyphPath_lineTo'. It may be ignored later if it turns + * out to be zero length in Device Space. + */ + glyphpath->pathIsClosing = TRUE; + + cf2_glyphpath_lineTo( glyphpath, + glyphpath->start.x, + glyphpath->start.y ); + + /* empty the final element from the queue and close the path */ + if ( glyphpath->elemIsQueued ) + cf2_glyphpath_pushPrevElem( glyphpath, + &glyphpath->hintMap, + &glyphpath->offsetStart0, + glyphpath->offsetStart1, + TRUE ); + + /* reset state machine */ + glyphpath->moveIsPending = TRUE; + glyphpath->pathIsOpen = FALSE; + glyphpath->pathIsClosing = FALSE; + glyphpath->elemIsQueued = FALSE; + } + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/pshints.h b/Dependencies/freetype/freetype/src/psaux/pshints.h new file mode 100644 index 00000000..31a82303 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/pshints.h @@ -0,0 +1,288 @@ +/**************************************************************************** + * + * pshints.h + * + * Adobe's code for handling CFF hints (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSHINT_H_ +#define PSHINT_H_ + +FT_BEGIN_HEADER + + + enum + { + CF2_MAX_HINTS = 96 /* maximum # of hints */ + }; + + + /* + * A HintMask object stores a bit mask that specifies which hints in the + * charstring are active at a given time. Hints in CFF must be declared + * at the start, before any drawing operators, with horizontal hints + * preceding vertical hints. The HintMask is ordered the same way, with + * horizontal hints immediately followed by vertical hints. Clients are + * responsible for knowing how many of each type are present. + * + * The maximum total number of hints is 96, as specified by the CFF + * specification. + * + * A HintMask is built 0 or more times while interpreting a charstring, by + * the HintMask operator. There is only one HintMask, but it is built or + * rebuilt each time there is a hint substitution (HintMask operator) in + * the charstring. A default HintMask with all bits set is built if there + * has been no HintMask operator prior to the first drawing operator. + * + */ + + typedef struct CF2_HintMaskRec_ + { + FT_Error* error; + + FT_Bool isValid; + FT_Bool isNew; + + size_t bitCount; + size_t byteCount; + + FT_Byte mask[( CF2_MAX_HINTS + 7 ) / 8]; + + } CF2_HintMaskRec, *CF2_HintMask; + + + typedef struct CF2_StemHintRec_ + { + FT_Bool used; /* DS positions are valid */ + + CF2_Fixed min; /* original character space value */ + CF2_Fixed max; + + CF2_Fixed minDS; /* DS position after first use */ + CF2_Fixed maxDS; + + } CF2_StemHintRec, *CF2_StemHint; + + + /* + * A HintMap object stores a piecewise linear function for mapping + * y-coordinates from character space to device space, providing + * appropriate pixel alignment to stem edges. + * + * The map is implemented as an array of `CF2_Hint' elements, each + * representing an edge. When edges are paired, as from stem hints, the + * bottom edge must immediately precede the top edge in the array. + * Element character space AND device space positions must both increase + * monotonically in the array. `CF2_Hint' elements are also used as + * parameters to `cf2_blues_capture'. + * + * The `cf2_hintmap_build' method must be called before any drawing + * operation (beginning with a Move operator) and at each hint + * substitution (HintMask operator). + * + * The `cf2_hintmap_map' method is called to transform y-coordinates at + * each drawing operation (move, line, curve). + * + */ + + /* TODO: make this a CF2_ArrStack and add a deep copy method */ + enum + { + CF2_MAX_HINT_EDGES = CF2_MAX_HINTS * 2 + }; + + + typedef struct CF2_HintMapRec_ + { + CF2_Font font; + + /* initial map based on blue zones */ + struct CF2_HintMapRec_* initialHintMap; + + /* working storage for 2nd pass adjustHints */ + CF2_ArrStack hintMoves; + + FT_Bool isValid; + FT_Bool hinted; + + CF2_Fixed scale; + CF2_UInt count; + + /* start search from this index */ + CF2_UInt lastIndex; + + CF2_HintRec edge[CF2_MAX_HINT_EDGES]; /* 192 */ + + } CF2_HintMapRec, *CF2_HintMap; + + + FT_LOCAL( FT_Bool ) + cf2_hint_isValid( const CF2_Hint hint ); + FT_LOCAL( FT_Bool ) + cf2_hint_isTop( const CF2_Hint hint ); + FT_LOCAL( FT_Bool ) + cf2_hint_isBottom( const CF2_Hint hint ); + FT_LOCAL( void ) + cf2_hint_lock( CF2_Hint hint ); + + + FT_LOCAL( void ) + cf2_hintmap_init( CF2_HintMap hintmap, + CF2_Font font, + CF2_HintMap initialMap, + CF2_ArrStack hintMoves, + CF2_Fixed scale ); + FT_LOCAL( void ) + cf2_hintmap_build( CF2_HintMap hintmap, + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + FT_Bool initialMap ); + + + /* + * GlyphPath is a wrapper for drawing operations that scales the + * coordinates according to the render matrix and HintMap. It also tracks + * open paths to control ClosePath and to insert MoveTo for broken fonts. + * + */ + typedef struct CF2_GlyphPathRec_ + { + /* TODO: gather some of these into a hinting context */ + + CF2_Font font; /* font instance */ + CF2_OutlineCallbacks callbacks; /* outline consumer */ + + + CF2_HintMapRec hintMap; /* current hint map */ + CF2_HintMapRec firstHintMap; /* saved copy */ + CF2_HintMapRec initialHintMap; /* based on all captured hints */ + + CF2_ArrStackRec hintMoves; /* list of hint moves for 2nd pass */ + + CF2_Fixed scaleX; /* matrix a */ + CF2_Fixed scaleC; /* matrix c */ + CF2_Fixed scaleY; /* matrix d */ + + FT_Vector fractionalTranslation; /* including deviceXScale */ +#if 0 + CF2_Fixed hShift; /* character space horizontal shift */ + /* (for fauxing) */ +#endif + + FT_Bool pathIsOpen; /* true after MoveTo */ + FT_Bool pathIsClosing; /* true when synthesizing closepath line */ + FT_Bool darken; /* true if stem darkening */ + FT_Bool moveIsPending; /* true between MoveTo and offset MoveTo */ + + /* references used to call `cf2_hintmap_build', if necessary */ + CF2_ArrStack hStemHintArray; + CF2_ArrStack vStemHintArray; + CF2_HintMask hintMask; /* ptr to the current mask */ + CF2_Fixed hintOriginY; /* copy of current origin */ + const CF2_BluesRec* blues; + + CF2_Fixed xOffset; /* character space offsets */ + CF2_Fixed yOffset; + + /* character space miter limit threshold */ + CF2_Fixed miterLimit; + /* vertical/horizontal snap distance in character space */ + CF2_Fixed snapThreshold; + + FT_Vector offsetStart0; /* first and second points of first */ + FT_Vector offsetStart1; /* element with offset applied */ + + /* current point, character space, before offset */ + FT_Vector currentCS; + /* current point, device space */ + FT_Vector currentDS; + /* start point of subpath, character space */ + FT_Vector start; + + /* the following members constitute the `queue' of one element */ + FT_Bool elemIsQueued; + CF2_Int prevElemOp; + + FT_Vector prevElemP0; + FT_Vector prevElemP1; + FT_Vector prevElemP2; + FT_Vector prevElemP3; + + } CF2_GlyphPathRec, *CF2_GlyphPath; + + + FT_LOCAL( void ) + cf2_glyphpath_init( CF2_GlyphPath glyphpath, + CF2_Font font, + CF2_OutlineCallbacks callbacks, + CF2_Fixed scaleY, + /* CF2_Fixed hShift, */ + CF2_ArrStack hStemHintArray, + CF2_ArrStack vStemHintArray, + CF2_HintMask hintMask, + CF2_Fixed hintOrigin, + const CF2_Blues blues, + const FT_Vector* fractionalTranslation ); + FT_LOCAL( void ) + cf2_glyphpath_finalize( CF2_GlyphPath glyphpath ); + + FT_LOCAL( void ) + cf2_glyphpath_moveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ); + FT_LOCAL( void ) + cf2_glyphpath_lineTo( CF2_GlyphPath glyphpath, + CF2_Fixed x, + CF2_Fixed y ); + FT_LOCAL( void ) + cf2_glyphpath_curveTo( CF2_GlyphPath glyphpath, + CF2_Fixed x1, + CF2_Fixed y1, + CF2_Fixed x2, + CF2_Fixed y2, + CF2_Fixed x3, + CF2_Fixed y3 ); + FT_LOCAL( void ) + cf2_glyphpath_closeOpenPath( CF2_GlyphPath glyphpath ); + + +FT_END_HEADER + + +#endif /* PSHINT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psintrp.c b/Dependencies/freetype/freetype/src/psaux/psintrp.c new file mode 100644 index 00000000..7572e225 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psintrp.c @@ -0,0 +1,3050 @@ +/**************************************************************************** + * + * psintrp.c + * + * Adobe's CFF Interpreter (body). + * + * Copyright 2007-2014 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include +#include +#include + +#include "psglue.h" +#include "psfont.h" +#include "psstack.h" +#include "pshints.h" +#include "psintrp.h" + +#include "pserror.h" + +#include "psobjs.h" /* for cff_random */ +#include "t1decode.h" /* for t1 seac */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT cf2interp + + + FT_LOCAL_DEF( void ) + cf2_hintmask_init( CF2_HintMask hintmask, + FT_Error* error ) + { + FT_ZERO( hintmask ); + + hintmask->error = error; + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hintmask_isValid( const CF2_HintMask hintmask ) + { + return hintmask->isValid; + } + + + FT_LOCAL_DEF( FT_Bool ) + cf2_hintmask_isNew( const CF2_HintMask hintmask ) + { + return hintmask->isNew; + } + + + FT_LOCAL_DEF( void ) + cf2_hintmask_setNew( CF2_HintMask hintmask, + FT_Bool val ) + { + hintmask->isNew = val; + } + + + /* clients call `getMaskPtr' in order to iterate */ + /* through hint mask */ + + FT_LOCAL_DEF( FT_Byte* ) + cf2_hintmask_getMaskPtr( CF2_HintMask hintmask ) + { + return hintmask->mask; + } + + + static size_t + cf2_hintmask_setCounts( CF2_HintMask hintmask, + size_t bitCount ) + { + if ( bitCount > CF2_MAX_HINTS ) + { + /* total of h and v stems must be <= 96 */ + CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format ); + return 0; + } + + hintmask->bitCount = bitCount; + hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8; + + hintmask->isValid = TRUE; + hintmask->isNew = TRUE; + + return bitCount; + } + + + /* consume the hintmask bytes from the charstring, advancing the src */ + /* pointer */ + static void + cf2_hintmask_read( CF2_HintMask hintmask, + CF2_Buffer charstring, + size_t bitCount ) + { + size_t i; + +#ifndef CF2_NDEBUG + /* these are the bits in the final mask byte that should be zero */ + /* Note: this variable is only used in an assert expression below */ + /* and then only if CF2_NDEBUG is not defined */ + CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; +#endif + + + /* initialize counts and isValid */ + if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) + return; + + FT_ASSERT( hintmask->byteCount > 0 ); + + FT_TRACE4(( " (maskbytes:" )); + + /* set mask and advance interpreter's charstring pointer */ + for ( i = 0; i < hintmask->byteCount; i++ ) + { + hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring ); + FT_TRACE4(( " 0x%02X", hintmask->mask[i] )); + } + + FT_TRACE4(( ")\n" )); + + /* assert any unused bits in last byte are zero unless there's a prior */ + /* error */ + /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ +#ifndef CF2_NDEBUG + FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 || + *hintmask->error ); +#endif + } + + + FT_LOCAL_DEF( void ) + cf2_hintmask_setAll( CF2_HintMask hintmask, + size_t bitCount ) + { + size_t i; + CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; + + + /* initialize counts and isValid */ + if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) + return; + + FT_ASSERT( hintmask->byteCount > 0 ); + FT_ASSERT( hintmask->byteCount <= + sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) ); + + /* set mask to all ones */ + for ( i = 0; i < hintmask->byteCount; i++ ) + hintmask->mask[i] = 0xFF; + + /* clear unused bits */ + /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ + hintmask->mask[hintmask->byteCount - 1] &= ~mask; + } + + + /* Type2 charstring opcodes */ + enum + { + cf2_cmdRESERVED_0, /* 0 */ + cf2_cmdHSTEM, /* 1 */ + cf2_cmdRESERVED_2, /* 2 */ + cf2_cmdVSTEM, /* 3 */ + cf2_cmdVMOVETO, /* 4 */ + cf2_cmdRLINETO, /* 5 */ + cf2_cmdHLINETO, /* 6 */ + cf2_cmdVLINETO, /* 7 */ + cf2_cmdRRCURVETO, /* 8 */ + cf2_cmdCLOSEPATH, /* 9 T1 only */ + cf2_cmdCALLSUBR, /* 10 */ + cf2_cmdRETURN, /* 11 */ + cf2_cmdESC, /* 12 */ + cf2_cmdHSBW, /* 13 T1 only */ + cf2_cmdENDCHAR, /* 14 */ + cf2_cmdVSINDEX, /* 15 */ + cf2_cmdBLEND, /* 16 */ + cf2_cmdRESERVED_17, /* 17 */ + cf2_cmdHSTEMHM, /* 18 */ + cf2_cmdHINTMASK, /* 19 */ + cf2_cmdCNTRMASK, /* 20 */ + cf2_cmdRMOVETO, /* 21 */ + cf2_cmdHMOVETO, /* 22 */ + cf2_cmdVSTEMHM, /* 23 */ + cf2_cmdRCURVELINE, /* 24 */ + cf2_cmdRLINECURVE, /* 25 */ + cf2_cmdVVCURVETO, /* 26 */ + cf2_cmdHHCURVETO, /* 27 */ + cf2_cmdEXTENDEDNMBR, /* 28 */ + cf2_cmdCALLGSUBR, /* 29 */ + cf2_cmdVHCURVETO, /* 30 */ + cf2_cmdHVCURVETO /* 31 */ + }; + + enum + { + cf2_escDOTSECTION, /* 0 */ + cf2_escVSTEM3, /* 1 T1 only */ + cf2_escHSTEM3, /* 2 T1 only */ + cf2_escAND, /* 3 */ + cf2_escOR, /* 4 */ + cf2_escNOT, /* 5 */ + cf2_escSEAC, /* 6 T1 only */ + cf2_escSBW, /* 7 T1 only */ + cf2_escRESERVED_8, /* 8 */ + cf2_escABS, /* 9 */ + cf2_escADD, /* 10 like otherADD */ + cf2_escSUB, /* 11 like otherSUB */ + cf2_escDIV, /* 12 */ + cf2_escRESERVED_13, /* 13 */ + cf2_escNEG, /* 14 */ + cf2_escEQ, /* 15 */ + cf2_escCALLOTHERSUBR,/* 16 T1 only */ + cf2_escPOP, /* 17 T1 only */ + cf2_escDROP, /* 18 */ + cf2_escRESERVED_19, /* 19 */ + cf2_escPUT, /* 20 like otherPUT */ + cf2_escGET, /* 21 like otherGET */ + cf2_escIFELSE, /* 22 like otherIFELSE */ + cf2_escRANDOM, /* 23 like otherRANDOM */ + cf2_escMUL, /* 24 like otherMUL */ + cf2_escRESERVED_25, /* 25 */ + cf2_escSQRT, /* 26 */ + cf2_escDUP, /* 27 like otherDUP */ + cf2_escEXCH, /* 28 like otherEXCH */ + cf2_escINDEX, /* 29 */ + cf2_escROLL, /* 30 */ + cf2_escRESERVED_31, /* 31 */ + cf2_escRESERVED_32, /* 32 */ + cf2_escSETCURRENTPT, /* 33 T1 only */ + cf2_escHFLEX, /* 34 */ + cf2_escFLEX, /* 35 */ + cf2_escHFLEX1, /* 36 */ + cf2_escFLEX1, /* 37 */ + cf2_escRESERVED_38 /* 38 & all higher */ + }; + + + /* `stemHintArray' does not change once we start drawing the outline. */ + static void + cf2_doStems( const CF2_Font font, + CF2_Stack opStack, + CF2_ArrStack stemHintArray, + CF2_Fixed* width, + FT_Bool* haveWidth, + CF2_Fixed hintOffset ) + { + CF2_UInt i; + CF2_UInt count = cf2_stack_count( opStack ); + FT_Bool hasWidthArg = FT_BOOL( count & 1 ); + + /* variable accumulates delta values from operand stack */ + CF2_Fixed position = hintOffset; + + if ( font->isT1 && !font->decoder->flex_state && !*haveWidth ) + FT_ERROR(( "cf2_doStems (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( !font->isT1 && hasWidthArg && !*haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + cf2_getNominalWidthX( font->decoder ) ); + + if ( font->decoder->width_only ) + goto exit; + + for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 ) + { + /* construct a CF2_StemHint and push it onto the list */ + CF2_StemHintRec stemhint; + + + stemhint.min = + position = ADD_INT32( position, + cf2_stack_getReal( opStack, i ) ); + stemhint.max = + position = ADD_INT32( position, + cf2_stack_getReal( opStack, i + 1 ) ); + + stemhint.used = FALSE; + stemhint.maxDS = + stemhint.minDS = 0; + + cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */ + } + + cf2_stack_clear( opStack ); + + exit: + /* cf2_doStems must define a width (may be default) */ + *haveWidth = TRUE; + } + + + static void + cf2_doFlex( CF2_Stack opStack, + CF2_Fixed* curX, + CF2_Fixed* curY, + CF2_GlyphPath glyphPath, + const FT_Bool* readFromStack, + FT_Bool doConditionalLastRead ) + { + CF2_Fixed vals[14]; + CF2_UInt idx; + FT_Bool isHFlex; + CF2_Int top, i, j; + + + vals[0] = *curX; + vals[1] = *curY; + idx = 0; + isHFlex = FT_BOOL( readFromStack[9] == FALSE ); + top = isHFlex ? 9 : 10; + + for ( i = 0; i < top; i++ ) + { + vals[i + 2] = vals[i]; + if ( readFromStack[i] ) + vals[i + 2] = ADD_INT32( vals[i + 2], cf2_stack_getReal( opStack, + idx++ ) ); + } + + if ( isHFlex ) + vals[9 + 2] = *curY; + + if ( doConditionalLastRead ) + { + FT_Bool lastIsX = FT_BOOL( + cf2_fixedAbs( SUB_INT32( vals[10], *curX ) ) > + cf2_fixedAbs( SUB_INT32( vals[11], *curY ) ) ); + CF2_Fixed lastVal = cf2_stack_getReal( opStack, idx ); + + + if ( lastIsX ) + { + vals[12] = ADD_INT32( vals[10], lastVal ); + vals[13] = *curY; + } + else + { + vals[12] = *curX; + vals[13] = ADD_INT32( vals[11], lastVal ); + } + } + else + { + if ( readFromStack[10] ) + vals[12] = ADD_INT32( vals[10], + cf2_stack_getReal( opStack, idx++ ) ); + else + vals[12] = *curX; + + if ( readFromStack[11] ) + vals[13] = ADD_INT32( vals[11], + cf2_stack_getReal( opStack, idx ) ); + else + vals[13] = *curY; + } + + for ( j = 0; j < 2; j++ ) + cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2], + vals[j * 6 + 3], + vals[j * 6 + 4], + vals[j * 6 + 5], + vals[j * 6 + 6], + vals[j * 6 + 7] ); + + cf2_stack_clear( opStack ); + + *curX = vals[12]; + *curY = vals[13]; + } + + + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + static void + cf2_doBlend( const CFF_Blend blend, + CF2_Stack opStack, + CF2_UInt numBlends ) + { + CF2_UInt delta; + CF2_UInt base; + CF2_UInt i, j; + CF2_UInt numOperands = (CF2_UInt)( numBlends * blend->lenBV ); + + + base = cf2_stack_count( opStack ) - numOperands; + delta = base + numBlends; + + FT_TRACE6(( " (" )); + + for ( i = 0; i < numBlends; i++ ) + { + const CF2_Fixed* weight = &blend->BV[1]; + + /* start with first term */ + CF2_Fixed sum = cf2_stack_getReal( opStack, i + base ); + + + for ( j = 1; j < blend->lenBV; j++ ) + sum = ADD_INT32( sum, + FT_MulFix( *weight++, + cf2_stack_getReal( opStack, + delta++ ) ) ); + + FT_TRACE6(( "%f ", (double)sum / 65536 )); + + /* store blended result */ + cf2_stack_setReal( opStack, i + base, sum ); + } + + FT_TRACE6(( "blended)\n" )); + + /* leave only `numBlends' results on stack */ + cf2_stack_pop( opStack, numOperands - numBlends ); + } + + + /* + * `error' is a shared error code used by many objects in this + * routine. Before the code continues from an error, it must check and + * record the error in `*error'. The idea is that this shared + * error code will record the first error encountered. If testing + * for an error anyway, the cost of `goto exit' is small, so we do it, + * even if continuing would be safe. In this case, `lastError' is + * set, so the testing and storing can be done in one place, at `exit'. + * + * Continuing after an error is intended for objects which do their own + * testing of `*error', e.g., array stack functions. This allows us to + * avoid an extra test after the call. + * + * Unimplemented opcodes are ignored. + * + */ + FT_LOCAL_DEF( void ) + cf2_interpT2CharString( CF2_Font font, + const CF2_Buffer buf, + CF2_OutlineCallbacks callbacks, + const FT_Vector* translation, + FT_Bool doingSeac, + CF2_Fixed curX, + CF2_Fixed curY, + CF2_Fixed* width ) + { + /* lastError is used for errors that are immediately tested */ + FT_Error lastError = FT_Err_Ok; + + /* pointer to parsed font object */ + PS_Decoder* decoder = font->decoder; + + FT_Error* error = &font->error; + FT_Memory memory = font->memory; + + CF2_Fixed scaleY = font->innerTransform.d; + CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder ); + + /* stuff for Type 1 */ + FT_Int known_othersubr_result_cnt = 0; + FT_Bool large_int = FALSE; + FT_Bool initial_map_ready = FALSE; + +#define PS_STORAGE_SIZE 3 + CF2_F16Dot16 results[PS_STORAGE_SIZE]; /* for othersubr results */ + FT_Int result_cnt = 0; + + /* save this for hinting seac accents */ + CF2_Fixed hintOriginY = curY; + + CF2_Stack opStack = NULL; + FT_UInt stackSize; + FT_Byte op1; /* first opcode byte */ + + CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */ + CF2_F16Dot16 flexStore[6]; /* for Type 1 flex */ + + /* instruction limit; 20,000,000 matches Avalon */ + FT_UInt32 instructionLimit = 20000000UL; + + CF2_ArrStackRec subrStack; + + FT_Bool haveWidth; + CF2_Buffer charstring = NULL; + + CF2_Int charstringIndex = -1; /* initialize to empty */ + + /* TODO: placeholders for hint structures */ + + /* objects used for hinting */ + CF2_ArrStackRec hStemHintArray; + CF2_ArrStackRec vStemHintArray; + + CF2_HintMaskRec hintMask; + CF2_GlyphPathRec glyphPath; + + + FT_ZERO( &storage ); + FT_ZERO( &results ); + FT_ZERO( &flexStore ); + + /* initialize the remaining objects */ + cf2_arrstack_init( &subrStack, + memory, + error, + sizeof ( CF2_BufferRec ) ); + cf2_arrstack_init( &hStemHintArray, + memory, + error, + sizeof ( CF2_StemHintRec ) ); + cf2_arrstack_init( &vStemHintArray, + memory, + error, + sizeof ( CF2_StemHintRec ) ); + + /* initialize CF2_StemHint arrays */ + cf2_hintmask_init( &hintMask, error ); + + /* initialize path map to manage drawing operations */ + + /* Note: last 4 params are used to handle `MoveToPermissive', which */ + /* may need to call `hintMap.Build' */ + /* TODO: MoveToPermissive is gone; are these still needed? */ + cf2_glyphpath_init( &glyphPath, + font, + callbacks, + scaleY, + /* hShift, */ + &hStemHintArray, + &vStemHintArray, + &hintMask, + hintOriginY, + &font->blues, + translation ); + + /* + * Initialize state for width parsing. From the CFF Spec: + * + * The first stack-clearing operator, which must be one of hstem, + * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, + * rmoveto, or endchar, takes an additional argument - the width (as + * described earlier), which may be expressed as zero or one numeric + * argument. + * + * What we implement here uses the first validly specified width, but + * does not detect errors for specifying more than one width. + * + * If one of the above operators occurs without explicitly specifying + * a width, we assume the default width. + * + * CFF2 charstrings always return the default width (0). + * + */ + haveWidth = font->isCFF2 ? TRUE : FALSE; + *width = cf2_getDefaultWidthX( decoder ); + + /* + * Note: At this point, all pointers to resources must be NULL + * and all local objects must be initialized. + * There must be no branches to `exit:' above this point. + * + */ + + /* allocate an operand stack */ + stackSize = font->isCFF2 ? cf2_getMaxstack( decoder ) + : CF2_OPERAND_STACK_SIZE; + opStack = cf2_stack_init( memory, error, stackSize ); + + if ( !opStack ) + { + lastError = FT_THROW( Out_Of_Memory ); + goto exit; + } + + /* initialize subroutine stack by placing top level charstring as */ + /* first element (max depth plus one for the charstring) */ + /* Note: Caller owns and must finalize the first charstring. */ + /* Our copy of it does not change that requirement. */ + cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 ); + + charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); + + /* catch errors so far */ + if ( *error ) + goto exit; + + *charstring = *buf; /* structure copy */ + charstringIndex = 0; /* entry is valid now */ + + /* main interpreter loop */ + while ( 1 ) + { + if ( font->isT1 ) + FT_ASSERT( known_othersubr_result_cnt == 0 || + result_cnt == 0 ); + + if ( cf2_buf_isEnd( charstring ) ) + { + /* If we've reached the end of the charstring, simulate a */ + /* cf2_cmdRETURN or cf2_cmdENDCHAR. */ + /* We do this for both CFF and CFF2. */ + if ( charstringIndex ) + op1 = cf2_cmdRETURN; /* end of buffer for subroutine */ + else + op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */ + } + else + { + op1 = (FT_Byte)cf2_buf_readByte( charstring ); + + /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */ + /* Note: Trace message will report 0 instead of 11 or 14. */ + if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) && + font->isCFF2 ) + op1 = cf2_cmdRESERVED_0; + } + + if ( font->isT1 ) + { + if ( !initial_map_ready && + !( op1 == cf2_cmdHSTEM || + op1 == cf2_cmdVSTEM || + op1 == cf2_cmdHSBW || + op1 == cf2_cmdCALLSUBR || + op1 == cf2_cmdRETURN || + op1 == cf2_cmdESC || + op1 == cf2_cmdENDCHAR || + op1 >= 32 /* Numbers */ ) ) + { + /* Skip outline commands first time round. */ + /* `endchar' will trigger initial hintmap build */ + /* and rewind the charstring. */ + FT_TRACE4(( " \n" )); + cf2_stack_clear( opStack ); + continue; + } + + if ( result_cnt > 0 && + !( op1 == cf2_cmdCALLSUBR || + op1 == cf2_cmdRETURN || + op1 == cf2_cmdESC || + op1 >= 32 /* Numbers */ ) ) + { + /* all operands have been transferred by previous pops */ + result_cnt = 0; + } + + if ( large_int && !( op1 >= 32 || op1 == cf2_escDIV ) ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no `div' after large integer\n" )); + + large_int = FALSE; + } + } + + /* check for errors once per loop */ + if ( *error ) + goto exit; + + instructionLimit--; + if ( instructionLimit == 0 ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + switch( op1 ) + { + case cf2_cmdRESERVED_0: + case cf2_cmdRESERVED_2: + case cf2_cmdRESERVED_17: + /* we may get here if we have a prior error */ + FT_TRACE4(( " unknown op (%d)\n", op1 )); + break; + + case cf2_cmdVSINDEX: + FT_TRACE4(( " vsindex\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + if ( font->blend.usedBV ) + { + /* vsindex not allowed after blend */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + { + FT_Int temp = cf2_stack_popInt( opStack ); + + + if ( temp >= 0 ) + font->vsindex = (FT_UInt)temp; + } + break; + + case cf2_cmdBLEND: + { + FT_UInt numBlends; + + + FT_TRACE4(( " blend" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + /* do we have a `blend' op in a non-variant font? */ + if ( !font->blend.font ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* check cached blend vector */ + if ( font->cffload->blend_check_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ) ) + { + lastError = font->cffload->blend_build_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ); + if ( lastError ) + goto exit; + } + + /* do the blend */ + numBlends = (FT_UInt)cf2_stack_popInt( opStack ); + if ( numBlends > stackSize ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + cf2_doBlend( &font->blend, opStack, numBlends ); + + font->blend.usedBV = TRUE; + } + continue; /* do not clear the stack */ + + case cf2_cmdHSTEMHM: + case cf2_cmdHSTEM: + FT_TRACE4(( "%s\n", op1 == cf2_cmdHSTEMHM ? " hstemhm" + : " hstem" )); + + if ( !font->isT1 ) + { + /* never add hints after the mask is computed */ + /* except if in Type 1 mode (no hintmask op) */ + if ( cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString:" + " invalid horizontal hint mask\n" )); + break; + } + } + + /* add left-sidebearing correction in Type 1 mode */ + cf2_doStems( font, + opStack, + &hStemHintArray, + width, + &haveWidth, + font->isT1 ? decoder->builder.left_bearing->y + : 0 ); + + if ( decoder->width_only ) + goto exit; + + break; + + case cf2_cmdVSTEMHM: + case cf2_cmdVSTEM: + FT_TRACE4(( "%s\n", op1 == cf2_cmdVSTEMHM ? " vstemhm" + : " vstem" )); + + if ( !font->isT1 ) + { + /* never add hints after the mask is computed */ + /* except if in Type 1 mode (no hintmask op) */ + if ( cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString:" + " invalid vertical hint mask\n" )); + break; + } + } + + /* add left-sidebearing correction in Type 1 mode */ + cf2_doStems( font, + opStack, + &vStemHintArray, + width, + &haveWidth, + font->isT1 ? decoder->builder.left_bearing->x + : 0 ); + + if ( decoder->width_only ) + goto exit; + + break; + + case cf2_cmdVMOVETO: + FT_TRACE4(( " vmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdRLINETO: + { + CF2_UInt idx; + CF2_UInt count = cf2_stack_count( opStack ); + + + FT_TRACE4(( " rlineto\n" )); + + for ( idx = 0; idx < count; idx += 2 ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdHLINETO: + case cf2_cmdVLINETO: + { + CF2_UInt idx; + CF2_UInt count = cf2_stack_count( opStack ); + + FT_Bool isX = FT_BOOL( op1 == cf2_cmdHLINETO ); + + + FT_TRACE4(( "%s\n", isX ? " hlineto" : " vlineto" )); + + for ( idx = 0; idx < count; idx++ ) + { + CF2_Fixed v = cf2_stack_getReal( opStack, idx ); + + + if ( isX ) + curX = ADD_INT32( curX, v ); + else + curY = ADD_INT32( curY, v ); + + isX = !isX; + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; + + case cf2_cmdRCURVELINE: + case cf2_cmdRRCURVETO: + { + CF2_UInt count = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + FT_TRACE4(( "%s\n", op1 == cf2_cmdRCURVELINE ? " rcurveline" + : " rrcurveto" )); + + while ( idx + 6 <= count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 6; + } + + if ( op1 == cf2_cmdRCURVELINE ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdCLOSEPATH: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (%d)\n", op1 )); + else + { + FT_TRACE4(( " closepath\n" )); + + /* if there is no path, `closepath' is a no-op */ + cf2_glyphpath_closeOpenPath( &glyphPath ); + + haveWidth = TRUE; + } + break; + + case cf2_cmdCALLGSUBR: + case cf2_cmdCALLSUBR: + { + CF2_Int subrNum; + + + FT_TRACE4(( "%s", op1 == cf2_cmdCALLGSUBR ? " callgsubr" + : " callsubr" )); + + if ( ( !font->isT1 && charstringIndex > CF2_MAX_SUBR ) || + ( font->isT1 && charstringIndex > T1_MAX_SUBRS_CALLS ) ) + { + /* max subr plus one for charstring */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* overflow of stack */ + } + + /* push our current CFF charstring region on subrStack */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (size_t)charstringIndex + 1 ); + + /* set up the new CFF region and pointer */ + subrNum = cf2_stack_popInt( opStack ); + + if ( font->isT1 && decoder->locals_hash ) + { + size_t* val = ft_hash_num_lookup( subrNum, + decoder->locals_hash ); + + + if ( val ) + subrNum = *val; + else + subrNum = -1; + } + + switch ( op1 ) + { + case cf2_cmdCALLGSUBR: + FT_TRACE4(( " (idx %d, entering level %d)\n", + subrNum + decoder->globals_bias, + charstringIndex + 1 )); + + if ( cf2_initGlobalRegionBuffer( decoder, + subrNum, + charstring ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* subroutine lookup or stream error */ + } + break; + + default: + /* cf2_cmdCALLSUBR */ + FT_TRACE4(( " (idx %d, entering level %d)\n", + subrNum + decoder->locals_bias, + charstringIndex + 1 )); + + if ( cf2_initLocalRegionBuffer( decoder, + subrNum, + charstring ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* subroutine lookup or stream error */ + } + } + + charstringIndex += 1; /* entry is valid now */ + } + continue; /* do not clear the stack */ + + case cf2_cmdRETURN: + FT_TRACE4(( " return (leaving level %d)\n", charstringIndex )); + + if ( charstringIndex < 1 ) + { + /* Note: cannot return from top charstring */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* underflow of stack */ + } + + /* restore position in previous charstring */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (CF2_UInt)--charstringIndex ); + continue; /* do not clear the stack */ + + case cf2_cmdESC: + { + FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring ); + + + /* first switch for 2-byte operators handles CFF2 */ + /* and opcodes that are reserved for both CFF and CFF2 */ + switch ( op2 ) + { + case cf2_escHFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, FALSE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, FALSE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " hflex\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + continue; + + case cf2_escFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, TRUE /* dy6 */ + }; + + + FT_TRACE4(( " flex\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + break; /* TODO: why is this not a continue? */ + + case cf2_escHFLEX1: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " hflex1\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + continue; + + case cf2_escFLEX1: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + FALSE /* dx6 */, FALSE /* dy6 */ + }; + + + FT_TRACE4(( " flex1\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + TRUE /* doConditionalLastRead */ ); + } + continue; + + /* these opcodes are always reserved */ + case cf2_escRESERVED_8: + case cf2_escRESERVED_13: + case cf2_escRESERVED_19: + case cf2_escRESERVED_25: + case cf2_escRESERVED_31: + case cf2_escRESERVED_32: + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + break; + + default: + { + if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else if ( font->isT1 && result_cnt > 0 && op2 != cf2_escPOP ) + { + /* all operands have been transferred by previous pops */ + result_cnt = 0; + } + else + { + /* second switch for 2-byte operators handles */ + /* CFF and Type 1 */ + switch ( op2 ) + { + + case cf2_escDOTSECTION: + /* something about `flip type of locking' -- ignore it */ + FT_TRACE4(( " dotsection\n" )); + + break; + + case cf2_escVSTEM3: + case cf2_escHSTEM3: + /* + * Type 1: Type 2: + * x0 dx0 x1 dx1 x2 dx2 vstem3 x dx {dxa dxb}* vstem + * y0 dy0 y1 dy1 y2 dy2 hstem3 y dy {dya dyb}* hstem + * relative to lsb point relative to zero + * + */ + { + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_F16Dot16 v0, v1, v2; + + FT_Bool isV = FT_BOOL( op2 == cf2_escVSTEM3 ); + + + FT_TRACE4(( "%s\n", isV ? " vstem3" + : " hstem3" )); + + FT_ASSERT( cf2_stack_count( opStack ) == 6 ); + + v0 = cf2_stack_getReal( opStack, 0 ); + v1 = cf2_stack_getReal( opStack, 2 ); + v2 = cf2_stack_getReal( opStack, 4 ); + + cf2_stack_setReal( + opStack, 2, + SUB_INT32( SUB_INT32( v1, v0 ), + cf2_stack_getReal( opStack, 1 ) ) ); + cf2_stack_setReal( + opStack, 4, + SUB_INT32( SUB_INT32( v2, v1 ), + cf2_stack_getReal( opStack, 3 ) ) ); + + /* add left-sidebearing correction */ + cf2_doStems( font, + opStack, + isV ? &vStemHintArray : &hStemHintArray, + width, + &haveWidth, + isV ? decoder->builder.left_bearing->x + : decoder->builder.left_bearing->y ); + + if ( decoder->width_only ) + goto exit; + } + } + break; + + case cf2_escAND: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " and\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 && arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escOR: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " or\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 || arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escNOT: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " not\n" )); + + arg = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, !arg ); + } + continue; /* do not clear the stack */ + + case cf2_escSEAC: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_Error error2; + CF2_Int bchar_index, achar_index; + FT_Vector left_bearing, advance; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + T1_Face face = (T1_Face)decoder->builder.face; +#endif + CF2_BufferRec component; + CF2_Fixed dummyWidth; + + CF2_Int achar = cf2_stack_popInt( opStack ); + CF2_Int bchar = cf2_stack_popInt( opStack ); + + FT_Pos ady = cf2_stack_popFixed ( opStack ); + FT_Pos adx = cf2_stack_popFixed ( opStack ); + FT_Pos asb = cf2_stack_popFixed ( opStack ); + + + FT_TRACE4(( " seac\n" )); + + if ( doingSeac ) + { + FT_ERROR(( " nested seac\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* nested seac */ + } + + if ( decoder->builder.metrics_only ) + { + FT_ERROR(( " unexpected seac\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* unexpected seac */ + } + + /* `glyph_names' is set to 0 for CID fonts which do */ + /* not include an encoding. How can we deal with */ + /* these? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( decoder->glyph_names == 0 && + !face->root.internal->incremental_interface ) +#else + if ( decoder->glyph_names == 0 ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) glyph names table" + " not available in this font\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* seac weirdness */ + adx += decoder->builder.left_bearing->x; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + { + /* the caller must handle the font encoding also */ + bchar_index = bchar; + achar_index = achar; + } + else +#endif + { + bchar_index = t1_lookup_glyph_by_stdcharcode_ps( + decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode_ps( + decoder, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) invalid" + " seac character code arguments\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* if we are trying to load a composite glyph, */ + /* do not load the accent character and return */ + /* the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error2 = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); + subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + + goto exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + /* prepare loader */ + FT_GlyphLoader_Prepare( decoder->builder.loader ); + + error2 = cf2_getT1SeacComponent( decoder, + (FT_UInt)bchar_index, + &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + 0, + 0, + &dummyWidth ); + cf2_freeT1SeacComponent( decoder, &component ); + + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ + + if ( !haveWidth ) + { + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + } + + decoder->builder.left_bearing->x = 0; + decoder->builder.left_bearing->y = 0; + + /* Now load `achar' on top of */ + /* the base outline */ + + error2 = cf2_getT1SeacComponent( decoder, + (FT_UInt)achar_index, + &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + adx - asb, + ady, + &dummyWidth ); + cf2_freeT1SeacComponent( decoder, &component ); + + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ + + *decoder->builder.left_bearing = left_bearing; + *decoder->builder.advance = advance; + + goto exit; + } + break; + + case cf2_escSBW: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_Fixed lsb_x, lsb_y; + PS_Builder* builder; + + + FT_TRACE4(( " sbw" )); + + builder = &decoder->builder; + + builder->advance->y = cf2_stack_popFixed( opStack ); + builder->advance->x = cf2_stack_popFixed( opStack ); + + lsb_y = cf2_stack_popFixed( opStack ); + lsb_x = cf2_stack_popFixed( opStack ); + + builder->left_bearing->x = + ADD_INT32( builder->left_bearing->x, lsb_x ); + builder->left_bearing->y = + ADD_INT32( builder->left_bearing->y, lsb_y ); + + haveWidth = TRUE; + + /* the `metrics_only' indicates that we only want */ + /* to compute the glyph's metrics (lsb + advance */ + /* width), not load the rest of it; so exit */ + /* immediately */ + if ( builder->metrics_only ) + goto exit; + + if ( initial_map_ready ) + { + curX = ADD_INT32( curX, lsb_x ); + curY = ADD_INT32( curY, lsb_y ); + } + } + break; + + case cf2_escABS: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " abs\n" )); + + arg = cf2_stack_popFixed( opStack ); + + if ( arg < -CF2_FIXED_MAX ) + cf2_stack_pushFixed( opStack, CF2_FIXED_MAX ); + else + cf2_stack_pushFixed( opStack, FT_ABS( arg ) ); + } + continue; /* do not clear the stack */ + + case cf2_escADD: + { + CF2_F16Dot16 summand1; + CF2_F16Dot16 summand2; + + + FT_TRACE4(( " add\n" )); + + summand2 = cf2_stack_popFixed( opStack ); + summand1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + ADD_INT32( summand1, + summand2 ) ); + } + continue; /* do not clear the stack */ + + case cf2_escSUB: + { + CF2_F16Dot16 minuend; + CF2_F16Dot16 subtrahend; + + + FT_TRACE4(( " sub\n" )); + + subtrahend = cf2_stack_popFixed( opStack ); + minuend = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + SUB_INT32( minuend, subtrahend ) ); + } + continue; /* do not clear the stack */ + + case cf2_escDIV: + { + CF2_F16Dot16 dividend; + CF2_F16Dot16 divisor; + + + FT_TRACE4(( " div\n" )); + + if ( font->isT1 && large_int ) + { + divisor = (CF2_F16Dot16)cf2_stack_popInt( opStack ); + dividend = (CF2_F16Dot16)cf2_stack_popInt( opStack ); + + large_int = FALSE; + } + else + { + divisor = cf2_stack_popFixed( opStack ); + dividend = cf2_stack_popFixed( opStack ); + } + + cf2_stack_pushFixed( opStack, + FT_DivFix( dividend, divisor ) ); + + } + continue; /* do not clear the stack */ + + case cf2_escNEG: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " neg\n" )); + + arg = cf2_stack_popFixed( opStack ); + + if ( arg < -CF2_FIXED_MAX ) + cf2_stack_pushFixed( opStack, CF2_FIXED_MAX ); + else + cf2_stack_pushFixed( opStack, -arg ); + } + continue; /* do not clear the stack */ + + case cf2_escEQ: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " eq\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushInt( opStack, arg1 == arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escCALLOTHERSUBR: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + CF2_Int subr_no; + CF2_Int arg_cnt; + CF2_UInt count; + CF2_UInt opIdx = 0; + + + FT_TRACE4(( " callothersubr\n" )); + + subr_no = cf2_stack_popInt( opStack ); + arg_cnt = cf2_stack_popInt( opStack ); + + /******************************************************** + * + * remove all operands to callothersubr from the stack + * + * for handled othersubrs, where we know the number of + * arguments, we increase the stack by the value of + * known_othersubr_result_cnt + * + * for unhandled othersubrs the following pops adjust + * the stack pointer as necessary + */ + + count = cf2_stack_count( opStack ); + if ( (CF2_UInt)arg_cnt > count ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " stack underflow\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + opIdx += count - (CF2_UInt)arg_cnt; + + known_othersubr_result_cnt = 0; + result_cnt = 0; + + /* XXX TODO: The checks to `arg_count == ' */ + /* might not be correct; an othersubr expects a */ + /* certain number of operands on the PostScript stack */ + /* (as opposed to the T1 stack) but it doesn't have to */ + /* put them there by itself; previous othersubrs might */ + /* have left the operands there if they were not */ + /* followed by an appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux */ + /* doesn't accept a font that contains charstrings */ + /* like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray */ + /* exists. */ + + switch ( subr_no ) + { + case 0: /* end flex feature */ + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + + if ( initial_map_ready && + ( !decoder->flex_state || + decoder->num_flex_vectors != 7 ) ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " unexpected flex end\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* the two `results' are popped */ + /* by the following setcurrentpoint */ + cf2_stack_pushFixed( opStack, curX ); + cf2_stack_pushFixed( opStack, curY ); + known_othersubr_result_cnt = 2; + break; + + case 1: /* start flex feature */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !initial_map_ready ) + break; + + if ( ps_builder_check_points( &decoder->builder, 6 ) ) + goto exit; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + break; + + case 2: /* add flex vectors */ + { + FT_Int idx; + FT_Int idx2; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !initial_map_ready ) + break; + + if ( !decoder->flex_state ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " missing flex start\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* note that we should not add a point for */ + /* index 0; this will move our current position */ + /* to the flex point without adding any point */ + /* to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + { + /* in malformed fonts it is possible to have */ + /* other opcodes in the middle of a flex (which */ + /* don't increase `num_flex_vectors'); we thus */ + /* have to check whether we can add a point */ + + if ( ps_builder_check_points( &decoder->builder, + 1 ) ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* map: 1->2 2->4 3->6 4->2 5->4 6->6 */ + idx2 = ( idx > 3 ? idx - 3 : idx ) * 2; + + flexStore[idx2 - 2] = curX; + flexStore[idx2 - 1] = curY; + + if ( idx == 3 || idx == 6 ) + cf2_glyphpath_curveTo( &glyphPath, + flexStore[0], + flexStore[1], + flexStore[2], + flexStore[3], + flexStore[4], + flexStore[5] ); + } + } + break; + + case 3: /* change hints */ + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + + if ( initial_map_ready ) + { + /* do not clear hints if initial hintmap */ + /* is not ready - we need to collate all */ + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); + + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + } + + known_othersubr_result_cnt = 1; + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + cf2_stack_clear( opStack ); + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + CF2_UInt delta; + CF2_UInt values; + + + if ( !blend ) + { + FT_ERROR(( + "cf2_interpT2CharString:" + " unexpected multiple masters operator\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + num_points = (FT_UInt)subr_no - 13 + + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * + blend->num_designs ) ) + { + FT_ERROR(( + "cf2_interpT2CharString:" + " incorrect number of multiple masters arguments\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* We want to compute */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ + /* */ + /* However, given that w0 + w1 + ... + wk == 1, we */ + /* can rewrite it easily as */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1. */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = opIdx + num_points; + values = opIdx; + for ( nn = 0; nn < num_points; nn++ ) + { + CF2_Fixed tmp = cf2_stack_getReal( opStack, + values ); + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp = ADD_INT32( tmp, + FT_MulFix( + cf2_stack_getReal( opStack, + delta++ ), + blend->weight_vector[mm] ) ); + + cf2_stack_setReal( opStack, values++, tmp ); + } + cf2_stack_pop( opStack, + (CF2_UInt)arg_cnt - num_points ); + + known_othersubr_result_cnt = (FT_Int)num_points; + break; + } + + case 19: + /* 1 19 callothersubr */ + /* ==> replace elements starting from index */ + /* cvi( ) of BuildCharArray with */ + /* WeightVector */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + FT_UInt len_buildchar = decoder->len_buildchar; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = (FT_UInt)cf2_stack_popInt( opStack ); + + if ( len_buildchar < blend->num_designs || + len_buildchar - blend->num_designs < idx ) + goto Unexpected_OtherSubr; + + if ( decoder->buildchar && blend->weight_vector ) + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); + } + break; + + case 20: + /* 2 20 callothersubr pop */ + /* ==> push + onto T1 stack */ + { + CF2_F16Dot16 summand1; + CF2_F16Dot16 summand2; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + summand2 = cf2_stack_popFixed( opStack ); + summand1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + ADD_INT32( summand1, + summand2 ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 21: + /* 2 21 callothersubr pop */ + /* ==> push - onto T1 stack */ + { + CF2_F16Dot16 minuend; + CF2_F16Dot16 subtrahend; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + subtrahend = cf2_stack_popFixed( opStack ); + minuend = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + SUB_INT32( minuend, + subtrahend ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 22: + /* 2 22 callothersubr pop */ + /* ==> push * onto T1 stack */ + { + CF2_F16Dot16 factor1; + CF2_F16Dot16 factor2; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + factor2 = cf2_stack_popFixed( opStack ); + factor1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + FT_MulFix( factor1, factor2 ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 23: + /* 2 23 callothersubr pop */ + /* ==> push / onto T1 stack */ + { + CF2_F16Dot16 dividend; + CF2_F16Dot16 divisor; + + + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + divisor = cf2_stack_popFixed( opStack ); + dividend = cf2_stack_popFixed( opStack ); + + if ( divisor == 0 ) + goto Unexpected_OtherSubr; + + cf2_stack_pushFixed( opStack, + FT_DivFix( dividend, + divisor ) ); + known_othersubr_result_cnt = 1; + } + break; + + case 24: + /* 2 24 callothersubr */ + /* ==> set BuildCharArray[cvi( )] = */ + { + CF2_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 2 || !blend ) + goto Unexpected_OtherSubr; + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = + cf2_stack_popFixed( opStack ); + } + break; + + case 25: + /* 1 25 callothersubr pop */ + /* ==> push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + CF2_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + cf2_stack_pushFixed( opStack, + decoder->buildchar[idx] ); + known_othersubr_result_cnt = 1; + } + break; + +#if 0 + case 26: + /* mark */ + /* ==> set BuildCharArray[cvi( )] = , */ + /* leave mark on T1 stack */ + /* */ + /* ==> set BuildCharArray[cvi( )] = */ + XXX which routine has left its mark on the + XXX (PostScript) stack?; + break; +#endif + + case 27: + /* 4 27 callothersubr pop */ + /* ==> push onto T1 stack if <= , */ + /* otherwise push */ + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + CF2_F16Dot16 cond1; + CF2_F16Dot16 cond2; + + + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + cond2 = cf2_stack_popFixed( opStack ); + cond1 = cf2_stack_popFixed( opStack ); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + cond1 <= cond2 ? arg1 : arg2 ); + known_othersubr_result_cnt = 1; + } + break; + + case 28: + /* 0 28 callothersubr pop */ + /* ==> push random value from interval [0, 1) */ + /* onto stack */ + { + CF2_F16Dot16 r; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + r = (CF2_F16Dot16) + ( ( decoder->current_subfont->random & 0xFFFF ) + 1 ); + + decoder->current_subfont->random = + cff_random( decoder->current_subfont->random ); + + cf2_stack_pushFixed( opStack, r ); + known_othersubr_result_cnt = 1; + } + break; + + default: + if ( arg_cnt >= 0 && subr_no >= 0 ) + { + FT_Int i; + + + FT_ERROR(( + "cf2_interpT2CharString (Type 1 mode):" + " unknown othersubr [%d %d], wish me luck\n", + arg_cnt, subr_no )); + + /* store the unused args */ + /* for this unhandled OtherSubr */ + + if ( arg_cnt > PS_STORAGE_SIZE ) + arg_cnt = PS_STORAGE_SIZE; + result_cnt = arg_cnt; + + for ( i = 1; i <= arg_cnt; i++ ) + results[result_cnt - i] = + cf2_stack_popFixed( opStack ); + + break; + } + /* fall through */ + + Unexpected_OtherSubr: + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " invalid othersubr [%d %d]\n", + arg_cnt, subr_no )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + } + continue; /* do not clear the stack */ + + case cf2_escPOP: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_TRACE4(( " pop" )); + + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; + /* ignore, we pushed the operands ourselves */ + continue; + } + + if ( result_cnt == 0 ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no more operands for othersubr\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + result_cnt--; + cf2_stack_pushFixed( opStack, results[result_cnt] ); + } + continue; /* do not clear the stack */ + + case cf2_escDROP: + FT_TRACE4(( " drop\n" )); + + (void)cf2_stack_popFixed( opStack ); + continue; /* do not clear the stack */ + + case cf2_escPUT: + { + CF2_F16Dot16 val; + CF2_UInt idx; + + + FT_TRACE4(( " put\n" )); + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + val = cf2_stack_popFixed( opStack ); + + if ( idx < CF2_STORAGE_SIZE ) + storage[idx] = val; + } + continue; /* do not clear the stack */ + + case cf2_escGET: + { + CF2_UInt idx; + + + FT_TRACE4(( " get\n" )); + + idx = (CF2_UInt)cf2_stack_popInt( opStack ); + + if ( idx < CF2_STORAGE_SIZE ) + cf2_stack_pushFixed( opStack, storage[idx] ); + } + continue; /* do not clear the stack */ + + case cf2_escIFELSE: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + CF2_F16Dot16 cond1; + CF2_F16Dot16 cond2; + + + FT_TRACE4(( " ifelse\n" )); + + cond2 = cf2_stack_popFixed( opStack ); + cond1 = cf2_stack_popFixed( opStack ); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + cond1 <= cond2 ? arg1 : arg2 ); + } + continue; /* do not clear the stack */ + + case cf2_escRANDOM: /* in spec */ + { + CF2_F16Dot16 r; + + + FT_TRACE4(( " random\n" )); + + /* only use the lower 16 bits of `random' */ + /* to generate a number in the range (0;1] */ + r = (CF2_F16Dot16) + ( ( decoder->current_subfont->random & 0xFFFF ) + 1 ); + + decoder->current_subfont->random = + cff_random( decoder->current_subfont->random ); + + cf2_stack_pushFixed( opStack, r ); + } + continue; /* do not clear the stack */ + + case cf2_escMUL: + { + CF2_F16Dot16 factor1; + CF2_F16Dot16 factor2; + + + FT_TRACE4(( " mul\n" )); + + factor2 = cf2_stack_popFixed( opStack ); + factor1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, + FT_MulFix( factor1, factor2 ) ); + } + continue; /* do not clear the stack */ + + case cf2_escSQRT: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " sqrt\n" )); + + arg = cf2_stack_popFixed( opStack ); + if ( arg > 0 ) + arg = (CF2_F16Dot16)FT_SqrtFixed( (FT_UInt32)arg ); + else + arg = 0; + + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ + + case cf2_escDUP: + { + CF2_F16Dot16 arg; + + + FT_TRACE4(( " dup\n" )); + + arg = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, arg ); + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ + + case cf2_escEXCH: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + + + FT_TRACE4(( " exch\n" )); + + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); + + cf2_stack_pushFixed( opStack, arg2 ); + cf2_stack_pushFixed( opStack, arg1 ); + } + continue; /* do not clear the stack */ + + case cf2_escINDEX: + { + CF2_Int idx; + CF2_UInt size; + + + FT_TRACE4(( " index\n" )); + + idx = cf2_stack_popInt( opStack ); + size = cf2_stack_count( opStack ); + + if ( size > 0 ) + { + /* for `cf2_stack_getReal', */ + /* index 0 is bottom of stack */ + CF2_UInt gr_idx; + + + if ( idx < 0 ) + gr_idx = size - 1; + else if ( (CF2_UInt)idx >= size ) + gr_idx = 0; + else + gr_idx = size - 1 - (CF2_UInt)idx; + + cf2_stack_pushFixed( opStack, + cf2_stack_getReal( opStack, + gr_idx ) ); + } + } + continue; /* do not clear the stack */ + + case cf2_escROLL: + { + CF2_Int idx; + CF2_Int count; + + + FT_TRACE4(( " roll\n" )); + + idx = cf2_stack_popInt( opStack ); + count = cf2_stack_popInt( opStack ); + + cf2_stack_roll( opStack, count, idx ); + } + continue; /* do not clear the stack */ + + case cf2_escSETCURRENTPT: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + FT_TRACE4(( " setcurrentpoint" )); + + if ( !initial_map_ready ) + break; + + /* From the T1 specification, section 6.4: */ + /* */ + /* The setcurrentpoint command is used only in */ + /* conjunction with results from OtherSubrs */ + /* procedures. */ + + /* known_othersubr_result_cnt != 0 is already handled */ + /* above. */ + + /* Note, however, that both Ghostscript and Adobe */ + /* Distiller handle this situation by silently */ + /* ignoring the inappropriate `setcurrentpoint' */ + /* instruction. So we do the same. */ +#if 0 + + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "cf2_interpT2CharString:" + " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + } + else + ... +#endif + + curY = cf2_stack_popFixed( opStack ); + curX = cf2_stack_popFixed( opStack ); + + decoder->flex_state = 0; + } + break; + + } /* end of 2nd switch checking op2 */ + } + } + } /* end of 1st switch checking op2 */ + } /* case cf2_cmdESC */ + + break; + + case cf2_cmdHSBW: + if ( !font->isT1 ) + FT_TRACE4(( " unknown op (%d)\n", op1 )); + else + { + CF2_Fixed lsb_x; + PS_Builder* builder; + + + FT_TRACE4(( " hsbw\n" )); + + builder = &decoder->builder; + + builder->advance->x = cf2_stack_popFixed( opStack ); + builder->advance->y = 0; + + lsb_x = cf2_stack_popFixed( opStack ); + + builder->left_bearing->x = ADD_INT32( builder->left_bearing->x, + lsb_x ); + + haveWidth = TRUE; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + goto exit; + + if ( initial_map_ready ) + curX = ADD_INT32( curX, lsb_x ); + } + break; + + case cf2_cmdENDCHAR: + FT_TRACE4(( " endchar\n" )); + + if ( font->isT1 && !initial_map_ready ) + { + FT_TRACE5(( "cf2_interpT2CharString (Type 1 mode): " + "Build initial hintmap, rewinding...\n" )); + + /* trigger initial hintmap build */ + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + initial_map_ready = TRUE; + + /* change hints routine - clear for rewind */ + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); + + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + + /* rewind charstring */ + /* some charstrings use endchar from a final subroutine call */ + /* without returning, detect these and exit to the top level */ + /* charstring */ + while ( charstringIndex > 0 ) + { + FT_TRACE4(( " return (leaving level %d)\n", charstringIndex )); + + /* restore position in previous charstring */ + charstring = (CF2_Buffer) + cf2_arrstack_getPointer( + &subrStack, + (CF2_UInt)--charstringIndex ); + } + charstring->ptr = charstring->start; + + break; + } + + if ( cf2_stack_count( opStack ) == 1 || + cf2_stack_count( opStack ) == 5 ) + { + if ( !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + } + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + /* close path if still open */ + cf2_glyphpath_closeOpenPath( &glyphPath ); + + /* disable seac for CFF2 and Type1 */ + /* (charstring ending with args on stack) */ + if ( !font->isCFF2 && !font->isT1 && cf2_stack_count( opStack ) > 1 ) + { + /* must be either 4 or 5 -- */ + /* this is a (deprecated) implied `seac' operator */ + + CF2_Int achar; + CF2_Int bchar; + CF2_BufferRec component; + CF2_Fixed dummyWidth; /* ignore component width */ + FT_Error error2; + + + if ( doingSeac ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; /* nested seac */ + } + + achar = cf2_stack_popInt( opStack ); + bchar = cf2_stack_popInt( opStack ); + + curY = cf2_stack_popFixed( opStack ); + curX = cf2_stack_popFixed( opStack ); + + error2 = cf2_getSeacComponent( decoder, achar, &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + curX, + curY, + &dummyWidth ); + cf2_freeSeacComponent( decoder, &component ); + + error2 = cf2_getSeacComponent( decoder, bchar, &component ); + if ( error2 ) + { + lastError = error2; /* pass FreeType error through */ + goto exit; + } + cf2_interpT2CharString( font, + &component, + callbacks, + translation, + TRUE, + 0, + 0, + &dummyWidth ); + cf2_freeSeacComponent( decoder, &component ); + } + goto exit; + + case cf2_cmdCNTRMASK: + case cf2_cmdHINTMASK: + /* the final \n in the tracing message gets added in */ + /* `cf2_hintmask_read' (which also traces the mask bytes) */ + FT_TRACE4(( "%s", op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" )); + + /* never add hints after the mask is computed */ + if ( cf2_stack_count( opStack ) > 1 && + cf2_hintmask_isValid( &hintMask ) ) + { + FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" )); + break; + } + + /* if there are arguments on the stack, there this is an */ + /* implied cf2_cmdVSTEMHM */ + cf2_doStems( font, + opStack, + &vStemHintArray, + width, + &haveWidth, + 0 ); + + if ( decoder->width_only ) + goto exit; + + if ( op1 == cf2_cmdHINTMASK ) + { + /* consume the hint mask bytes which follow the operator */ + cf2_hintmask_read( &hintMask, + charstring, + cf2_arrstack_size( &hStemHintArray ) + + cf2_arrstack_size( &vStemHintArray ) ); + } + else + { + /* + * Consume the counter mask bytes which follow the operator: + * Build a temporary hint map, just to place and lock those + * stems participating in the counter mask. These are most + * likely the dominant hstems, and are grouped together in a + * few counter groups, not necessarily in correspondence + * with the hint groups. This reduces the chances of + * conflicts between hstems that are initially placed in + * separate hint groups and then brought together. The + * positions are copied back to `hStemHintArray', so we can + * discard `counterMask' and `counterHintMap'. + * + */ + CF2_HintMapRec counterHintMap; + CF2_HintMaskRec counterMask; + + + cf2_hintmap_init( &counterHintMap, + font, + &glyphPath.initialHintMap, + &glyphPath.hintMoves, + scaleY ); + cf2_hintmask_init( &counterMask, error ); + + cf2_hintmask_read( &counterMask, + charstring, + cf2_arrstack_size( &hStemHintArray ) + + cf2_arrstack_size( &vStemHintArray ) ); + cf2_hintmap_build( &counterHintMap, + &hStemHintArray, + &vStemHintArray, + &counterMask, + 0, + FALSE ); + } + break; + + case cf2_cmdRMOVETO: + FT_TRACE4(( " rmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 2 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) ); + curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdHMOVETO: + FT_TRACE4(( " hmoveto\n" )); + + if ( font->isT1 && !decoder->flex_state && !haveWidth ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " No width. Use hsbw/sbw as first op\n" )); + + if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) + *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ), + nominalWidthX ); + + /* width is defined or default after this */ + haveWidth = TRUE; + + if ( decoder->width_only ) + goto exit; + + curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) ); + + if ( !decoder->flex_state ) + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + break; + + case cf2_cmdRLINECURVE: + { + CF2_UInt count = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + FT_TRACE4(( " rlinecurve\n" )); + + while ( idx + 6 < count ) + { + curX = ADD_INT32( curX, cf2_stack_getReal( opStack, + idx + 0 ) ); + curY = ADD_INT32( curY, cf2_stack_getReal( opStack, + idx + 1 ) ); + + cf2_glyphpath_lineTo( &glyphPath, curX, curY ); + idx += 2; + } + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 6; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdVVCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( " vvcurveto\n" )); + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + if ( ( count - idx ) & 1 ) + { + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curX ); + + idx++; + } + else + x1 = curX; + + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = x2; + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 ); + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdHHCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + + /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ + /* we enforce it by clearing the second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( " hhcurveto\n" )); + + while ( idx < count ) + { + CF2_Fixed x1, y1, x2, y2, x3, y3; + + + if ( ( count - idx ) & 1 ) + { + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curY ); + + idx++; + } + else + y1 = curY; + + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 ); + y3 = y2; + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdVHCURVETO: + case cf2_cmdHVCURVETO: + { + CF2_UInt count, count1 = cf2_stack_count( opStack ); + CF2_UInt idx = 0; + + FT_Bool alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO ); + + + /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */ + /* 8n+4, or 8n+5, we enforce it by clearing the */ + /* second bit */ + /* (and sorting the stack indexing to suit) */ + count = count1 & ~2U; + idx += count1 - count; + + FT_TRACE4(( "%s\n", alternate ? " hvcurveto" : " vhcurveto" )); + + while ( idx < count ) + { + CF2_Fixed x1, x2, x3, y1, y2, y3; + + + if ( alternate ) + { + x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX ); + y1 = curY; + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 ); + + if ( count - idx == 5 ) + { + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 ); + + idx++; + } + else + x3 = x2; + + alternate = FALSE; + } + else + { + x1 = curX; + y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY ); + x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 ); + y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 ); + x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 ); + + if ( count - idx == 5 ) + { + y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), y2 ); + + idx++; + } + else + y3 = y2; + + alternate = TRUE; + } + + cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); + + curX = x3; + curY = y3; + idx += 4; + } + + cf2_stack_clear( opStack ); + } + continue; /* no need to clear stack again */ + + case cf2_cmdEXTENDEDNMBR: + { + CF2_Int v; + + CF2_Int byte1 = cf2_buf_readByte( charstring ); + CF2_Int byte2 = cf2_buf_readByte( charstring ); + + + v = (FT_Short)( ( byte1 << 8 ) | + byte2 ); + + FT_TRACE4(( " %d", v )); + + cf2_stack_pushInt( opStack, v ); + } + continue; + + default: + /* numbers */ + { + if ( /* op1 >= 32 && */ op1 <= 246 ) + { + CF2_Int v; + + + v = op1 - 139; + + FT_TRACE4(( " %d", v )); + + /* -107 .. 107 */ + cf2_stack_pushInt( opStack, v ); + } + + else if ( /* op1 >= 247 && */ op1 <= 250 ) + { + CF2_Int v; + + + v = op1; + v -= 247; + v *= 256; + v += cf2_buf_readByte( charstring ); + v += 108; + + FT_TRACE4(( " %d", v )); + + /* 108 .. 1131 */ + cf2_stack_pushInt( opStack, v ); + } + + else if ( /* op1 >= 251 && */ op1 <= 254 ) + { + CF2_Int v; + + + v = op1; + v -= 251; + v *= 256; + v += cf2_buf_readByte( charstring ); + v = -v - 108; + + FT_TRACE4(( " %d", v )); + + /* -1131 .. -108 */ + cf2_stack_pushInt( opStack, v ); + } + + else /* op1 == 255 */ + { + CF2_Fixed v; + + FT_UInt32 byte1 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte2 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte3 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte4 = (FT_UInt32)cf2_buf_readByte( charstring ); + + + v = (CF2_Fixed)( ( byte1 << 24 ) | + ( byte2 << 16 ) | + ( byte3 << 8 ) | + byte4 ); + + /* + * For Type 1: + * + * According to the specification, values > 32000 or < -32000 + * must be followed by a `div' operator to make the result be + * in the range [-32000;32000]. We expect that the second + * argument of `div' is not a large number. Additionally, we + * don't handle stuff like ` div + * div' or div div'. This is probably + * not allowed anyway. + * + * + div is not checked but should not be + * allowed as the large value remains untouched. + * + */ + if ( font->isT1 ) + { + if ( v > 32000 || v < -32000 ) + { + if ( large_int ) + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " no `div' after large integer\n" )); + else + large_int = TRUE; + } + + FT_TRACE4(( " %d", v )); + + cf2_stack_pushInt( opStack, (CF2_Int)v ); + } + else + { + FT_TRACE4(( " %.5fF", v / 65536.0 )); + + cf2_stack_pushFixed( opStack, v ); + } + } + } + continue; /* don't clear stack */ + + } /* end of switch statement checking `op1' */ + + cf2_stack_clear( opStack ); + + } /* end of main interpreter loop */ + + /* we get here if the charstring ends without cf2_cmdENDCHAR */ + FT_TRACE4(( "cf2_interpT2CharString:" + " charstring ends without ENDCHAR\n" )); + + exit: + /* check whether last error seen is also the first one */ + cf2_setError( error, lastError ); + + if ( *error ) + FT_TRACE4(( "charstring error %d\n", *error )); + + /* free resources from objects we've used */ + cf2_glyphpath_finalize( &glyphPath ); + cf2_arrstack_finalize( &vStemHintArray ); + cf2_arrstack_finalize( &hStemHintArray ); + cf2_arrstack_finalize( &subrStack ); + cf2_stack_free( opStack ); + + FT_TRACE4(( "\n" )); + + return; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psintrp.h b/Dependencies/freetype/freetype/src/psaux/psintrp.h new file mode 100644 index 00000000..d8b9342e --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psintrp.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * + * psintrp.h + * + * Adobe's CFF Interpreter (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSINTRP_H_ +#define PSINTRP_H_ + + +#include "psft.h" +#include "pshints.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + cf2_hintmask_init( CF2_HintMask hintmask, + FT_Error* error ); + FT_LOCAL( FT_Bool ) + cf2_hintmask_isValid( const CF2_HintMask hintmask ); + FT_LOCAL( FT_Bool ) + cf2_hintmask_isNew( const CF2_HintMask hintmask ); + FT_LOCAL( void ) + cf2_hintmask_setNew( CF2_HintMask hintmask, + FT_Bool val ); + FT_LOCAL( FT_Byte* ) + cf2_hintmask_getMaskPtr( CF2_HintMask hintmask ); + FT_LOCAL( void ) + cf2_hintmask_setAll( CF2_HintMask hintmask, + size_t bitCount ); + + FT_LOCAL( void ) + cf2_interpT2CharString( CF2_Font font, + const CF2_Buffer buf, + CF2_OutlineCallbacks callbacks, + const FT_Vector* translation, + FT_Bool doingSeac, + CF2_Fixed curX, + CF2_Fixed curY, + CF2_Fixed* width ); + + +FT_END_HEADER + + +#endif /* PSINTRP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psobjs.c b/Dependencies/freetype/freetype/src/psaux/psobjs.c new file mode 100644 index 00000000..eca465f0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psobjs.c @@ -0,0 +1,2560 @@ +/**************************************************************************** + * + * psobjs.c + * + * Auxiliary functions for PostScript fonts (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "psobjs.h" +#include "psconv.h" +#include "psft.h" + +#include "psauxerr.h" +#include "psauxmod.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT psobjs + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * ps_table_new + * + * @Description: + * Initializes a PS_Table. + * + * @InOut: + * table :: + * The address of the target table. + * + * @Input: + * count :: + * The table size = the maximum number of elements. + * + * memory :: + * The memory object to use for all subsequent + * reallocations. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + + table->memory = memory; + if ( FT_NEW_ARRAY( table->elements, count ) || + FT_NEW_ARRAY( table->lengths, count ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xDEADBEEFUL; + table->block = NULL; + table->capacity = 0; + table->cursor = 0; + + *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; + + Exit: + if ( error ) + FT_FREE( table->elements ); + + return error; + } + + + static FT_Error + ps_table_realloc( PS_Table table, + FT_Offset new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + + /* (re)allocate the base block */ + if ( FT_REALLOC( table->block, table->capacity, new_size ) ) + return error; + + /* rebase offsets if necessary */ + if ( old_base && table->block != old_base ) + { + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + for ( ; offset < limit; offset++ ) + { + if ( *offset ) + *offset = table->block + ( *offset - old_base ); + } + } + + table->capacity = new_size; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * ps_table_add + * + * @Description: + * Adds an object to a PS_Table, possibly growing its memory block. + * + * @InOut: + * table :: + * The target table. + * + * @Input: + * idx :: + * The index of the object in the table. + * + * object :: + * The address of the object to copy in memory. + * + * length :: + * The length in bytes of the source object. + * + * @Return: + * FreeType error code. 0 means success. An error is returned if a + * reallocation fails. + */ + FT_LOCAL_DEF( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ) + { + if ( idx < 0 || idx >= table->max_elems ) + { + FT_ERROR(( "ps_table_add: invalid index\n" )); + return FT_THROW( Invalid_Argument ); + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Offset new_size = table->capacity; + FT_PtrDist in_offset; + + + in_offset = (FT_Byte*)object - table->block; + if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity ) + in_offset = -1; + + while ( new_size < table->cursor + length ) + { + /* increase size by 25% and round up to the nearest multiple + of 1024 */ + new_size += ( new_size >> 2 ) + 1; + new_size = FT_PAD_CEIL( new_size, 1024 ); + } + + error = ps_table_realloc( table, new_size ); + if ( error ) + return error; + + if ( in_offset >= 0 ) + object = table->block + in_offset; + } + + /* add the object to the base block and adjust offset */ + table->elements[idx] = FT_OFFSET( table->block, table->cursor ); + table->lengths [idx] = length; + /* length == 0 also implies a NULL destination, so skip the copy call */ + if ( length > 0 ) + FT_MEM_COPY( table->block + table->cursor, object, length ); + + table->cursor += length; + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * ps_table_done + * + * @Description: + * Finalizes a PS_TableRec (i.e., reallocate it to its current + * cursor). + * + * @InOut: + * table :: + * The target table. + */ + FT_LOCAL_DEF( void ) + ps_table_done( PS_Table table ) + { + /* no problem if shrinking fails */ + ps_table_realloc( table, table->cursor ); + } + + + FT_LOCAL_DEF( void ) + ps_table_release( PS_Table table ) + { + FT_Memory memory = table->memory; + + + if ( table->init == 0xDEADBEEFUL ) + { + FT_FREE( table->block ); + FT_FREE( table->elements ); + FT_FREE( table->lengths ); + table->init = 0; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* first character must be already part of the comment */ + + static void + skip_comment( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( IS_PS_NEWLINE( *cur ) ) + break; + cur++; + } + + *acur = cur; + } + + + static void + skip_spaces( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + + + while ( cur < limit ) + { + if ( !IS_PS_SPACE( *cur ) ) + { + if ( *cur == '%' ) + /* According to the PLRM, a comment is equal to a space. */ + skip_comment( &cur, limit ); + else + break; + } + cur++; + } + + *acur = cur; + } + + +#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) + + + /* first character must be `('; */ + /* *acur is positioned at the character after the closing `)' */ + + static FT_Error + skip_literal_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Int embed = 0; + FT_Error error = FT_ERR( Invalid_File_Format ); + unsigned int i; + + + while ( cur < limit ) + { + FT_Byte c = *cur; + + + cur++; + + if ( c == '\\' ) + { + /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ + /* A backslash can introduce three different types */ + /* of escape sequences: */ + /* - a special escaped char like \r, \n, etc. */ + /* - a one-, two-, or three-digit octal number */ + /* - none of the above in which case the backslash is ignored */ + + if ( cur == limit ) + /* error (or to be ignored?) */ + break; + + switch ( *cur ) + { + /* skip `special' escape */ + case 'n': + case 'r': + case 't': + case 'b': + case 'f': + case '\\': + case '(': + case ')': + cur++; + break; + + default: + /* skip octal escape or ignore backslash */ + for ( i = 0; i < 3 && cur < limit; i++ ) + { + if ( !IS_OCTAL_DIGIT( *cur ) ) + break; + + cur++; + } + } + } + else if ( c == '(' ) + embed++; + else if ( c == ')' ) + { + embed--; + if ( embed == 0 ) + { + error = FT_Err_Ok; + break; + } + } + } + + *acur = cur; + + return error; + } + + + /* first character must be `<' */ + + static FT_Error + skip_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Error err = FT_Err_Ok; + + + while ( ++cur < limit ) + { + /* All whitespace characters are ignored. */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; + + if ( !IS_PS_XDIGIT( *cur ) ) + break; + } + + if ( cur < limit && *cur != '>' ) + { + FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); + err = FT_THROW( Invalid_File_Format ); + } + else + cur++; + + *acur = cur; + return err; + } + + + /* first character must be the opening brace that */ + /* starts the procedure */ + + /* NB: [ and ] need not match: */ + /* `/foo {[} def' is a valid PostScript fragment, */ + /* even within a Type1 font */ + + static FT_Error + skip_procedure( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur; + FT_Int embed = 0; + FT_Error error = FT_Err_Ok; + + + FT_ASSERT( **acur == '{' ); + + for ( cur = *acur; cur < limit && error == FT_Err_Ok; cur++ ) + { + switch ( *cur ) + { + case '{': + embed++; + break; + + case '}': + embed--; + if ( embed == 0 ) + { + cur++; + goto end; + } + break; + + case '(': + error = skip_literal_string( &cur, limit ); + break; + + case '<': + error = skip_string( &cur, limit ); + break; + + case '%': + skip_comment( &cur, limit ); + break; + } + } + + end: + if ( embed != 0 ) + error = FT_THROW( Invalid_File_Format ); + + *acur = cur; + + return error; + } + + + /************************************************************************ + * + * All exported parsing routines handle leading whitespace and stop at + * the first character which isn't part of the just handled token. + * + */ + + + FT_LOCAL_DEF( void ) + ps_parser_skip_PS_token( PS_Parser parser ) + { + /* Note: PostScript allows any non-delimiting, non-whitespace */ + /* character in a name (PS Ref Manual, 3rd ed, p31). */ + /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ + + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + FT_Error error = FT_Err_Ok; + + + skip_spaces( &cur, limit ); /* this also skips comments */ + if ( cur >= limit ) + goto Exit; + + /* self-delimiting, single-character tokens */ + if ( *cur == '[' || *cur == ']' ) + { + cur++; + goto Exit; + } + + /* skip balanced expressions (procedures and strings) */ + + if ( *cur == '{' ) /* {...} */ + { + error = skip_procedure( &cur, limit ); + goto Exit; + } + + if ( *cur == '(' ) /* (...) */ + { + error = skip_literal_string( &cur, limit ); + goto Exit; + } + + if ( *cur == '<' ) /* <...> */ + { + if ( cur + 1 < limit && *( cur + 1 ) == '<' ) /* << */ + { + cur++; + cur++; + } + else + error = skip_string( &cur, limit ); + + goto Exit; + } + + if ( *cur == '>' ) + { + cur++; + if ( cur >= limit || *cur != '>' ) /* >> */ + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " unexpected closing delimiter `>'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + cur++; + goto Exit; + } + + if ( *cur == '/' ) + cur++; + + /* anything else */ + while ( cur < limit ) + { + /* *cur might be invalid (e.g., ')' or '}'), but this */ + /* is handled by the test `cur == parser->cursor' below */ + if ( IS_PS_DELIM( *cur ) ) + break; + + cur++; + } + + Exit: + if ( cur < limit && cur == parser->cursor ) + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " current token is `%c' which is self-delimiting\n", + *cur )); + FT_ERROR(( " " + " but invalid at this point\n" )); + + error = FT_THROW( Invalid_File_Format ); + } + + if ( cur > limit ) + cur = limit; + + parser->error = error; + parser->cursor = cur; + } + + + FT_LOCAL_DEF( void ) + ps_parser_skip_spaces( PS_Parser parser ) + { + skip_spaces( &parser->cursor, parser->limit ); + } + + + /* `token' here means either something between balanced delimiters */ + /* or the next token; the delimiters are not removed. */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Int embed; + + + token->type = T1_TOKEN_TYPE_NONE; + token->start = NULL; + token->limit = NULL; + + /* first of all, skip leading whitespace */ + ps_parser_skip_spaces( parser ); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur >= limit ) + return; + + switch ( *cur ) + { + /************* check for literal string *****************/ + case '(': + token->type = T1_TOKEN_TYPE_STRING; + token->start = cur; + + if ( skip_literal_string( &cur, limit ) == FT_Err_Ok ) + token->limit = cur; + break; + + /************* check for programs/array *****************/ + case '{': + token->type = T1_TOKEN_TYPE_ARRAY; + token->start = cur; + + if ( skip_procedure( &cur, limit ) == FT_Err_Ok ) + token->limit = cur; + break; + + /************* check for table/array ********************/ + /* XXX: in theory we should also look for "<<" */ + /* since this is semantically equivalent to "["; */ + /* in practice it doesn't matter (?) */ + case '[': + token->type = T1_TOKEN_TYPE_ARRAY; + embed = 1; + token->start = cur++; + + /* we need this to catch `[ ]' */ + parser->cursor = cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + while ( cur < limit && !parser->error ) + { + /* XXX: this is wrong because it does not */ + /* skip comments, procedures, and strings */ + if ( *cur == '[' ) + embed++; + else if ( *cur == ']' ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = ++cur; + break; + } + } + + parser->cursor = cur; + ps_parser_skip_PS_token( parser ); + /* we need this to catch `[XXX ]' */ + ps_parser_skip_spaces ( parser ); + cur = parser->cursor; + } + break; + + /* ************ otherwise, it is any token **************/ + default: + token->start = cur; + token->type = ( *cur == '/' ) ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY; + ps_parser_skip_PS_token( parser ); + cur = parser->cursor; + if ( !parser->error ) + token->limit = cur; + } + + if ( !token->limit ) + { + token->start = NULL; + token->type = T1_TOKEN_TYPE_NONE; + } + + parser->cursor = cur; + } + + + /* NB: `tokens' can be NULL if we only want to count */ + /* the number of array elements */ + + FT_LOCAL_DEF( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + T1_TokenRec master; + + + *pnum_tokens = -1; + + /* this also handles leading whitespace */ + ps_parser_to_token( parser, &master ); + + if ( master.type == T1_TOKEN_TYPE_ARRAY ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + T1_Token cur = tokens; + T1_Token limit = cur + max_tokens; + + + /* don't include outermost delimiters */ + parser->cursor = master.start + 1; + parser->limit = master.limit - 1; + + while ( parser->cursor < parser->limit ) + { + T1_TokenRec token; + + + ps_parser_to_token( parser, &token ); + if ( !token.type ) + break; + + if ( tokens && cur < limit ) + *cur = token; + + cur++; + } + + *pnum_tokens = (FT_Int)( cur - tokens ); + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `coords' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_coords' */ + + static FT_Int + ps_tocoordarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* check for the beginning of an array; otherwise, only one number */ + /* will be read */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the coordinates */ + while ( cur < limit ) + { + FT_Short dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( coords && count >= max_coords ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( coords ? &coords[count] : &dummy ) = + (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + + /* first character must be a delimiter or a part of a number */ + /* NB: `values' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_values' */ + /* */ + /* return number of successfully parsed values */ + + static FT_Int + ps_tofixedarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + + + if ( cur >= limit ) + goto Exit; + + /* Check for the beginning of an array. Otherwise, only one number */ + /* will be read. */ + c = *cur; + ender = 0; + + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + + if ( ender ) + cur++; + + /* now, read the values */ + while ( cur < limit ) + { + FT_Fixed dummy; + FT_Byte* old_cur; + + + /* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + + if ( *cur == ender ) + { + cur++; + break; + } + + old_cur = cur; + + if ( values && count >= max_values ) + break; + + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( values ? &values[count] : &dummy ) = + PS_Conv_ToFixed( &cur, limit, power_ten ); + + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + + if ( !ender ) + break; + } + + Exit: + *acur = cur; + return count; + } + + +#if 0 + + static FT_String* + ps_tostring( FT_Byte** cursor, + FT_Byte* limit, + FT_Memory memory ) + { + FT_Byte* cur = *cursor; + FT_UInt len = 0; + FT_Int count; + FT_String* result; + FT_Error error; + + + /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ + /* that simply doesn't begin with an opening parenthesis, even */ + /* though they have a closing one! E.g. "amuncial.pfb" */ + /* */ + /* We must deal with these ill-fated cases there. Note that */ + /* these fonts didn't work with the old Type 1 driver as the */ + /* notice/copyright was not recognized as a valid string token */ + /* and made the old token parser commit errors. */ + + while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) + cur++; + if ( cur + 1 >= limit ) + return 0; + + if ( *cur == '(' ) + cur++; /* skip the opening parenthesis, if there is one */ + + *cursor = cur; + count = 0; + + /* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if ( *cur == '(' ) + count++; + + else if ( *cur == ')' ) + { + count--; + if ( count < 0 ) + break; + } + } + + len = (FT_UInt)( cur - *cursor ); + if ( cur >= limit || FT_QALLOC( result, len + 1 ) ) + return 0; + + /* now copy the string */ + FT_MEM_COPY( result, *cursor, len ); + result[len] = '\0'; + *cursor = cur; + return result; + } + +#endif /* 0 */ + + + static int + ps_tobool( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Bool result = 0; + + + /* return 1 if we find `true', 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + + *acur = cur; + return result; + } + + + /* load a simple field (i.e. non-table) into the current list of objects */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt idx; + FT_Error error; + T1_FieldType type; + + + /* this also skips leading whitespace */ + ps_parser_to_token( parser, &token ); + if ( !token.type ) + goto Fail; + + count = 1; + idx = 0; + cur = token.start; + limit = token.limit; + + type = field->type; + + /* we must detect arrays in /FontBBox */ + if ( type == T1_FIELD_TYPE_BBOX ) + { + T1_TokenRec token2; + FT_Byte* old_cur = parser->cursor; + FT_Byte* old_limit = parser->limit; + + + /* don't include delimiters */ + parser->cursor = token.start + 1; + parser->limit = token.limit - 1; + + ps_parser_to_token( parser, &token2 ); + parser->cursor = old_cur; + parser->limit = old_limit; + + if ( token2.type == T1_TOKEN_TYPE_ARRAY ) + { + type = T1_FIELD_TYPE_MM_BBOX; + goto FieldArray; + } + } + else if ( token.type == T1_TOKEN_TYPE_ARRAY ) + { + count = max_objects; + + FieldArray: + /* if this is an array and we have no blend, an error occurs */ + if ( max_objects == 0 ) + goto Fail; + + idx = 1; + + /* don't include delimiters */ + cur++; + limit--; + } + + for ( ; count > 0; count--, idx++ ) + { + FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; + FT_Long val; + + + skip_spaces( &cur, limit ); + + switch ( type ) + { + case T1_FIELD_TYPE_BOOL: + val = ps_tobool( &cur, limit ); + FT_TRACE4(( " %s", val ? "true" : "false" )); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED: + val = PS_Conv_ToFixed( &cur, limit, 0 ); + FT_TRACE4(( " %f", (double)val / 65536 )); + goto Store_Integer; + + case T1_FIELD_TYPE_FIXED_1000: + val = PS_Conv_ToFixed( &cur, limit, 3 ); + FT_TRACE4(( " %f", (double)val / 65536 / 1000 )); + goto Store_Integer; + + case T1_FIELD_TYPE_INTEGER: + val = PS_Conv_ToInt( &cur, limit ); + FT_TRACE4(( " %ld", val )); + /* fall through */ + + Store_Integer: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + + case (16 / FT_CHAR_BIT): + *(FT_UShort*)q = (FT_UShort)val; + break; + + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)q = (FT_UInt32)val; + break; + + default: /* for 64-bit systems */ + *(FT_Long*)q = val; + } + break; + + case T1_FIELD_TYPE_STRING: + case T1_FIELD_TYPE_KEY: + { + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + FT_String* string = NULL; + + + if ( cur >= limit ) + break; + + /* we allow both a string or a name */ + /* for cases like /FontName (foo) def */ + if ( token.type == T1_TOKEN_TYPE_KEY ) + { + /* don't include leading `/' */ + len--; + cur++; + } + else if ( token.type == T1_TOKEN_TYPE_STRING ) + { + /* don't include delimiting parentheses */ + /* XXX we don't handle <<...>> here */ + /* XXX should we convert octal escapes? */ + /* if so, what encoding should we use? */ + cur++; + len -= 2; + } + else + { + FT_ERROR(( "ps_parser_load_field:" + " expected a name or string\n" )); + FT_ERROR(( " " + " but found token of type %d instead\n", + token.type )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* for this to work (FT_String**)q must have been */ + /* initialized to NULL */ + if ( *(FT_String**)q ) + { + FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", + field->ident )); + FT_FREE( *(FT_String**)q ); + } + + if ( FT_QALLOC( string, len + 1 ) ) + goto Exit; + + FT_MEM_COPY( string, cur, len ); + string[len] = 0; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( token.type == T1_TOKEN_TYPE_STRING ) + FT_TRACE4(( " (%s)", string )); + else + FT_TRACE4(( " /%s", string )); +#endif + + *(FT_String**)q = string; + } + break; + + case T1_FIELD_TYPE_BBOX: + { + FT_Fixed temp[4]; + FT_BBox* bbox = (FT_BBox*)q; + FT_Int result; + + + result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); + + if ( result < 4 ) + { + FT_ERROR(( "ps_parser_load_field:" + " expected four integers in bounding box\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + bbox->xMin = FT_RoundFix( temp[0] ); + bbox->yMin = FT_RoundFix( temp[1] ); + bbox->xMax = FT_RoundFix( temp[2] ); + bbox->yMax = FT_RoundFix( temp[3] ); + + FT_TRACE4(( " [%ld %ld %ld %ld]", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + break; + + case T1_FIELD_TYPE_MM_BBOX: + { + FT_Memory memory = parser->memory; + FT_Fixed* temp = NULL; + FT_Int result; + FT_UInt i; + + + if ( FT_QNEW_ARRAY( temp, max_objects * 4 ) ) + goto Exit; + + for ( i = 0; i < 4; i++ ) + { + result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects, + temp + i * max_objects, 0 ); + if ( result < 0 || (FT_UInt)result < max_objects ) + { + FT_ERROR(( "ps_parser_load_field:" + " expected %d integer%s in the %s subarray\n", + max_objects, max_objects > 1 ? "s" : "", + i == 0 ? "first" + : ( i == 1 ? "second" + : ( i == 2 ? "third" + : "fourth" ) ) )); + FT_ERROR(( " " + " of /FontBBox in the /Blend dictionary\n" )); + error = FT_THROW( Invalid_File_Format ); + + FT_FREE( temp ); + goto Exit; + } + + skip_spaces( &cur, limit ); + } + + FT_TRACE4(( " [" )); + for ( i = 0; i < max_objects; i++ ) + { + FT_BBox* bbox = (FT_BBox*)objects[i]; + + + bbox->xMin = FT_RoundFix( temp[i ] ); + bbox->yMin = FT_RoundFix( temp[i + max_objects] ); + bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] ); + bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] ); + + FT_TRACE4(( " [%ld %ld %ld %ld]", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + FT_TRACE4(( "]" )); + + FT_FREE( temp ); + } + break; + + default: + /* an error occurred */ + goto Fail; + } + } + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + error = FT_Err_Ok; + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; + T1_Token token; + FT_Int num_elements; + FT_Error error = FT_Err_Ok; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_FieldRec fieldrec = *(T1_Field)field; + + + fieldrec.type = T1_FIELD_TYPE_INTEGER; + if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || + field->type == T1_FIELD_TYPE_BBOX ) + fieldrec.type = T1_FIELD_TYPE_FIXED; + + ps_parser_to_token_array( parser, elements, + T1_MAX_TABLE_ELEMENTS, &num_elements ); + if ( num_elements < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( (FT_UInt)num_elements > field->array_max ) + num_elements = (FT_Int)field->array_max; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count if necessary; */ + /* we further assume that `count_offset' can't be zero */ + if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) + *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = + (FT_Byte)num_elements; + + FT_TRACE4(( " [" )); + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + + error = ps_parser_load_field( parser, + &fieldrec, + objects, + max_objects, + 0 ); + if ( error ) + break; + + fieldrec.offset += fieldrec.size; + } + + FT_TRACE4(( "]" )); + +#if 0 /* obsolete -- keep for reference */ + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Long ) + ps_parser_to_int( PS_Parser parser ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToInt( &parser->cursor, parser->limit ); + } + + + /* first character must be `<' if `delimiters' is non-zero */ + + FT_LOCAL_DEF( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* cur; + + + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + + if ( cur >= parser->limit ) + goto Exit; + + if ( delimiters ) + { + if ( *cur != '<' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + cur++; + } + + *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, + parser->limit, + bytes, + max_bytes ); + + parser->cursor = cur; + + if ( delimiters ) + { + if ( cur < parser->limit && *cur != '>' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + parser->cursor++; + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ) + { + ps_parser_skip_spaces( parser ); + return ps_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + + + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return ps_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } + + +#if 0 + + FT_LOCAL_DEF( FT_String* ) + T1_ToString( PS_Parser parser ) + { + return ps_tostring( &parser->cursor, parser->limit, parser->memory ); + } + + + FT_LOCAL_DEF( FT_Bool ) + T1_ToBool( PS_Parser parser ) + { + return ps_tobool( &parser->cursor, parser->limit ); + } + +#endif /* 0 */ + + + FT_LOCAL_DEF( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ) + { + parser->error = FT_Err_Ok; + parser->base = base; + parser->limit = limit; + parser->cursor = base; + parser->memory = memory; + parser->funcs = ps_parser_funcs; + } + + + FT_LOCAL_DEF( void ) + ps_parser_done( PS_Parser parser ) + { + FT_UNUSED( parser ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * t1_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting should be applied. + */ + FT_LOCAL_DEF( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->parse_state = T1_Parse_Start; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = size->internal->module_data; + builder->hints_funcs = NULL; + + if ( hinting ) + builder->hints_funcs = glyph->internal->glyph_hints; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->funcs = t1_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * t1_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + t1_builder_done( T1_Builder builder ) + { + FT_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; + + + point->x = FIXED_TO_INT( x ); + point->y = FIXED_TO_INT( y ); + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = t1_builder_check_points( builder, 1 ); + if ( !error ) + t1_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + /* this might happen in invalid fonts */ + if ( !outline ) + { + FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); + return FT_THROW( Invalid_File_Format ); + } + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_ERR( Invalid_File_Format ); + + + /* test whether we are building a new contour */ + + if ( builder->parse_state == T1_Parse_Have_Path ) + error = FT_Err_Ok; + else + { + builder->parse_state = T1_Parse_Have_Path; + error = t1_builder_add_contour( builder ); + if ( !error ) + error = t1_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + t1_builder_close_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether the first and the last point is the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * cff_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting is active. + */ + FT_LOCAL_DEF( void ) + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if ( glyph ) + { + FT_GlyphLoader loader = glyph->root.internal->loader; + + + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + + builder->hints_globals = NULL; + builder->hints_funcs = NULL; + + if ( hinting && size ) + { + FT_Size ftsize = FT_SIZE( size ); + CFF_Internal internal = (CFF_Internal)ftsize->internal->module_data; + + if ( internal ) + { + builder->hints_globals = (void *)internal->topfont; + builder->hints_funcs = glyph->root.internal->glyph_hints; + } + } + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->funcs = cff_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * cff_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + cff_builder_done( CFF_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + cff_check_points( CFF_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + + if ( driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = x >> 16; + point->y = y >> 16; + } + else +#endif + { + /* cf2_decoder_parse_charstrings uses 16.16 coordinates */ + point->x = x >> 10; + point->y = y >> 10; + } + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = cff_check_points( builder, 1 ); + if ( !error ) + cff_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_add_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_Err_Ok; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = cff_builder_add_contour( builder ); + if ( !error ) + error = cff_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + cff_builder_close_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and if it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether begin point and last point are the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * ps_builder_init + * + * @Description: + * Initializes a given glyph builder. + * + * @InOut: + * builder :: + * A pointer to the glyph builder to initialize. + * + * @Input: + * face :: + * The current face object. + * + * size :: + * The current size object. + * + * glyph :: + * The current glyph object. + * + * hinting :: + * Whether hinting should be applied. + */ + FT_LOCAL_DEF( void ) + ps_builder_init( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ) + { + FT_ZERO( ps_builder ); + + if ( is_t1 ) + { + T1_Builder t1builder = (T1_Builder)builder; + + + ps_builder->memory = t1builder->memory; + ps_builder->face = (FT_Face)t1builder->face; + ps_builder->glyph = (CFF_GlyphSlot)t1builder->glyph; + ps_builder->loader = t1builder->loader; + ps_builder->base = t1builder->base; + ps_builder->current = t1builder->current; + + ps_builder->pos_x = &t1builder->pos_x; + ps_builder->pos_y = &t1builder->pos_y; + + ps_builder->left_bearing = &t1builder->left_bearing; + ps_builder->advance = &t1builder->advance; + + ps_builder->bbox = &t1builder->bbox; + ps_builder->path_begun = 0; + ps_builder->load_points = t1builder->load_points; + ps_builder->no_recurse = t1builder->no_recurse; + + ps_builder->metrics_only = t1builder->metrics_only; + } + else + { + CFF_Builder* cffbuilder = (CFF_Builder*)builder; + + + ps_builder->memory = cffbuilder->memory; + ps_builder->face = (FT_Face)cffbuilder->face; + ps_builder->glyph = cffbuilder->glyph; + ps_builder->loader = cffbuilder->loader; + ps_builder->base = cffbuilder->base; + ps_builder->current = cffbuilder->current; + + ps_builder->pos_x = &cffbuilder->pos_x; + ps_builder->pos_y = &cffbuilder->pos_y; + + ps_builder->left_bearing = &cffbuilder->left_bearing; + ps_builder->advance = &cffbuilder->advance; + + ps_builder->bbox = &cffbuilder->bbox; + ps_builder->path_begun = cffbuilder->path_begun; + ps_builder->load_points = cffbuilder->load_points; + ps_builder->no_recurse = cffbuilder->no_recurse; + + ps_builder->metrics_only = cffbuilder->metrics_only; + } + + ps_builder->is_t1 = is_t1; + ps_builder->funcs = ps_builder_funcs; + } + + + /************************************************************************** + * + * @Function: + * ps_builder_done + * + * @Description: + * Finalizes a given glyph builder. Its contents can still be used + * after the call, but the function saves important information + * within the corresponding glyph slot. + * + * @Input: + * builder :: + * A pointer to the glyph builder to finalize. + */ + FT_LOCAL_DEF( void ) + ps_builder_done( PS_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + + + if ( glyph ) + glyph->root.outline = *builder->base; + } + + + /* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_check_points( PS_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } + + + /* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + ps_builder_add_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + + + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; + +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); + + + if ( !builder->is_t1 && + driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = x >> 16; + point->y = y >> 16; + } + else +#endif +#ifdef T1_CONFIG_OPTION_OLD_ENGINE +#ifndef CFF_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); +#endif + if ( builder->is_t1 && + driver->hinting_engine == FT_HINTING_FREETYPE ) + { + point->x = FIXED_TO_INT( x ); + point->y = FIXED_TO_INT( y ); + } + else +#endif + { + /* cf2_decoder_parse_charstrings uses 16.16 coordinates */ + point->x = x >> 10; + point->y = y >> 10; + } + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } + + + /* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_add_point1( PS_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + + error = ps_builder_check_points( builder, 1 ); + if ( !error ) + ps_builder_add_point( builder, x, y, 1 ); + + return error; + } + + + /* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_add_contour( PS_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + + + /* this might happen in invalid fonts */ + if ( !outline ) + { + FT_ERROR(( "ps_builder_add_contour: no outline to add points to\n" )); + return FT_THROW( Invalid_File_Format ); + } + + if ( !builder->load_points ) + { + outline->n_contours++; + return FT_Err_Ok; + } + + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + + outline->n_contours++; + } + + return error; + } + + + /* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + ps_builder_start_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = FT_Err_Ok; + + + /* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = ps_builder_add_contour( builder ); + if ( !error ) + error = ps_builder_add_point1( builder, x, y ); + } + + return error; + } + + + /* close the current contour */ + FT_LOCAL_DEF( void ) + ps_builder_close_contour( PS_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + + + if ( !outline ) + return; + + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* in malformed fonts it can happen that a contour was started */ + /* but no points were added */ + if ( outline->n_contours && first == outline->n_points ) + { + outline->n_contours--; + return; + } + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; + + + /* `delete' last point only if it coincides with the first */ + /* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + + if ( outline->n_contours > 0 ) + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether the first and the last point is the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = outline->n_points - 1; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * ps_decoder_init + * + * @Description: + * Creates a wrapper decoder for use in the combined + * Type 1 / CFF interpreter. + * + * @InOut: + * ps_decoder :: + * A pointer to the decoder to initialize. + * + * @Input: + * decoder :: + * A pointer to the original decoder. + * + * is_t1 :: + * Flag indicating Type 1 or CFF + */ + FT_LOCAL_DEF( void ) + ps_decoder_init( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ) + { + FT_ZERO( ps_decoder ); + + if ( is_t1 ) + { + T1_Decoder t1_decoder = (T1_Decoder)decoder; + + + ps_builder_init( &ps_decoder->builder, + &t1_decoder->builder, + is_t1 ); + + ps_decoder->cf2_instance = &t1_decoder->cf2_instance; + ps_decoder->psnames = t1_decoder->psnames; + + ps_decoder->num_glyphs = t1_decoder->num_glyphs; + ps_decoder->glyph_names = t1_decoder->glyph_names; + ps_decoder->hint_mode = t1_decoder->hint_mode; + ps_decoder->blend = t1_decoder->blend; + + ps_decoder->num_locals = (FT_UInt)t1_decoder->num_subrs; + ps_decoder->locals = t1_decoder->subrs; + ps_decoder->locals_len = t1_decoder->subrs_len; + ps_decoder->locals_hash = t1_decoder->subrs_hash; + + ps_decoder->buildchar = t1_decoder->buildchar; + ps_decoder->len_buildchar = t1_decoder->len_buildchar; + + ps_decoder->lenIV = t1_decoder->lenIV; + } + else + { + CFF_Decoder* cff_decoder = (CFF_Decoder*)decoder; + + + ps_builder_init( &ps_decoder->builder, + &cff_decoder->builder, + is_t1 ); + + ps_decoder->cff = cff_decoder->cff; + ps_decoder->cf2_instance = &cff_decoder->cff->cf2_instance; + ps_decoder->current_subfont = cff_decoder->current_subfont; + + ps_decoder->num_globals = cff_decoder->num_globals; + ps_decoder->globals = cff_decoder->globals; + ps_decoder->globals_bias = cff_decoder->globals_bias; + ps_decoder->num_locals = cff_decoder->num_locals; + ps_decoder->locals = cff_decoder->locals; + ps_decoder->locals_bias = cff_decoder->locals_bias; + + ps_decoder->glyph_width = &cff_decoder->glyph_width; + ps_decoder->width_only = cff_decoder->width_only; + + ps_decoder->hint_mode = cff_decoder->hint_mode; + + ps_decoder->get_glyph_callback = cff_decoder->get_glyph_callback; + ps_decoder->free_glyph_callback = cff_decoder->free_glyph_callback; + } + } + + + /* Synthesize a SubFont object for Type 1 fonts, for use in the */ + /* new interpreter to access Private dict data. */ + FT_LOCAL_DEF( void ) + t1_make_subfont( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ) + { + CFF_Private cpriv = &subfont->private_dict; + FT_UInt n, count; + + + FT_ZERO( subfont ); + FT_ZERO( cpriv ); + + count = cpriv->num_blue_values = priv->num_blue_values; + for ( n = 0; n < count; n++ ) + cpriv->blue_values[n] = cf2_intToFixed( priv->blue_values[n] ); + + count = cpriv->num_other_blues = priv->num_other_blues; + for ( n = 0; n < count; n++ ) + cpriv->other_blues[n] = cf2_intToFixed( priv->other_blues[n] ); + + count = cpriv->num_family_blues = priv->num_family_blues; + for ( n = 0; n < count; n++ ) + cpriv->family_blues[n] = cf2_intToFixed( priv->family_blues[n] ); + + count = cpriv->num_family_other_blues = priv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + cpriv->family_other_blues[n] = + cf2_intToFixed( priv->family_other_blues[n] ); + + cpriv->blue_scale = priv->blue_scale; + cpriv->blue_shift = (FT_Pos)priv->blue_shift; + cpriv->blue_fuzz = (FT_Pos)priv->blue_fuzz; + + cpriv->standard_width = (FT_Pos)priv->standard_width[0]; + cpriv->standard_height = (FT_Pos)priv->standard_height[0]; + + count = cpriv->num_snap_widths = priv->num_snap_widths; + for ( n = 0; n < count; n++ ) + cpriv->snap_widths[n] = (FT_Pos)priv->snap_widths[n]; + + count = cpriv->num_snap_heights = priv->num_snap_heights; + for ( n = 0; n < count; n++ ) + cpriv->snap_heights[n] = (FT_Pos)priv->snap_heights[n]; + + cpriv->force_bold = priv->force_bold; + cpriv->lenIV = priv->lenIV; + cpriv->language_group = priv->language_group; + cpriv->expansion_factor = priv->expansion_factor; + + cpriv->subfont = subfont; + + + /* Initialize the random number generator. */ + if ( face->internal->random_seed != -1 ) + { + /* If we have a face-specific seed, use it. */ + /* If non-zero, update it to a positive value. */ + subfont->random = (FT_UInt32)face->internal->random_seed; + if ( face->internal->random_seed ) + { + do + { + face->internal->random_seed = (FT_Int32)cff_random( + (FT_UInt32)face->internal->random_seed ); + + } while ( face->internal->random_seed < 0 ); + } + } + if ( !subfont->random ) + { + FT_UInt32 seed; + + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&face ^ + (FT_Offset)(char*)&subfont ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + if ( seed == 0 ) + seed = 0x7384; + + subfont->random = seed; + } + } + + + FT_LOCAL_DEF( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ) + { + PS_Conv_EexecDecode( &buffer, + FT_OFFSET( buffer, length ), + buffer, + length, + &seed ); + } + + + FT_LOCAL_DEF( FT_UInt32 ) + cff_random( FT_UInt32 r ) + { + /* a 32bit version of the `xorshift' algorithm */ + r ^= r << 13; + r ^= r >> 17; + r ^= r << 5; + + return r; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psobjs.h b/Dependencies/freetype/freetype/src/psaux/psobjs.h new file mode 100644 index 00000000..345fc8a7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psobjs.h @@ -0,0 +1,312 @@ +/**************************************************************************** + * + * psobjs.h + * + * Auxiliary functions for PostScript fonts (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSOBJS_H_ +#define PSOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1_TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_TABLE + const PS_Table_FuncsRec ps_table_funcs; + + FT_CALLBACK_TABLE + const PS_Parser_FuncsRec ps_parser_funcs; + + FT_CALLBACK_TABLE + const T1_Builder_FuncsRec t1_builder_funcs; + + + FT_LOCAL( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ); + + FT_LOCAL( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + const void* object, + FT_UInt length ); + + FT_LOCAL( void ) + ps_table_done( PS_Table table ); + + + FT_LOCAL( void ) + ps_table_release( PS_Table table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL( void ) + ps_parser_skip_spaces( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_skip_PS_token( PS_Parser parser ); + + FT_LOCAL( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ); + + FT_LOCAL( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + + FT_LOCAL( FT_Long ) + ps_parser_to_int( PS_Parser parser ); + + + FT_LOCAL( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_ULong* pnum_bytes, + FT_Bool delimiters ); + + + FT_LOCAL( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ); + + + FT_LOCAL( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + + FT_LOCAL( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + + + FT_LOCAL( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + + FT_LOCAL( void ) + ps_parser_done( PS_Parser parser ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ); + + FT_LOCAL( void ) + t1_builder_done( T1_Builder builder ); + + FT_LOCAL( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ); + + FT_LOCAL( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + FT_LOCAL( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( FT_Error ) + t1_builder_add_contour( T1_Builder builder ); + + + FT_LOCAL( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + + + FT_LOCAL( void ) + t1_builder_close_contour( T1_Builder builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CFF BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ); + + FT_LOCAL( void ) + cff_builder_done( CFF_Builder* builder ); + + FT_LOCAL( FT_Error ) + cff_check_points( CFF_Builder* builder, + FT_Int count ); + + FT_LOCAL( void ) + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + FT_LOCAL( FT_Error ) + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( FT_Error ) + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( void ) + cff_builder_close_contour( CFF_Builder* builder ); + + FT_LOCAL( FT_Error ) + cff_builder_add_contour( CFF_Builder* builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS BUILDER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + ps_builder_init( PS_Builder* ps_builder, + void* builder, + FT_Bool is_t1 ); + + + FT_LOCAL( void ) + ps_builder_done( PS_Builder* builder ); + + FT_LOCAL( FT_Error ) + ps_builder_check_points( PS_Builder* builder, + FT_Int count ); + + FT_LOCAL( void ) + ps_builder_add_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + + FT_LOCAL( FT_Error ) + ps_builder_add_point1( PS_Builder* builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( FT_Error ) + ps_builder_add_contour( PS_Builder* builder ); + + FT_LOCAL( FT_Error ) + ps_builder_start_point( PS_Builder* builder, + FT_Pos x, + FT_Pos y ); + + FT_LOCAL( void ) + ps_builder_close_contour( PS_Builder* builder ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** OTHER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + ps_decoder_init( PS_Decoder* ps_decoder, + void* decoder, + FT_Bool is_t1 ); + + FT_LOCAL( void ) + t1_make_subfont( FT_Face face, + PS_Private priv, + CFF_SubFont subfont ); + + FT_LOCAL( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + + + FT_LOCAL( FT_UInt32 ) + cff_random( FT_UInt32 r ); + + +FT_END_HEADER + +#endif /* PSOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psread.c b/Dependencies/freetype/freetype/src/psaux/psread.c new file mode 100644 index 00000000..7f657f2c --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psread.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * + * psread.c + * + * Adobe's code for stream handling (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" + +#include "pserror.h" + + + /* Define CF2_IO_FAIL as 1 to enable random errors and random */ + /* value errors in I/O. */ +#define CF2_IO_FAIL 0 + + +#if CF2_IO_FAIL + + /* set the .00 value to a nonzero probability */ + static int + randomError2( void ) + { + /* for region buffer ReadByte (interp) function */ + return (double)rand() / RAND_MAX < .00; + } + + /* set the .00 value to a nonzero probability */ + static CF2_Int + randomValue() + { + return (double)rand() / RAND_MAX < .00 ? rand() : 0; + } + +#endif /* CF2_IO_FAIL */ + + + /* Region Buffer */ + /* */ + /* Can be constructed from a copied buffer managed by */ + /* `FCM_getDatablock'. */ + /* Reads bytes with check for end of buffer. */ + + /* reading past the end of the buffer sets error and returns zero */ + FT_LOCAL_DEF( CF2_Int ) + cf2_buf_readByte( CF2_Buffer buf ) + { + if ( buf->ptr < buf->end ) + { +#if CF2_IO_FAIL + if ( randomError2() ) + { + CF2_SET_ERROR( buf->error, Invalid_Stream_Operation ); + return 0; + } + + return *(buf->ptr)++ + randomValue(); +#else + return *(buf->ptr)++; +#endif + } + else + { + CF2_SET_ERROR( buf->error, Invalid_Stream_Operation ); + return 0; + } + } + + + /* note: end condition can occur without error */ + FT_LOCAL_DEF( FT_Bool ) + cf2_buf_isEnd( CF2_Buffer buf ) + { + return FT_BOOL( buf->ptr >= buf->end ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psread.h b/Dependencies/freetype/freetype/src/psaux/psread.h new file mode 100644 index 00000000..9e55fe04 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psread.h @@ -0,0 +1,68 @@ +/**************************************************************************** + * + * psread.h + * + * Adobe's code for stream handling (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSREAD_H_ +#define PSREAD_H_ + + +FT_BEGIN_HEADER + + + typedef struct CF2_BufferRec_ + { + FT_Error* error; + const FT_Byte* start; + const FT_Byte* end; + const FT_Byte* ptr; + + } CF2_BufferRec, *CF2_Buffer; + + + FT_LOCAL( CF2_Int ) + cf2_buf_readByte( CF2_Buffer buf ); + FT_LOCAL( FT_Bool ) + cf2_buf_isEnd( CF2_Buffer buf ); + + +FT_END_HEADER + + +#endif /* PSREAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psstack.c b/Dependencies/freetype/freetype/src/psaux/psstack.c new file mode 100644 index 00000000..79748658 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psstack.c @@ -0,0 +1,329 @@ +/**************************************************************************** + * + * psstack.c + * + * Adobe's code for emulating a CFF stack (body). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#include "psft.h" +#include + +#include "psglue.h" +#include "psfont.h" +#include "psstack.h" + +#include "pserror.h" + + + /* Allocate and initialize an instance of CF2_Stack. */ + /* Note: This function returns NULL on error (does not set */ + /* `error'). */ + FT_LOCAL_DEF( CF2_Stack ) + cf2_stack_init( FT_Memory memory, + FT_Error* e, + FT_UInt stackSize ) + { + FT_Error error; /* for FT_QNEW */ + CF2_Stack stack = NULL; + + + if ( FT_QNEW( stack ) ) + return NULL; + + stack->memory = memory; + stack->error = e; + + /* allocate the stack buffer */ + if ( FT_QNEW_ARRAY( stack->buffer, stackSize ) ) + { + FT_FREE( stack ); + return NULL; + } + + stack->stackSize = stackSize; + stack->top = stack->buffer; /* empty stack */ + + return stack; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_free( CF2_Stack stack ) + { + if ( stack ) + { + FT_Memory memory = stack->memory; + + /* free the buffer */ + FT_FREE( stack->buffer ); + + /* free the main structure */ + FT_FREE( stack ); + } + } + + + FT_LOCAL_DEF( CF2_UInt ) + cf2_stack_count( CF2_Stack stack ) + { + return (CF2_UInt)( stack->top - stack->buffer ); + } + + + FT_LOCAL_DEF( void ) + cf2_stack_pushInt( CF2_Stack stack, + CF2_Int val ) + { + if ( stack->top == stack->buffer + stack->stackSize ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; /* stack overflow */ + } + + stack->top->u.i = val; + stack->top->type = CF2_NumberInt; + stack->top++; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_pushFixed( CF2_Stack stack, + CF2_Fixed val ) + { + if ( stack->top == stack->buffer + stack->stackSize ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; /* stack overflow */ + } + + stack->top->u.r = val; + stack->top->type = CF2_NumberFixed; + stack->top++; + } + + + /* this function is only allowed to pop an integer type */ + FT_LOCAL_DEF( CF2_Int ) + cf2_stack_popInt( CF2_Stack stack ) + { + if ( stack->top == stack->buffer ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return 0; /* underflow */ + } + if ( stack->top[-1].type != CF2_NumberInt ) + { + CF2_SET_ERROR( stack->error, Syntax_Error ); + return 0; /* type mismatch */ + } + + stack->top--; + + return stack->top->u.i; + } + + + /* Note: type mismatch is silently cast */ + /* TODO: check this */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_stack_popFixed( CF2_Stack stack ) + { + if ( stack->top == stack->buffer ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return cf2_intToFixed( 0 ); /* underflow */ + } + + stack->top--; + + switch ( stack->top->type ) + { + case CF2_NumberInt: + return cf2_intToFixed( stack->top->u.i ); + case CF2_NumberFrac: + return cf2_fracToFixed( stack->top->u.f ); + default: + return stack->top->u.r; + } + } + + + /* Note: type mismatch is silently cast */ + /* TODO: check this */ + FT_LOCAL_DEF( CF2_Fixed ) + cf2_stack_getReal( CF2_Stack stack, + CF2_UInt idx ) + { + FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize ); + + if ( idx >= cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return cf2_intToFixed( 0 ); /* bounds error */ + } + + switch ( stack->buffer[idx].type ) + { + case CF2_NumberInt: + return cf2_intToFixed( stack->buffer[idx].u.i ); + case CF2_NumberFrac: + return cf2_fracToFixed( stack->buffer[idx].u.f ); + default: + return stack->buffer[idx].u.r; + } + } + + + /* provide random access to stack */ + FT_LOCAL_DEF( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ) + { + if ( idx > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + stack->buffer[idx].u.r = val; + stack->buffer[idx].type = CF2_NumberFixed; + } + + + /* discard (pop) num values from stack */ + FT_LOCAL_DEF( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ) + { + if ( num > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return; + } + stack->top -= num; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int shift ) + { + /* we initialize this variable to avoid compiler warnings */ + CF2_StackNumber last = { { 0 }, CF2_NumberInt }; + + CF2_Int start_idx, idx, i; + + + if ( count < 2 ) + return; /* nothing to do (values 0 and 1), or undefined value */ + + if ( (CF2_UInt)count > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + /* before C99 it is implementation-defined whether */ + /* the result of `%' is negative if the first operand */ + /* is negative */ + if ( shift < 0 ) + shift = -( ( -shift ) % count ); + else + shift %= count; + + if ( shift == 0 ) + return; /* nothing to do */ + + /* We use the following algorithm to do the rolling, */ + /* which needs two temporary variables only. */ + /* */ + /* Example: */ + /* */ + /* count = 8 */ + /* shift = 2 */ + /* */ + /* stack indices before roll: 7 6 5 4 3 2 1 0 */ + /* stack indices after roll: 1 0 7 6 5 4 3 2 */ + /* */ + /* The value of index 0 gets moved to index 2, while */ + /* the old value of index 2 gets moved to index 4, */ + /* and so on. We thus have the following copying */ + /* chains for shift value 2. */ + /* */ + /* 0 -> 2 -> 4 -> 6 -> 0 */ + /* 1 -> 3 -> 5 -> 7 -> 1 */ + /* */ + /* If `count' and `shift' are incommensurable, we */ + /* have a single chain only. Otherwise, increase */ + /* the start index by 1 after the first chain, then */ + /* do the next chain until all elements in all */ + /* chains are handled. */ + + start_idx = -1; + idx = -1; + for ( i = 0; i < count; i++ ) + { + CF2_StackNumber tmp; + + + if ( start_idx == idx ) + { + start_idx++; + idx = start_idx; + last = stack->buffer[idx]; + } + + idx += shift; + if ( idx >= count ) + idx -= count; + else if ( idx < 0 ) + idx += count; + + tmp = stack->buffer[idx]; + stack->buffer[idx] = last; + last = tmp; + } + } + + + FT_LOCAL_DEF( void ) + cf2_stack_clear( CF2_Stack stack ) + { + stack->top = stack->buffer; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/psstack.h b/Dependencies/freetype/freetype/src/psaux/psstack.h new file mode 100644 index 00000000..907b4240 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/psstack.h @@ -0,0 +1,122 @@ +/**************************************************************************** + * + * psstack.h + * + * Adobe's code for emulating a CFF stack (specification). + * + * Copyright 2007-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSSTACK_H_ +#define PSSTACK_H_ + +#include + +FT_BEGIN_HEADER + + + /* CFF operand stack; specified maximum of 48 or 192 values */ + typedef struct CF2_StackNumber_ + { + union + { + CF2_Fixed r; /* 16.16 fixed-point */ + CF2_Frac f; /* 2.30 fixed-point (for font matrix) */ + CF2_Int i; + } u; + + CF2_NumberType type; + + } CF2_StackNumber; + + + typedef struct CF2_StackRec_ + { + FT_Memory memory; + FT_Error* error; + CF2_StackNumber* buffer; + CF2_StackNumber* top; + FT_UInt stackSize; + + } CF2_StackRec, *CF2_Stack; + + + FT_LOCAL( CF2_Stack ) + cf2_stack_init( FT_Memory memory, + FT_Error* error, + FT_UInt stackSize ); + FT_LOCAL( void ) + cf2_stack_free( CF2_Stack stack ); + + FT_LOCAL( CF2_UInt ) + cf2_stack_count( CF2_Stack stack ); + + FT_LOCAL( void ) + cf2_stack_pushInt( CF2_Stack stack, + CF2_Int val ); + FT_LOCAL( void ) + cf2_stack_pushFixed( CF2_Stack stack, + CF2_Fixed val ); + + FT_LOCAL( CF2_Int ) + cf2_stack_popInt( CF2_Stack stack ); + FT_LOCAL( CF2_Fixed ) + cf2_stack_popFixed( CF2_Stack stack ); + + FT_LOCAL( CF2_Fixed ) + cf2_stack_getReal( CF2_Stack stack, + CF2_UInt idx ); + FT_LOCAL( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ); + + FT_LOCAL( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ); + + FT_LOCAL( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int idx ); + + FT_LOCAL( void ) + cf2_stack_clear( CF2_Stack stack ); + + +FT_END_HEADER + + +#endif /* PSSTACK_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/pstypes.h b/Dependencies/freetype/freetype/src/psaux/pstypes.h new file mode 100644 index 00000000..435ef7e1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/pstypes.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * + * pstypes.h + * + * Adobe's code for defining data types (specification only). + * + * Copyright 2011-2013 Adobe Systems Incorporated. + * + * This software, and all works of authorship, whether in source or + * object code form as indicated by the copyright notice(s) included + * herein (collectively, the "Work") is made available, and may only be + * used, modified, and distributed under the FreeType Project License, + * LICENSE.TXT. Additionally, subject to the terms and conditions of the + * FreeType Project License, each contributor to the Work hereby grants + * to any individual or legal entity exercising permissions granted by + * the FreeType Project License and this section (hereafter, "You" or + * "Your") a perpetual, worldwide, non-exclusive, no-charge, + * royalty-free, irrevocable (except as stated in this section) patent + * license to make, have made, use, offer to sell, sell, import, and + * otherwise transfer the Work, where such license applies only to those + * patent claims licensable by such contributor that are necessarily + * infringed by their contribution(s) alone or by combination of their + * contribution(s) with the Work to which such contribution(s) was + * submitted. If You institute patent litigation against any entity + * (including a cross-claim or counterclaim in a lawsuit) alleging that + * the Work or a contribution incorporated within the Work constitutes + * direct or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate as of + * the date such litigation is filed. + * + * By using, modifying, or distributing the Work you indicate that you + * have read and understood the terms and conditions of the + * FreeType Project License as well as those provided in this section, + * and you accept them fully. + * + */ + + +#ifndef PSTYPES_H_ +#define PSTYPES_H_ + +#include + + +FT_BEGIN_HEADER + + + /* + * The data models that we expect to support are as follows: + * + * name char short int long long-long pointer example + * ----------------------------------------------------- + * ILP32 8 16 32 32 64* 32 32-bit MacOS, x86 + * LLP64 8 16 32 32 64 64 x64 + * LP64 8 16 32 64 64 64 64-bit MacOS + * + * *) type may be supported by emulation on a 32-bit architecture + * + */ + + + /* integers at least 32 bits wide */ +#define CF2_UInt FT_UFast +#define CF2_Int FT_Fast + + + /* fixed-float numbers */ + typedef FT_Int32 CF2_F16Dot16; + + +FT_END_HEADER + + +#endif /* PSTYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/t1cmap.c b/Dependencies/freetype/freetype/src/psaux/t1cmap.c new file mode 100644 index 00000000..5681c3bd --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/t1cmap.c @@ -0,0 +1,393 @@ +/**************************************************************************** + * + * t1cmap.c + * + * Type 1 character map support (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1cmap.h" + +#include + +#include "psauxerr.h" + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_cmap_std_init( T1_CMapStd cmap, + FT_Int is_expert ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + cmap->num_glyphs = (FT_UInt)face->type1.num_glyphs; + cmap->glyph_names = (const char* const*)face->type1.glyph_names; + cmap->sid_to_string = psnames->adobe_std_strings; + cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding + : psnames->adobe_std_encoding; + + FT_ASSERT( cmap->code_to_sid ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_std_done( FT_CMap cmap_ ) /* T1_CMapStd */ + { + T1_CMapStd cmap = (T1_CMapStd)cmap_; + + + cmap->num_glyphs = 0; + cmap->glyph_names = NULL; + cmap->sid_to_string = NULL; + cmap->code_to_sid = NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_index( FT_CMap cmap, /* T1_CMapStd */ + FT_UInt32 char_code ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UInt result = 0; + + + if ( char_code < 256 ) + { + FT_UInt code, n; + const char* glyph_name; + + + /* convert character code to Adobe SID string */ + code = t1cmap->code_to_sid[char_code]; + glyph_name = t1cmap->sid_to_string( code ); + + /* look for the corresponding glyph name */ + for ( n = 0; n < t1cmap->num_glyphs; n++ ) + { + const char* gname = t1cmap->glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + ft_strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + while ( char_code < 256 ) + { + result = t1_cmap_std_char_index( cmap, char_code ); + if ( result != 0 ) + goto Exit; + + char_code++; + } + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_standard_init( FT_CMap cmap, /* T1_CMapStd */ + FT_Pointer pointer ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UNUSED( pointer ); + + + t1_cmap_std_init( t1cmap, 0 ); + return 0; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_standard_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_standard_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_std_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_expert_init( FT_CMap cmap, /* T1_CMapStd */ + FT_Pointer pointer ) + { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UNUSED( pointer ); + + + t1_cmap_std_init( t1cmap, 1 ); + return 0; + } + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_expert_class_rec = + { + sizeof ( T1_CMapStdRec ), + + (FT_CMap_InitFunc) t1_cmap_expert_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_std_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_custom_init( FT_CMap cmap, /* T1_CMapCustom */ + FT_Pointer pointer ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + T1_Encoding encoding = &face->type1.encoding; + + FT_UNUSED( pointer ); + + + t1cmap->first = (FT_UInt)encoding->code_first; + t1cmap->count = (FT_UInt)encoding->code_last - t1cmap->first; + t1cmap->indices = encoding->char_index; + + FT_ASSERT( t1cmap->indices ); + FT_ASSERT( encoding->code_first <= encoding->code_last ); + + return 0; + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_custom_done( FT_CMap cmap ) /* T1_CMapCustom */ + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + + + t1cmap->indices = NULL; + t1cmap->first = 0; + t1cmap->count = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_index( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 char_code ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; + + + if ( char_code >= t1cmap->first && + char_code < ( t1cmap->first + t1cmap->count ) ) + result = t1cmap->indices[char_code]; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_next( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 *pchar_code ) + { + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + + + char_code++; + + if ( char_code < t1cmap->first ) + char_code = t1cmap->first; + + for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ ) + { + result = t1cmap->indices[char_code]; + if ( result != 0 ) + goto Exit; + } + + char_code = 0; + + Exit: + *pchar_code = char_code; + return result; + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_custom_class_rec = + { + sizeof ( T1_CMapCustomRec ), + + (FT_CMap_InitFunc) t1_cmap_custom_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_custom_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_custom_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_CALLBACK_DEF( const char * ) + psaux_get_glyph_name( void* face_, + FT_UInt idx ) + { + T1_Face face = (T1_Face)face_; + + + return face->type1.glyph_names[idx]; + } + + + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + FT_UNUSED( pointer ); + + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + (FT_UInt)face->type1.num_glyphs, + &psaux_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + t1_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_unicode_class_rec = + { + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) t1_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) t1_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/t1cmap.h b/Dependencies/freetype/freetype/src/psaux/t1cmap.h new file mode 100644 index 00000000..445e6a27 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/t1cmap.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * t1cmap.h + * + * Type 1 character map support (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1CMAP_H_ +#define T1CMAP_H_ + +#include +#include + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* standard (and expert) encoding cmaps */ + typedef struct T1_CMapStdRec_* T1_CMapStd; + + typedef struct T1_CMapStdRec_ + { + FT_CMapRec cmap; + + const FT_UShort* code_to_sid; + PS_Adobe_Std_StringsFunc sid_to_string; + + FT_UInt num_glyphs; + const char* const* glyph_names; + + } T1_CMapStdRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_standard_class_rec; + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_expert_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 CUSTOM ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct T1_CMapCustomRec_* T1_CMapCustom; + + typedef struct T1_CMapCustomRec_ + { + FT_CMapRec cmap; + FT_UInt first; + FT_UInt count; + FT_UShort* indices; + + } T1_CMapCustomRec; + + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_custom_class_rec; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* unicode (synthetic) cmaps */ + + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_unicode_class_rec; + + /* */ + + +FT_END_HEADER + +#endif /* T1CMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/t1decode.c b/Dependencies/freetype/freetype/src/psaux/t1decode.c new file mode 100644 index 00000000..c74baa80 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/t1decode.c @@ -0,0 +1,2159 @@ +/**************************************************************************** + * + * t1decode.c + * + * PostScript Type 1 decoding routines (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "t1decode.h" +#include "psobjs.h" + +#include "psauxerr.h" + + +/* ensure proper sign extension */ +#define Fix2Int( f ) ( (FT_Int) (FT_Short)( (f) >> 16 ) ) +#define Fix2UInt( f ) ( (FT_UInt)(FT_Short)( (f) >> 16 ) ) + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1decode + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + op_unknown15, + + op_max /* never remove this one */ + + } T1_Operator; + + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2, /* setcurrentpoint */ + 2 /* opcode 15 (undocumented and obsolete) */ + }; + + + /************************************************************************** + * + * @Function: + * t1_lookup_glyph_by_stdcharcode_ps + * + * @Description: + * Looks up a given glyph by its StandardEncoding charcode. Used to + * implement the SEAC Type 1 operator in the Adobe engine + * + * @Input: + * face :: + * The current face object. + * + * charcode :: + * The character code to look for. + * + * @Return: + * A glyph index in the font face. Returns -1 if the corresponding + * glyph wasn't found. + */ + FT_LOCAL_DEF( FT_Int ) + t1_lookup_glyph_by_stdcharcode_ps( PS_Decoder* decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && + name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return (FT_Int)n; + } + + return -1; + } + + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + + /************************************************************************** + * + * @Function: + * t1_lookup_glyph_by_stdcharcode + * + * @Description: + * Looks up a given glyph by its StandardEncoding charcode. Used to + * implement the SEAC Type 1 operator. + * + * @Input: + * face :: + * The current face object. + * + * charcode :: + * The character code to look for. + * + * @Return: + * A glyph index in the font face. Returns -1 if the corresponding + * glyph wasn't found. + */ + static FT_Int + t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && + name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return (FT_Int)n; + } + + return -1; + } + + + /* parse a single Type 1 glyph */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph ) + { + return decoder->parse_callback( decoder, glyph ); + } + + + /************************************************************************** + * + * @Function: + * t1operator_seac + * + * @Description: + * Implements the `seac' Type 1 operator for a Type 1 decoder. + * + * @Input: + * decoder :: + * The current CID decoder. + * + * asb :: + * The accent's side bearing. + * + * adx :: + * The horizontal offset of the accent. + * + * ady :: + * The vertical offset of the accent. + * + * bchar :: + * The base character's StandardEncoding charcode. + * + * achar :: + * The accent character's StandardEncoding charcode. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + t1operator_seac( T1_Decoder decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index; +#if 0 + FT_Int n_base_points; + FT_Outline* base = decoder->builder.base; +#endif + FT_Vector left_bearing, advance; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + T1_Face face = (T1_Face)decoder->builder.face; +#endif + + + if ( decoder->seac ) + { + FT_ERROR(( "t1operator_seac: invalid nested seac\n" )); + return FT_THROW( Syntax_Error ); + } + + if ( decoder->builder.metrics_only ) + { + FT_ERROR(( "t1operator_seac: unexpected seac\n" )); + return FT_THROW( Syntax_Error ); + } + + /* seac weirdness */ + adx += decoder->builder.left_bearing.x; + + /* `glyph_names' is set to 0 for CID fonts which do not */ + /* include an encoding. How can we deal with these? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( decoder->glyph_names == 0 && + !face->root.internal->incremental_interface ) +#else + if ( decoder->glyph_names == 0 ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ERROR(( "t1operator_seac:" + " glyph names table not available in this font\n" )); + return FT_THROW( Syntax_Error ); + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + { + /* the caller must handle the font encoding also */ + bchar_index = bchar; + achar_index = achar; + } + else +#endif + { + bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); + } + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" + " invalid seac character code arguments\n" )); + return FT_THROW( Syntax_Error ); + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); + subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + loader->current.num_subglyphs = 2; + goto Exit; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, (FT_UInt)bchar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; + + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ + + if ( decoder->builder.parse_state != T1_Parse_Have_Width ) + { + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + } + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + decoder->builder.pos_x = adx - asb; + decoder->builder.pos_y = ady; + + /* Now load `achar' on top of */ + /* the base outline */ + + /* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, (FT_UInt)achar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; + + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + decoder->builder.pos_x = 0; + decoder->builder.pos_y = 0; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * t1_decoder_parse_charstrings + * + * @Description: + * Parses a given Type 1 charstrings program. + * + * @Input: + * decoder :: + * The current Type 1 decoder. + * + * charstring_base :: + * The base address of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + FT_Error error; + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Pos x, y, orig_x, orig_y; + FT_Int known_othersubr_result_cnt = 0; + FT_Int unknown_othersubr_result_cnt = 0; + FT_Bool large_int; + FT_Fixed seed; + + T1_Hints_Funcs hinter; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool bol = TRUE; +#endif + + + /* compute random seed from stack address of parameter */ + seed = (FT_Fixed)( ( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&decoder ^ + (FT_Offset)(char*)&charstring_base ) & + FT_ULONG_MAX ); + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; + if ( seed == 0 ) + seed = 0x7384; + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->parse_state = T1_Parse_Start; + + hinter = (T1_Hints_Funcs)builder->hints_funcs; + + /* a font that reads BuildCharArray without setting */ + /* its values first is buggy, but ... */ + FT_ASSERT( ( decoder->len_buildchar == 0 ) == + ( decoder->buildchar == NULL ) ); + + if ( decoder->buildchar && decoder->len_buildchar > 0 ) + FT_ARRAY_ZERO( decoder->buildchar, decoder->len_buildchar ); + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = FT_Err_Ok; + + x = orig_x = builder->pos_x; + y = orig_y = builder->pos_y; + + /* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + + large_int = FALSE; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Int32 value = 0; + + + FT_ASSERT( known_othersubr_result_cnt == 0 || + unknown_othersubr_result_cnt == 0 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( bol ) + { + FT_TRACE5(( " (%td)", decoder->top - decoder->stack )); + bol = FALSE; + } +#endif + + /********************************************************************** + * + * Decode operator or operand + * + */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 15: /* undocumented, obsolete operator */ + op = op_unknown15; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip >= limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + + /* According to the specification, values > 32000 or < -32000 must */ + /* be followed by a `div' operator to make the result be in the */ + /* range [-32000;32000]. We expect that the second argument of */ + /* `div' is not a large number. Additionally, we don't handle */ + /* stuff like ` div div' or */ + /* div div'. This is probably not allowed */ + /* anyway. */ + if ( value > 32000 || value < -32000 ) + { + if ( large_int ) + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + else + large_int = TRUE; + } + else + { + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Int32)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( ip[-2] - 247 ) * 256 ) + ip[-1] + 108; + else + value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 ); + } + + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + else + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + + if ( unknown_othersubr_result_cnt > 0 ) + { + switch ( op ) + { + case op_callsubr: + case op_return: + case op_none: + case op_pop: + break; + + default: + /* all operands have been transferred by previous pops */ + unknown_othersubr_result_cnt = 0; + break; + } + } + + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + + large_int = FALSE; + } + + /********************************************************************** + * + * Push value on stack, or process operator + * + */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow\n" )); + goto Syntax_Error; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( large_int ) + FT_TRACE4(( " %d", value )); + else + FT_TRACE4(( " %d", value / 65536 )); +#endif + + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_Int subr_no; + FT_Int arg_cnt; + + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " callothersubr\n" )); + bol = TRUE; +#endif + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + + subr_no = Fix2Int( top[1] ); + arg_cnt = Fix2Int( top[0] ); + + /************************************************************ + * + * remove all operands to callothersubr from the stack + * + * for handled othersubrs, where we know the number of + * arguments, we increase the stack by the value of + * known_othersubr_result_cnt + * + * for unhandled othersubrs the following pops adjust the + * stack pointer as necessary + */ + + if ( arg_cnt > top - decoder->stack ) + goto Stack_Underflow; + + top -= arg_cnt; + + known_othersubr_result_cnt = 0; + unknown_othersubr_result_cnt = 0; + + /* XXX TODO: The checks to `arg_count == ' */ + /* might not be correct; an othersubr expects a certain */ + /* number of operands on the PostScript stack (as opposed */ + /* to the T1 stack) but it doesn't have to put them there */ + /* by itself; previous othersubrs might have left the */ + /* operands there if they were not followed by an */ + /* appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ + /* accept a font that contains charstrings like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray exists. */ + + switch ( subr_no ) + { + case 0: /* end flex feature */ + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + + if ( !decoder->flex_state || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected flex end\n" )); + goto Syntax_Error; + } + + /* the two `results' are popped by the following setcurrentpoint */ + top[0] = x; + top[1] = y; + known_othersubr_result_cnt = 2; + break; + + case 1: /* start flex feature */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 6 ) ) ) + goto Fail; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + break; + + case 2: /* add flex vectors */ + { + FT_Int idx; + + + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + if ( !decoder->flex_state ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " missing flex start\n" )); + goto Syntax_Error; + } + + /* note that we should not add a point for index 0; */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + { + /* in malformed fonts it is possible to have other */ + /* opcodes in the middle of a flex (which don't */ + /* increase `num_flex_vectors'); we thus have to */ + /* check whether we can add a point */ + if ( FT_SET_ERROR( t1_builder_check_points( builder, 1 ) ) ) + goto Syntax_Error; + + t1_builder_add_point( builder, + x, + y, + (FT_Byte)( idx == 3 || idx == 6 ) ); + } + } + break; + + case 3: /* change hints */ + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + + known_othersubr_result_cnt = 1; + + if ( hinter ) + hinter->reset( hinter->hints, + (FT_UInt)builder->current->n_points ); + break; + + case 12: + case 13: + /* counter control hints, clear stack */ + top = decoder->stack; + break; + + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Long* delta; + FT_Long* values; + + + if ( !blend ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected multiple masters operator\n" )); + goto Syntax_Error; + } + + num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " incorrect number of multiple masters arguments\n" )); + goto Syntax_Error; + } + + /* We want to compute */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ + /* */ + /* However, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1. */ + /* */ + /* I guess that's why it's written in this `compact' */ + /* form. */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Long tmp = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp = ADD_LONG( tmp, + FT_MulFix( *delta++, + blend->weight_vector[mm] ) ); + + *values++ = tmp; + } + + known_othersubr_result_cnt = (FT_Int)num_points; + break; + } + + case 19: + /* 1 19 callothersubr */ + /* => replace elements starting from index cvi( ) */ + /* of BuildCharArray with WeightVector */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2Int( top[0] ); + + if ( idx < 0 || + (FT_UInt)idx + blend->num_designs > decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); + } + break; + + case 20: + /* 2 20 callothersubr pop */ + /* ==> push + onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = ADD_LONG( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 21: + /* 2 21 callothersubr pop */ + /* ==> push - onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = SUB_LONG( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 22: + /* 2 22 callothersubr pop */ + /* ==> push * onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] = FT_MulFix( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 23: + /* 2 23 callothersubr pop */ + /* ==> push / onto T1 stack */ + if ( arg_cnt != 2 || top[1] == 0 ) + goto Unexpected_OtherSubr; + + top[0] = FT_DivFix( top[0], top[1] ); + + known_othersubr_result_cnt = 1; + break; + + case 24: + /* 2 24 callothersubr */ + /* ==> set BuildCharArray[cvi( )] = */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 2 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2UInt( top[1] ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = top[0]; + } + break; + + case 25: + /* 1 25 callothersubr pop */ + /* ==> push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + FT_UInt idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || !blend ) + goto Unexpected_OtherSubr; + + idx = Fix2UInt( top[0] ); + + if ( idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + + top[0] = decoder->buildchar[idx]; + } + + known_othersubr_result_cnt = 1; + break; + +#if 0 + case 26: + /* mark ==> set BuildCharArray[cvi( )] = , */ + /* leave mark on T1 stack */ + /* ==> set BuildCharArray[cvi( )] = */ + XXX which routine has left its mark on the (PostScript) stack?; + break; +#endif + + case 27: + /* 4 27 callothersubr pop */ + /* ==> push onto T1 stack if <= , */ + /* otherwise push */ + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + if ( top[2] > top[3] ) + top[0] = top[1]; + + known_othersubr_result_cnt = 1; + break; + + case 28: + /* 0 28 callothersubr pop */ + /* => push random value from interval [0, 1) onto stack */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + { + FT_Fixed Rand; + + + Rand = seed; + if ( Rand >= 0x8000L ) + Rand++; + + top[0] = Rand; + + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + } + + known_othersubr_result_cnt = 1; + break; + + default: + if ( arg_cnt >= 0 && subr_no >= 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unknown othersubr [%d %d], wish me luck\n", + arg_cnt, subr_no )); + unknown_othersubr_result_cnt = arg_cnt; + break; + } + /* fall through */ + + Unexpected_OtherSubr: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid othersubr [%d %d]\n", arg_cnt, subr_no )); + goto Syntax_Error; + } + + top += known_othersubr_result_cnt; + + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + FT_ASSERT( num_args >= 0 ); + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + /* XXX Operators usually take their operands from the */ + /* bottom of the stack, i.e., the operands are */ + /* decoder->stack[0], ..., decoder->stack[num_args - 1]; */ + /* only div, callsubr, and callothersubr are different. */ + /* In practice it doesn't matter (?). */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + switch ( op ) + { + case op_callsubr: + case op_div: + case op_callothersubr: + case op_pop: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_charstrings:" + " too much operands on the stack" + " (seen %td, expected %d)\n", + top - decoder->stack, num_args )); + break; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar\n" )); + + t1_builder_close_contour( builder ); + + /* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + (FT_UInt)builder->current->n_points ) ) + goto Syntax_Error; + + /* apply hints to the loaded glyph outline now */ + error = hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + if ( error ) + goto Fail; + } + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* the compiler should optimize away this empty loop but ... */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + if ( decoder->len_buildchar > 0 ) + { + FT_UInt i; + + + FT_TRACE4(( "BuildCharArray = [ " )); + + for ( i = 0; i < decoder->len_buildchar; i++ ) + FT_TRACE4(( "%ld ", decoder->buildchar[i] )); + + FT_TRACE4(( "]\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + FT_TRACE4(( "\n" )); + + /* return now! */ + return FT_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + + builder->advance.x = top[1]; + builder->advance.y = 0; + + orig_x = x = ADD_LONG( builder->pos_x, top[0] ); + orig_y = y = builder->pos_y; + + FT_UNUSED( orig_y ); + + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + { + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + } + + break; + + case op_seac: + return t1operator_seac( decoder, + top[0], + top[1], + top[2], + Fix2Int( top[3] ), + Fix2Int( top[4] ) ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + builder->left_bearing.y = ADD_LONG( builder->left_bearing.y, + top[1] ); + + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + x = ADD_LONG( builder->pos_x, top[0] ); + y = ADD_LONG( builder->pos_y, top[1] ); + + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + { + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + } + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + /* if there is no path, `closepath' is a no-op */ + if ( builder->parse_state == T1_Parse_Have_Path || + builder->parse_state == T1_Parse_Have_Moveto ) + t1_builder_close_contour( builder ); + + builder->parse_state = T1_Parse_Have_Width; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x = ADD_LONG( x, top[0] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[1] ); + y = ADD_LONG( y, top[2] ); + t1_builder_add_point( builder, x, y, 0 ); + + y = ADD_LONG( y, top[3] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + + Add_Line: + if ( FT_SET_ERROR( t1_builder_add_point1( builder, x, y ) ) ) + goto Fail; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_rrcurveto: + FT_TRACE4(( " rrcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + x = ADD_LONG( x, top[0] ); + y = ADD_LONG( y, top[1] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[2] ); + y = ADD_LONG( y, top[3] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[4] ); + y = ADD_LONG( y, top[5] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) || + FT_SET_ERROR( t1_builder_check_points( builder, 3 ) ) ) + goto Fail; + + y = ADD_LONG( y, top[0] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[1] ); + y = ADD_LONG( y, top[2] ); + t1_builder_add_point( builder, x, y, 0 ); + + x = ADD_LONG( x, top[3] ); + t1_builder_add_point( builder, x, y, 1 ); + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( FT_SET_ERROR( t1_builder_start_point( builder, x, y ) ) ) + goto Fail; + + y = ADD_LONG( y, top[0] ); + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y = ADD_LONG( y, top[0] ); + + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + + case op_div: + FT_TRACE4(( " div" )); + + /* if `large_int' is set, we divide unscaled numbers; */ + /* otherwise, we divide numbers in 16.16 format -- */ + /* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + top++; + + large_int = FALSE; + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + + if ( idx < 0 || idx >= decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_pop: + FT_TRACE4(( " pop" )); + + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; + /* ignore, we pushed the operands ourselves */ + break; + } + + if ( unknown_othersubr_result_cnt == 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no more operands for othersubr\n" )); + goto Syntax_Error; + } + + unknown_othersubr_result_cnt--; + top++; /* `push' the operand to callothersubr onto the stack */ + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + /* record horizontal hint */ + if ( hinter ) + { + /* top[0] += builder->left_bearing.y; */ + hinter->stem( hinter->hints, 1, top ); + } + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + /* record horizontal counter-controlled hints */ + if ( hinter ) + hinter->stem3( hinter->hints, 1, top ); + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + /* record vertical hint */ + if ( hinter ) + { + top[0] = ADD_LONG( top[0], orig_x ); + hinter->stem( hinter->hints, 0, top ); + } + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + /* record vertical counter-controlled hints */ + if ( hinter ) + { + FT_Pos dx = orig_x; + + + top[0] = ADD_LONG( top[0], dx ); + top[2] = ADD_LONG( top[2], dx ); + top[4] = ADD_LONG( top[4], dx ); + hinter->stem3( hinter->hints, 0, top ); + } + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + /* From the T1 specification, section 6.4: */ + /* */ + /* The setcurrentpoint command is used only in */ + /* conjunction with results from OtherSubrs procedures. */ + + /* known_othersubr_result_cnt != 0 is already handled */ + /* above. */ + + /* Note, however, that both Ghostscript and Adobe */ + /* Distiller handle this situation by silently ignoring */ + /* the inappropriate `setcurrentpoint' instruction. So */ + /* we do the same. */ +#if 0 + + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + } + else + ... +#endif + + x = top[0]; + y = top[1]; + decoder->flex_state = 0; + break; + + case op_unknown15: + FT_TRACE4(( " opcode_15" )); + /* nothing to do except to pop the two arguments */ + break; + + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + /* XXX Operators usually clear the operand stack; */ + /* only div, callsubr, callothersubr, pop, and */ + /* return are different. */ + /* In practice it doesn't matter (?). */ + + decoder->top = top; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( "\n" )); + bol = TRUE; +#endif + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + Fail: + return error; + + Syntax_Error: + return FT_THROW( Syntax_Error ); + + Stack_Underflow: + return FT_THROW( Stack_Underflow ); + } + + +#else /* !T1_CONFIG_OPTION_OLD_ENGINE */ + + + /************************************************************************** + * + * @Function: + * t1_decoder_parse_metrics + * + * @Description: + * Parses a given Type 1 charstrings program to extract width + * + * @Input: + * decoder :: + * The current Type 1 decoder. + * + * charstring_base :: + * The base address of the charstring stream. + * + * charstring_len :: + * The length in bytes of the charstring stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_metrics( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Bool large_int; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool bol = TRUE; +#endif + + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->parse_state = T1_Parse_Start; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + large_int = FALSE; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Int32 value = 0; + + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( bol ) + { + FT_TRACE5(( " (%ld)", decoder->top - decoder->stack )); + bol = FALSE; + } +#endif + + /********************************************************************** + * + * Decode operator or operand + * + */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 14: + case 15: + case 21: + case 22: + case 30: + case 31: + goto No_Width; + + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + + case 12: + if ( ip >= limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + + default: + goto No_Width; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) | + ( (FT_UInt32)ip[1] << 16 ) | + ( (FT_UInt32)ip[2] << 8 ) | + (FT_UInt32)ip[3] ); + ip += 4; + + /* According to the specification, values > 32000 or < -32000 must */ + /* be followed by a `div' operator to make the result be in the */ + /* range [-32000;32000]. We expect that the second argument of */ + /* `div' is not a large number. Additionally, we don't handle */ + /* stuff like ` div div' or */ + /* div div'. This is probably not allowed */ + /* anyway. */ + if ( value > 32000 || value < -32000 ) + { + if ( large_int ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + else + large_int = TRUE; + } + else + { + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Int32)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( ip[-2] - 247 ) * 256 ) + ip[-1] + 108; + else + value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 ); + } + + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); + } + else + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + + /********************************************************************** + * + * Push value on stack, or process operator + * + */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_metrics: stack overflow\n" )); + goto Syntax_Error; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( large_int ) + FT_TRACE4(( " %d", value )); + else + FT_TRACE4(( " %d", value / 65536 )); +#endif + + *top++ = value; + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + FT_ASSERT( num_args >= 0 ); + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + +#ifdef FT_DEBUG_LEVEL_TRACE + + switch ( op ) + { + case op_callsubr: + case op_div: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_metrics:" + " too much operands on the stack" + " (seen %ld, expected %d)\n", + top - decoder->stack, num_args )); + break; + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + top -= num_args; + + switch ( op ) + { + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + + builder->advance.x = top[1]; + builder->advance.y = 0; + + /* we only want to compute the glyph's metrics */ + /* (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->parse_state = T1_Parse_Have_Width; + + builder->left_bearing.x = ADD_LONG( builder->left_bearing.x, + top[0] ); + builder->left_bearing.y = ADD_LONG( builder->left_bearing.y, + top[1] ); + + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + /* we only want to compute the glyph's metrics */ + /* (lsb + advance width), without loading the */ + /* rest of it; so exit immediately */ + FT_TRACE4(( "\n" )); + return FT_Err_Ok; + + case op_div: + FT_TRACE4(( " div" )); + + /* if `large_int' is set, we divide unscaled numbers; */ + /* otherwise, we divide numbers in 16.16 format -- */ + /* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + top++; + + large_int = FALSE; + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + + if ( idx < 0 || idx >= decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + + /* The Type 1 driver stores subroutines without the seed bytes. */ + /* The CID driver stores subroutines with seed bytes. This */ + /* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { + /* We are using subroutines from a CID font. We must adjust */ + /* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + default: + FT_ERROR(( "t1_decoder_parse_metrics:" + " unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); + + No_Width: + FT_ERROR(( "t1_decoder_parse_metrics:" + " no width, found op %d instead\n", + ip[-1] )); + Syntax_Error: + return FT_THROW( Syntax_Error ); + + Stack_Underflow: + return FT_THROW( Stack_Underflow ); + } + +#endif /* !T1_CONFIG_OPTION_OLD_ENGINE */ + + + /* initialize T1 decoder */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_callback ) + { + FT_ZERO( decoder ); + + /* retrieve `psnames' interface from list of current modules */ + { + FT_Service_PsCMaps psnames; + + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + { + FT_ERROR(( "t1_decoder_init:" + " the `psnames' module is not available\n" )); + return FT_THROW( Unimplemented_Feature ); + } + + decoder->psnames = psnames; + } + + t1_builder_init( &decoder->builder, face, size, slot, hinting ); + + /* decoder->buildchar and decoder->len_buildchar have to be */ + /* initialized by the caller since we cannot know the length */ + /* of the BuildCharArray */ + + decoder->num_glyphs = (FT_UInt)face->num_glyphs; + decoder->glyph_names = glyph_names; + decoder->hint_mode = hint_mode; + decoder->blend = blend; + decoder->parse_callback = parse_callback; + + decoder->funcs = t1_decoder_funcs; + + return FT_Err_Ok; + } + + + /* finalize T1 decoder */ + FT_LOCAL_DEF( void ) + t1_decoder_done( T1_Decoder decoder ) + { + FT_Memory memory = decoder->builder.memory; + + + t1_builder_done( &decoder->builder ); + + if ( decoder->cf2_instance.finalizer ) + { + decoder->cf2_instance.finalizer( decoder->cf2_instance.data ); + FT_FREE( decoder->cf2_instance.data ); + } + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psaux/t1decode.h b/Dependencies/freetype/freetype/src/psaux/t1decode.h new file mode 100644 index 00000000..16203b8f --- /dev/null +++ b/Dependencies/freetype/freetype/src/psaux/t1decode.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * + * t1decode.h + * + * PostScript Type 1 decoding routines (specification). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1DECODE_H_ +#define T1DECODE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_CALLBACK_TABLE + const T1_Decoder_FuncsRec t1_decoder_funcs; + + FT_LOCAL( FT_Int ) + t1_lookup_glyph_by_stdcharcode_ps( PS_Decoder* decoder, + FT_Int charcode ); + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + FT_LOCAL( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph_index ); + + FT_LOCAL( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); +#else + FT_LOCAL( FT_Error ) + t1_decoder_parse_metrics( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ); +#endif + + FT_LOCAL( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_glyph ); + + FT_LOCAL( void ) + t1_decoder_done( T1_Decoder decoder ); + + +FT_END_HEADER + +#endif /* T1DECODE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshalgo.c b/Dependencies/freetype/freetype/src/pshinter/pshalgo.c new file mode 100644 index 00000000..967767b3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshalgo.c @@ -0,0 +1,2191 @@ +/**************************************************************************** + * + * pshalgo.c + * + * PostScript hinting algorithm (body). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "pshalgo.h" + +#include "pshnterr.h" + + +#undef FT_COMPONENT +#define FT_COMPONENT pshalgo + + +#ifdef DEBUG_HINTER + PSH_Hint_Table ps_debug_hint_table = NULL; + PSH_HintFunc ps_debug_hint_func = NULL; + PSH_Glyph ps_debug_glyph = NULL; +#endif + + +#define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */ + /* and similar glyphs */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BASIC HINTS RECORDINGS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* return true if two stem hints overlap */ + static FT_Int + psh_hint_overlap( PSH_Hint hint1, + PSH_Hint hint2 ) + { + return ADD_INT( hint1->org_pos, hint1->org_len ) >= hint2->org_pos && + ADD_INT( hint2->org_pos, hint2->org_len ) >= hint1->org_pos; + } + + + /* destroy hints table */ + static void + psh_hint_table_done( PSH_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->zones ); + table->num_zones = 0; + table->zone = NULL; + + FT_FREE( table->sort ); + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + table->sort_global = NULL; + } + + + /* deactivate all hints in a table */ + static void + psh_hint_table_deactivate( PSH_Hint_Table table ) + { + FT_UInt count = table->max_hints; + PSH_Hint hint = table->hints; + + + for ( ; count > 0; count--, hint++ ) + { + psh_hint_deactivate( hint ); + hint->order = -1; + } + } + + + /* internal function to record a new hint */ + static void + psh_hint_table_record( PSH_Hint_Table table, + FT_UInt idx ) + { + PSH_Hint hint = table->hints + idx; + + + if ( idx >= table->max_hints ) + { + FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); + return; + } + + /* ignore active hints */ + if ( psh_hint_is_active( hint ) ) + return; + + psh_hint_activate( hint ); + + /* now scan the current active hint set to check */ + /* whether `hint' overlaps with another hint */ + { + PSH_Hint* sorted = table->sort_global; + FT_UInt count = table->num_hints; + PSH_Hint hint2; + + + hint->parent = NULL; + for ( ; count > 0; count--, sorted++ ) + { + hint2 = sorted[0]; + + if ( psh_hint_overlap( hint, hint2 ) ) + { + hint->parent = hint2; + break; + } + } + } + + if ( table->num_hints < table->max_hints ) + table->sort_global[table->num_hints++] = hint; + else + FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" )); + } + + + static void + psh_hint_table_record_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit; + + + limit = hint_mask->num_bits; + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + psh_hint_table_record( table, idx ); + + mask >>= 1; + } + } + + + /* create hints table */ + static FT_Error + psh_hint_table_init( PSH_Hint_Table table, + PS_Hint_Table hints, + PS_Mask_Table hint_masks, + PS_Mask_Table counter_masks, + FT_Memory memory ) + { + FT_UInt count; + FT_Error error; + + FT_UNUSED( counter_masks ); + + + count = hints->num_hints; + + /* allocate our tables */ + if ( FT_QNEW_ARRAY( table->sort, 2 * count ) || + FT_QNEW_ARRAY( table->hints, count ) || + FT_QNEW_ARRAY( table->zones, 2 * count + 1 ) ) + goto Exit; + + table->max_hints = count; + table->sort_global = FT_OFFSET( table->sort, count ); + table->num_hints = 0; + table->num_zones = 0; + table->zone = NULL; + + /* initialize the `table->hints' array */ + { + PSH_Hint write = table->hints; + PS_Hint read = hints->hints; + + + for ( ; count > 0; count--, write++, read++ ) + { + write->org_pos = read->pos; + write->org_len = read->len; + write->flags = read->flags; + } + } + + /* we now need to determine the initial `parent' stems; first */ + /* activate the hints that are given by the initial hint masks */ + if ( hint_masks ) + { + PS_Mask mask = hint_masks->masks; + + + count = hint_masks->num_masks; + table->hint_masks = hint_masks; + + for ( ; count > 0; count--, mask++ ) + psh_hint_table_record_mask( table, mask ); + } + + /* finally, do a linear parse in case some hints were left alone */ + if ( table->num_hints != table->max_hints ) + { + FT_UInt idx; + + + FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" )); + + count = table->max_hints; + for ( idx = 0; idx < count; idx++ ) + psh_hint_table_record( table, idx ); + } + + Exit: + return error; + } + + + static void + psh_hint_table_activate_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit, count; + + + limit = hint_mask->num_bits; + count = 0; + + psh_hint_table_deactivate( table ); + + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + + if ( val & mask ) + { + PSH_Hint hint = &table->hints[idx]; + + + if ( !psh_hint_is_active( hint ) ) + { + FT_UInt count2; + +#if 0 + PSH_Hint* sort = table->sort; + PSH_Hint hint2; + + + for ( count2 = count; count2 > 0; count2--, sort++ ) + { + hint2 = sort[0]; + if ( psh_hint_overlap( hint, hint2 ) ) + FT_TRACE0(( "psh_hint_table_activate_mask:" + " found overlapping hints\n" )) + } +#else + count2 = 0; +#endif + + if ( count2 == 0 ) + { + psh_hint_activate( hint ); + if ( count < table->max_hints ) + table->sort[count++] = hint; + else + FT_TRACE0(( "psh_hint_tableactivate_mask:" + " too many active hints\n" )); + } + } + } + + mask >>= 1; + } + table->num_hints = count; + + /* now, sort the hints; they are guaranteed to not overlap */ + /* so we can compare their "org_pos" field directly */ + { + FT_UInt i1, i2; + PSH_Hint hint1, hint2; + PSH_Hint* sort = table->sort; + + + /* a simple bubble sort will do, since in 99% of cases, the hints */ + /* will be already sorted -- and the sort will be linear */ + for ( i1 = 1; i1 < count; i1++ ) + { + hint1 = sort[i1]; + /* this loop stops when i2 wraps around after reaching 0 */ + for ( i2 = i1 - 1; i2 < i1; i2-- ) + { + hint2 = sort[i2]; + + if ( hint2->org_pos < hint1->org_pos ) + break; + + sort[i2 + 1] = hint2; + sort[i2] = hint1; + } + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTS GRID-FITTING AND OPTIMIZATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 1 + static FT_Pos + psh_dimension_quantize_len( PSH_Dimension dim, + FT_Pos len, + FT_Bool do_snapping ) + { + if ( len <= 64 ) + len = 64; + else + { + FT_Pos delta = len - dim->stdw.widths[0].cur; + + + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + len = dim->stdw.widths[0].cur; + if ( len < 48 ) + len = 48; + } + + if ( len < 3 * 64 ) + { + delta = ( len & 63 ); + len &= -64; + + if ( delta < 10 ) + len += delta; + + else if ( delta < 32 ) + len += 10; + + else if ( delta < 54 ) + len += 54; + + else + len += delta; + } + else + len = FT_PIX_ROUND( len ); + } + + if ( do_snapping ) + len = FT_PIX_ROUND( len ); + + return len; + } +#endif /* 0 */ + + +#ifdef DEBUG_HINTER + + static void + ps_simple_scale( PSH_Hint_Table table, + FT_Fixed scale, + FT_Fixed delta, + FT_Int dimension ) + { + FT_UInt count; + + + for ( count = 0; count < table->max_hints; count++ ) + { + PSH_Hint hint = table->hints + count; + + + hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta; + hint->cur_len = FT_MulFix( hint->org_len, scale ); + + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); + } + } + +#endif /* DEBUG_HINTER */ + + + static FT_Fixed + psh_hint_snap_stem_side_delta( FT_Fixed pos, + FT_Fixed len ) + { + FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos; + FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len; + + + if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) ) + return delta1; + else + return delta2; + } + + + static void + psh_hint_align( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Int do_snapping; + FT_Pos fit_len; + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + /* perform stem snapping when requested - this is necessary + * for monochrome and LCD hinting modes only + */ + do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) || + ( dimension == 1 && glyph->do_vert_snapping ); + + hint->cur_len = fit_len = len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + ADD_INT( hint->org_pos, hint->org_len ), + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align( parent, globals, dimension, glyph ); + + /* keep original relation between hints, that is, use the */ + /* scaled distance between the centers of the hints to */ + /* compute the new position */ + par_org_center = parent->org_pos + ( parent->org_len >> 1 ); + par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 ); + cur_org_center = hint->org_pos + ( hint->org_len >> 1 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + hint->cur_pos = pos; + hint->cur_len = fit_len; + + /* Stem adjustment tries to snap stem widths to standard + * ones. This is important to prevent unpleasant rounding + * artefacts. + */ + if ( glyph->do_stem_adjust ) + { + if ( len <= 64 ) + { + /* the stem is less than one pixel; we will center it + * around the nearest pixel center + */ + if ( len >= 32 ) + { + /* This is a special case where we also widen the stem + * and align it to the pixel grid. + * + * stem_center = pos + (len/2) + * nearest_pixel_center = FT_ROUND(stem_center-32)+32 + * new_pos = nearest_pixel_center-32 + * = FT_ROUND(stem_center-32) + * = FT_FLOOR(stem_center-32+32) + * = FT_FLOOR(stem_center) + * new_len = 64 + */ + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ); + len = 64; + } + else if ( len > 0 ) + { + /* This is a very small stem; we simply align it to the + * pixel grid, trying to find the minimum displacement. + * + * left = pos + * right = pos + len + * left_nearest_edge = ROUND(pos) + * right_nearest_edge = ROUND(right) + * + * if ( ABS(left_nearest_edge - left) <= + * ABS(right_nearest_edge - right) ) + * new_pos = left + * else + * new_pos = right + */ + FT_Pos left_nearest = FT_PIX_ROUND( pos ); + FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); + FT_Pos left_disp = left_nearest - pos; + FT_Pos right_disp = right_nearest - ( pos + len ); + + + if ( left_disp < 0 ) + left_disp = -left_disp; + if ( right_disp < 0 ) + right_disp = -right_disp; + if ( left_disp <= right_disp ) + pos = left_nearest; + else + pos = right_nearest; + } + else + { + /* this is a ghost stem; we simply round it */ + pos = FT_PIX_ROUND( pos ); + } + } + else + { + len = psh_dimension_quantize_len( dim, len, 0 ); + } + } + + /* now that we have a good hinted stem width, try to position */ + /* the stem along a pixel grid integer coordinate */ + hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); + hint->cur_len = len; + } + } + + if ( do_snapping ) + { + pos = hint->cur_pos; + len = hint->cur_len; + + if ( len < 64 ) + len = 64; + else + len = FT_PIX_ROUND( len ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + hint->cur_pos = align.align_top - len; + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT: + hint->cur_len = len; + break; + + case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: + /* don't touch */ + break; + + + default: + hint->cur_len = len; + if ( len & 64 ) + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; + else + pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); + + hint->cur_pos = pos - ( len >> 1 ); + hint->cur_len = len; + } + } + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + + +#if 0 /* not used for now, experimental */ + + /* + * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) + * of stems + */ + static void + psh_hint_align_light( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + + FT_Pos fit_len; + + PSH_AlignmentRec align; + + + /* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + + psh_hint_set_fitted( hint ); + return; + } + + fit_len = len; + + hint->cur_len = fit_len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + ADD_INT( hint->org_pos, hint->org_len ), + hint->org_pos, + &align ); + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + + default: + { + PSH_Hint parent = hint->parent; + + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align_light( parent, globals, dimension, glyph ); + + par_org_center = parent->org_pos + ( parent->org_len / 2 ); + par_cur_center = parent->cur_pos + ( parent->cur_len / 2 ); + cur_org_center = hint->org_pos + ( hint->org_len / 2 ); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + /* Stems less than one pixel wide are easy -- we want to + * make them as dark as possible, so they must fall within + * one pixel. If the stem is split between two pixels + * then snap the edge that is nearer to the pixel boundary + * to the pixel boundary. + */ + if ( len <= 64 ) + { + if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + + /* Position stems other to minimize the amount of mid-grays. + * There are, in general, two positions that do this, + * illustrated as A) and B) below. + * + * + + + + + * + * A) |--------------------------------| + * B) |--------------------------------| + * C) |--------------------------------| + * + * Position A) (split the excess stem equally) should be better + * for stems of width N + f where f < 0.5. + * + * Position B) (split the deficiency equally) should be better + * for stems of width N + f where f > 0.5. + * + * It turns out though that minimizing the total number of lit + * pixels is also important, so position C), with one edge + * aligned with a pixel boundary is actually preferable + * to A). There are also more possible positions for C) than + * for A) or B), so it involves less distortion of the overall + * character shape. + */ + else /* len > 64 */ + { + FT_Fixed frac_len = len & 63; + FT_Fixed center = pos + ( len >> 1 ); + FT_Fixed delta_a, delta_b; + + + if ( ( len / 64 ) & 1 ) + { + delta_a = FT_PIX_FLOOR( center ) + 32 - center; + delta_b = FT_PIX_ROUND( center ) - center; + } + else + { + delta_a = FT_PIX_ROUND( center ) - center; + delta_b = FT_PIX_FLOOR( center ) + 32 - center; + } + + /* We choose between B) and C) above based on the amount + * of fractional stem width; for small amounts, choose + * C) always, for large amounts, B) always, and inbetween, + * pick whichever one involves less stem movement. + */ + if ( frac_len < 32 ) + { + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + else if ( frac_len < 48 ) + { + FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, + len ); + + if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) + pos += side_delta; + else + pos += delta_b; + } + else + { + pos += delta_b; + } + } + + hint->cur_pos = pos; + } + } /* switch */ + + psh_hint_set_fitted( hint ); + +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } + +#endif /* 0 */ + + + static void + psh_hint_table_align_hints( PSH_Hint_Table table, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Hint hint; + FT_UInt count; + +#ifdef DEBUG_HINTER + + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + + + if ( ps_debug_no_vert_hints && dimension == 0 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + + if ( ps_debug_no_horz_hints && dimension == 1 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + +#endif /* DEBUG_HINTER */ + + hint = table->hints; + count = table->max_hints; + + for ( ; count > 0; count--, hint++ ) + psh_hint_align( hint, globals, dimension, glyph ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** POINTS INTERPOLATION ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define xxDEBUG_ZONES + + +#ifdef DEBUG_ZONES + +#include FT_CONFIG_STANDARD_LIBRARY_H + + static void + psh_print_zone( PSH_Zone zone ) + { + printf( "zone [scale,delta,min,max] = [%.5f,%.2f,%d,%d]\n", + zone->scale / 65536.0, + zone->delta / 64.0, + zone->min, + zone->max ); + } + +#endif /* DEBUG_ZONES */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HINTER GLYPH MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define psh_corner_is_flat ft_corner_is_flat +#define psh_corner_orientation ft_corner_orientation + + +#ifdef COMPUTE_INFLEXS + + /* compute all inflex points in a given glyph */ + static void + psh_glyph_compute_inflections( PSH_Glyph glyph ) + { + FT_UInt n; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first, start, end, before, after; + FT_Pos in_x, in_y, out_x, out_y; + FT_Int orient_prev, orient_cur; + FT_Int finished = 0; + + + /* we need at least 4 points to create an inflection point */ + if ( glyph->contours[n].count < 4 ) + continue; + + /* compute first segment in contour */ + first = glyph->contours[n].start; + + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + + in_x = end->org_u - start->org_u; + in_y = end->org_v - start->org_v; + + } while ( in_x == 0 && in_y == 0 ); + + /* extend the segment start whenever possible */ + before = start; + do + { + do + { + start = before; + before = before->prev; + if ( before == first ) + goto Skip; + + out_x = start->org_u - before->org_u; + out_y = start->org_v - before->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_prev == 0 ); + + first = start; + in_x = out_x; + in_y = out_y; + + /* now, process all segments in the contour */ + do + { + /* first, extend current segment's end whenever possible */ + after = end; + do + { + do + { + end = after; + after = after->next; + if ( after == first ) + finished = 1; + + out_x = after->org_u - end->org_u; + out_y = after->org_v - end->org_v; + + } while ( out_x == 0 && out_y == 0 ); + + orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); + + } while ( orient_cur == 0 ); + + if ( ( orient_cur ^ orient_prev ) < 0 ) + { + do + { + psh_point_set_inflex( start ); + start = start->next; + } + while ( start != end ); + + psh_point_set_inflex( start ); + } + + start = end; + end = after; + orient_prev = orient_cur; + in_x = out_x; + in_y = out_y; + + } while ( !finished ); + + Skip: + ; + } + } + +#endif /* COMPUTE_INFLEXS */ + + + static void + psh_glyph_done( PSH_Glyph glyph ) + { + FT_Memory memory = glyph->memory; + + + psh_hint_table_done( &glyph->hint_tables[1], memory ); + psh_hint_table_done( &glyph->hint_tables[0], memory ); + + FT_FREE( glyph->points ); + FT_FREE( glyph->contours ); + + glyph->num_points = 0; + glyph->num_contours = 0; + + glyph->memory = NULL; + } + + + static PSH_Dir + psh_compute_dir( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ax, ay; + PSH_Dir result = PSH_DIR_NONE; + + + ax = FT_ABS( dx ); + ay = FT_ABS( dy ); + + if ( ay * 12 < ax ) + { + /* |dy| <<< |dx| means a near-horizontal segment */ + result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; + } + else if ( ax * 12 < ay ) + { + /* |dx| <<< |dy| means a near-vertical segment */ + result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; + } + + return result; + } + + + /* load outline point coordinates into hinter glyph */ + static void + psh_glyph_load_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_Vector* vec = glyph->outline->points; + PSH_Point point = glyph->points; + FT_UInt count = glyph->num_points; + + + for ( ; count > 0; count--, point++, vec++ ) + { + point->flags2 = 0; + point->hint = NULL; + if ( dimension == 0 ) + { + point->org_u = vec->x; + point->org_v = vec->y; + } + else + { + point->org_u = vec->y; + point->org_v = vec->x; + } + +#ifdef DEBUG_HINTER + point->org_x = vec->x; + point->org_y = vec->y; +#endif + + } + } + + + /* save hinted point coordinates back to outline */ + static void + psh_glyph_save_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_UInt n; + PSH_Point point = glyph->points; + FT_Vector* vec = glyph->outline->points; + FT_Byte* tags = glyph->outline->tags; + + + for ( n = 0; n < glyph->num_points; n++ ) + { + if ( dimension == 0 ) + vec[n].x = point->cur_u; + else + vec[n].y = point->cur_u; + + if ( psh_point_is_strong( point ) ) + tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 ); + +#ifdef DEBUG_HINTER + + if ( dimension == 0 ) + { + point->cur_x = point->cur_u; + point->flags_x = point->flags2 | point->flags; + } + else + { + point->cur_y = point->cur_u; + point->flags_y = point->flags2 | point->flags; + } + +#endif + + point++; + } + } + + + static FT_Error + psh_glyph_init( PSH_Glyph glyph, + FT_Outline* outline, + PS_Hints ps_hints, + PSH_Globals globals ) + { + FT_Error error; + FT_Memory memory; + + + /* clear all fields */ + FT_ZERO( glyph ); + + memory = glyph->memory = globals->memory; + + /* allocate and setup points + contours arrays */ + if ( FT_QNEW_ARRAY( glyph->points, outline->n_points ) || + FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) + goto Exit; + + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; + + { + FT_UInt first = 0, next, n; + PSH_Point points = glyph->points; + PSH_Contour contour = glyph->contours; + + + for ( n = 0; n < glyph->num_contours; n++ ) + { + FT_UInt count; + PSH_Point point; + + + next = outline->contours[n] + 1; + count = next - first; + + contour->start = points + first; + contour->count = count; + + if ( count > 0 ) + { + point = points + first; + + point->prev = points + next - 1; + point->contour = contour; + + for ( ; count > 1; count-- ) + { + point[0].next = point + 1; + point[1].prev = point; + point++; + point->contour = contour; + } + point->next = points + first; + } + + contour++; + first = next; + } + } + + { + PSH_Point points = glyph->points; + PSH_Point point = points; + FT_Vector* vec = outline->points; + FT_UInt n; + + + for ( n = 0; n < glyph->num_points; n++, point++ ) + { + FT_Int n_prev = (FT_Int)( point->prev - points ); + FT_Int n_next = (FT_Int)( point->next - points ); + FT_Pos dxi, dyi, dxo, dyo; + + + point->flags = 0; + if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) + psh_point_set_off( point ); + + dxi = vec[n].x - vec[n_prev].x; + dyi = vec[n].y - vec[n_prev].y; + + point->dir_in = psh_compute_dir( dxi, dyi ); + + dxo = vec[n_next].x - vec[n].x; + dyo = vec[n_next].y - vec[n].y; + + point->dir_out = psh_compute_dir( dxo, dyo ); + + /* detect smooth points */ + if ( psh_point_is_off( point ) ) + psh_point_set_smooth( point ); + + else if ( point->dir_in == point->dir_out ) + { + if ( point->dir_out != PSH_DIR_NONE || + psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) + psh_point_set_smooth( point ); + } + } + } + + glyph->outline = outline; + glyph->globals = globals; + +#ifdef COMPUTE_INFLEXS + psh_glyph_load_points( glyph, 0 ); + psh_glyph_compute_inflections( glyph ); +#endif /* COMPUTE_INFLEXS */ + + /* now deal with hints tables */ + error = psh_hint_table_init( &glyph->hint_tables [0], + &ps_hints->dimension[0].hints, + &ps_hints->dimension[0].masks, + &ps_hints->dimension[0].counters, + memory ); + if ( error ) + goto Exit; + + error = psh_hint_table_init( &glyph->hint_tables [1], + &ps_hints->dimension[1].hints, + &ps_hints->dimension[1].masks, + &ps_hints->dimension[1].counters, + memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* compute all extrema in a glyph for a given dimension */ + static void + psh_glyph_compute_extrema( PSH_Glyph glyph ) + { + FT_UInt n; + + + /* first of all, compute all local extrema */ + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first = glyph->contours[n].start; + PSH_Point point, before, after; + + + if ( glyph->contours[n].count == 0 ) + continue; + + point = first; + before = point; + + do + { + before = before->prev; + if ( before == first ) + goto Skip; + + } while ( before->org_u == point->org_u ); + + first = point = before->next; + + for (;;) + { + after = point; + do + { + after = after->next; + if ( after == first ) + goto Next; + + } while ( after->org_u == point->org_u ); + + if ( before->org_u < point->org_u ) + { + if ( after->org_u < point->org_u ) + { + /* local maximum */ + goto Extremum; + } + } + else /* before->org_u > point->org_u */ + { + if ( after->org_u > point->org_u ) + { + /* local minimum */ + Extremum: + do + { + psh_point_set_extremum( point ); + point = point->next; + + } while ( point != after ); + } + } + + before = after->prev; + point = after; + + } /* for */ + + Next: + ; + } + + /* for each extremum, determine its direction along the */ + /* orthogonal axis */ + for ( n = 0; n < glyph->num_points; n++ ) + { + PSH_Point point, before, after; + + + point = &glyph->points[n]; + before = point; + after = point; + + if ( psh_point_is_extremum( point ) ) + { + do + { + before = before->prev; + if ( before == point ) + goto Skip; + + } while ( before->org_v == point->org_v ); + + do + { + after = after->next; + if ( after == point ) + goto Skip; + + } while ( after->org_v == point->org_v ); + } + + if ( before->org_v < point->org_v && + after->org_v > point->org_v ) + { + psh_point_set_positive( point ); + } + else if ( before->org_v > point->org_v && + after->org_v < point->org_v ) + { + psh_point_set_negative( point ); + } + + Skip: + ; + } + } + + + /* the min and max are based on contour orientation and fill rule */ + static void + psh_hint_table_find_strong_points( PSH_Hint_Table table, + PSH_Point point, + FT_UInt count, + FT_Int threshold, + PSH_Dir major_dir ) + { + PSH_Hint* sort = table->sort; + FT_UInt num_hints = table->num_hints; + + + for ( ; count > 0; count--, point++ ) + { + PSH_Dir point_dir; + FT_Pos org_u = point->org_u; + + + if ( psh_point_is_strong( point ) ) + continue; + + point_dir = + (PSH_Dir)( ( point->dir_in | point->dir_out ) & major_dir ); + + if ( point_dir & ( PSH_DIR_DOWN | PSH_DIR_RIGHT ) ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; + } + } + } + else if ( point_dir & ( PSH_DIR_UP | PSH_DIR_LEFT ) ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; + } + } + } + +#if 1 + else if ( psh_point_is_extremum( point ) ) + { + /* treat extrema as special cases for stem edge alignment */ + FT_UInt nn, min_flag, max_flag; + + + if ( major_dir == PSH_DIR_HORIZONTAL ) + { + min_flag = PSH_POINT_POSITIVE; + max_flag = PSH_POINT_NEGATIVE; + } + else + { + min_flag = PSH_POINT_NEGATIVE; + max_flag = PSH_POINT_POSITIVE; + } + + if ( point->flags2 & min_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + else if ( point->flags2 & max_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + + + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + + if ( !point->hint ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + + + if ( org_u >= hint->org_pos && + org_u <= ADD_INT( hint->org_pos, hint->org_len ) ) + { + point->hint = hint; + break; + } + } + } + } + +#endif /* 1 */ + } + } + + + /* the accepted shift for strong points in fractional pixels */ +#define PSH_STRONG_THRESHOLD 32 + + /* the maximum shift value in font units tuned to distinguish */ + /* between stems and serifs in URW+ font collection */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 12 + + + /* find strong points in a glyph */ + static void + psh_glyph_find_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + /* a point is `strong' if it is located on a stem edge and */ + /* has an `in' or `out' tangent parallel to the hint's direction */ + + PSH_Hint_Table table = &glyph->hint_tables[dimension]; + PS_Mask mask = table->hint_masks->masks; + FT_UInt num_masks = table->hint_masks->num_masks; + FT_UInt first = 0; + PSH_Dir major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL + : PSH_DIR_HORIZONTAL; + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Int threshold; + + + threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); + if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) + threshold = PSH_STRONG_THRESHOLD_MAXIMUM; + + /* process secondary hints to `selected' points */ + if ( num_masks > 1 && glyph->num_points > 0 ) + { + /* the `endchar' op can reduce the number of points */ + first = mask->end_point > glyph->num_points + ? glyph->num_points + : mask->end_point; + mask++; + for ( ; num_masks > 1; num_masks--, mask++ ) + { + FT_UInt next = FT_MIN( mask->end_point, glyph->num_points ); + + + if ( next > first ) + { + FT_UInt count = next - first; + PSH_Point point = glyph->points + first; + + + psh_hint_table_activate_mask( table, mask ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + first = next; + } + } + + /* process primary hints for all points */ + if ( num_masks == 1 ) + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + psh_hint_table_activate_mask( table, table->hint_masks->masks ); + + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + + /* now, certain points may have been attached to a hint and */ + /* not marked as strong; update their flags then */ + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + if ( point->hint && !psh_point_is_strong( point ) ) + psh_point_set_strong( point ); + } + } + + + /* find points in a glyph which are in a blue zone and have `in' or */ + /* `out' tangents parallel to the horizontal axis */ + static void + psh_glyph_find_blue_points( PSH_Blues blues, + PSH_Glyph glyph ) + { + PSH_Blue_Table table; + PSH_Blue_Zone zone; + FT_UInt glyph_count = glyph->num_points; + FT_UInt blue_count; + PSH_Point point = glyph->points; + + + for ( ; glyph_count > 0; glyph_count--, point++ ) + { + FT_Pos y; + + + /* check tangents */ + if ( !( point->dir_in & PSH_DIR_HORIZONTAL ) && + !( point->dir_out & PSH_DIR_HORIZONTAL ) ) + continue; + + /* skip strong points */ + if ( psh_point_is_strong( point ) ) + continue; + + y = point->org_u; + + /* look up top zones */ + table = &blues->normal_top; + blue_count = table->count; + zone = table->zones; + + for ( ; blue_count > 0; blue_count--, zone++ ) + { + FT_Pos delta = y - zone->org_bottom; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y <= zone->org_top + blues->blue_fuzz ) + if ( blues->no_overshoots || delta <= blues->blue_threshold ) + { + point->cur_u = zone->cur_bottom; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + + /* look up bottom zones */ + table = &blues->normal_bottom; + blue_count = table->count; + zone = table->zones + blue_count - 1; + + for ( ; blue_count > 0; blue_count--, zone-- ) + { + FT_Pos delta = zone->org_top - y; + + + if ( delta < -blues->blue_fuzz ) + break; + + if ( y >= zone->org_bottom - blues->blue_fuzz ) + if ( blues->no_overshoots || delta < blues->blue_threshold ) + { + point->cur_u = zone->cur_top; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + } + } + + + /* interpolate strong points with the help of hinted coordinates */ + static void + psh_glyph_interpolate_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + + + for ( ; count > 0; count--, point++ ) + { + PSH_Hint hint = point->hint; + + + if ( hint ) + { + FT_Pos delta; + + + if ( psh_point_is_edge_min( point ) ) + point->cur_u = hint->cur_pos; + + else if ( psh_point_is_edge_max( point ) ) + point->cur_u = hint->cur_pos + hint->cur_len; + + else + { + delta = point->org_u - hint->org_pos; + + if ( delta <= 0 ) + point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); + + else if ( delta >= hint->org_len ) + point->cur_u = hint->cur_pos + hint->cur_len + + FT_MulFix( delta - hint->org_len, scale ); + + else /* hint->org_len > 0 */ + point->cur_u = hint->cur_pos + + FT_MulDiv( delta, hint->cur_len, + hint->org_len ); + } + psh_point_set_fitted( point ); + } + } + } + + +#define PSH_MAX_STRONG_INTERNAL 16 + + static void + psh_glyph_interpolate_normal_points( PSH_Glyph glyph, + FT_Int dimension ) + { + +#if 1 + /* first technique: a point is strong if it is a local extremum */ + + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Memory memory = glyph->memory; + + PSH_Point* strongs = NULL; + PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; + FT_UInt num_strongs = 0; + + PSH_Point points = glyph->points; + PSH_Point points_end = points + glyph->num_points; + PSH_Point point; + + + /* first count the number of strong points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + num_strongs++; + } + + if ( num_strongs == 0 ) /* nothing to do here */ + return; + + /* allocate an array to store a list of points, */ + /* stored in increasing org_u order */ + if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) + strongs = strongs_0; + else + { + FT_Error error; + + + if ( FT_QNEW_ARRAY( strongs, num_strongs ) ) + return; + } + + num_strongs = 0; + for ( point = points; point < points_end; point++ ) + { + PSH_Point* insert; + + + if ( !psh_point_is_strong( point ) ) + continue; + + for ( insert = strongs + num_strongs; insert > strongs; insert-- ) + { + if ( insert[-1]->org_u <= point->org_u ) + break; + + insert[0] = insert[-1]; + } + insert[0] = point; + num_strongs++; + } + + /* now try to interpolate all normal points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + continue; + + /* sometimes, some local extrema are smooth points */ + if ( psh_point_is_smooth( point ) ) + { + if ( point->dir_in == PSH_DIR_NONE || + point->dir_in != point->dir_out ) + continue; + + if ( !psh_point_is_extremum( point ) && + !psh_point_is_inflex( point ) ) + continue; + + point->flags &= ~PSH_POINT_SMOOTH; + } + + /* find best enclosing point coordinates then interpolate */ + { + PSH_Point before, after; + FT_UInt nn; + + + for ( nn = 0; nn < num_strongs; nn++ ) + if ( strongs[nn]->org_u > point->org_u ) + break; + + if ( nn == 0 ) /* point before the first strong point */ + { + after = strongs[0]; + + point->cur_u = after->cur_u + + FT_MulFix( point->org_u - after->org_u, + scale ); + } + else + { + before = strongs[nn - 1]; + + for ( nn = num_strongs; nn > 0; nn-- ) + if ( strongs[nn - 1]->org_u < point->org_u ) + break; + + if ( nn == num_strongs ) /* point is after last strong point */ + { + before = strongs[nn - 1]; + + point->cur_u = before->cur_u + + FT_MulFix( point->org_u - before->org_u, + scale ); + } + else + { + FT_Pos u; + + + after = strongs[nn]; + + /* now interpolate point between before and after */ + u = point->org_u; + + if ( u == before->org_u ) + point->cur_u = before->cur_u; + + else if ( u == after->org_u ) + point->cur_u = after->cur_u; + + else + point->cur_u = before->cur_u + + FT_MulDiv( u - before->org_u, + after->cur_u - before->cur_u, + after->org_u - before->org_u ); + } + } + psh_point_set_fitted( point ); + } + } + + if ( strongs != strongs_0 ) + FT_FREE( strongs ); + +#endif /* 1 */ + + } + + + /* interpolate other points */ + static void + psh_glyph_interpolate_other_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + PSH_Contour contour = glyph->contours; + FT_UInt num_contours = glyph->num_contours; + + + for ( ; num_contours > 0; num_contours--, contour++ ) + { + PSH_Point start = contour->start; + PSH_Point first, next, point; + FT_UInt fit_count; + + + /* count the number of strong points in this contour */ + next = start + contour->count; + fit_count = 0; + first = NULL; + + for ( point = start; point < next; point++ ) + if ( psh_point_is_fitted( point ) ) + { + if ( !first ) + first = point; + + fit_count++; + } + + /* if there are less than 2 fitted points in the contour, we */ + /* simply scale and eventually translate the contour points */ + if ( fit_count < 2 ) + { + if ( fit_count == 1 ) + delta = first->cur_u - FT_MulFix( first->org_u, scale ); + + for ( point = start; point < next; point++ ) + if ( point != first ) + point->cur_u = FT_MulFix( point->org_u, scale ) + delta; + + goto Next_Contour; + } + + /* there are more than 2 strong points in this contour; we */ + /* need to interpolate weak points between them */ + start = first; + do + { + /* skip consecutive fitted points */ + for (;;) + { + next = first->next; + if ( next == start ) + goto Next_Contour; + + if ( !psh_point_is_fitted( next ) ) + break; + + first = next; + } + + /* find next fitted point after unfitted one */ + for (;;) + { + next = next->next; + if ( psh_point_is_fitted( next ) ) + break; + } + + /* now interpolate between them */ + { + FT_Pos org_a, org_ab, cur_a, cur_ab; + FT_Pos org_c, org_ac, cur_c; + FT_Fixed scale_ab; + + + if ( first->org_u <= next->org_u ) + { + org_a = first->org_u; + cur_a = first->cur_u; + org_ab = next->org_u - org_a; + cur_ab = next->cur_u - cur_a; + } + else + { + org_a = next->org_u; + cur_a = next->cur_u; + org_ab = first->org_u - org_a; + cur_ab = first->cur_u - cur_a; + } + + scale_ab = 0x10000L; + if ( org_ab > 0 ) + scale_ab = FT_DivFix( cur_ab, org_ab ); + + point = first->next; + do + { + org_c = point->org_u; + org_ac = org_c - org_a; + + if ( org_ac <= 0 ) + { + /* on the left of the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale ); + } + else if ( org_ac >= org_ab ) + { + /* on the right on the interpolation zone */ + cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); + } + else + { + /* within the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); + } + + point->cur_u = cur_c; + + point = point->next; + + } while ( point != next ); + } + + /* keep going until all points in the contours have been processed */ + first = next; + + } while ( first != start ); + + Next_Contour: + ; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** HIGH-LEVEL INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + PSH_GlyphRec glyphrec; + PSH_Glyph glyph = &glyphrec; + FT_Error error; +#ifdef DEBUG_HINTER + FT_Memory memory; +#endif + FT_Int dimension; + + + /* something to do? */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return FT_Err_Ok; + +#ifdef DEBUG_HINTER + + memory = globals->memory; + + if ( ps_debug_glyph ) + { + psh_glyph_done( ps_debug_glyph ); + FT_FREE( ps_debug_glyph ); + } + + if ( FT_NEW( glyph ) ) + return error; + + ps_debug_glyph = glyph; + +#endif /* DEBUG_HINTER */ + + error = psh_glyph_init( glyph, outline, ps_hints, globals ); + if ( error ) + goto Exit; + + /* try to optimize the y_scale so that the top of non-capital letters + * is aligned on a pixel boundary whenever possible + */ + { + PSH_Dimension dim_x = &glyph->globals->dimension[0]; + PSH_Dimension dim_y = &glyph->globals->dimension[1]; + + FT_Fixed x_scale = dim_x->scale_mult; + FT_Fixed y_scale = dim_y->scale_mult; + + FT_Fixed old_x_scale = x_scale; + FT_Fixed old_y_scale = y_scale; + + FT_Fixed scaled = 0; + FT_Fixed fitted = 0; + + FT_Bool rescale = FALSE; + + + if ( globals->blues.normal_top.count ) + { + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + } + + if ( fitted != 0 && scaled != fitted ) + { + rescale = TRUE; + + y_scale = FT_MulDiv( y_scale, fitted, scaled ); + + if ( fitted < scaled ) + x_scale -= x_scale / 50; + + psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); + } + + glyph->do_horz_hints = 1; + glyph->do_vert_hints = 1; + + glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD ); + + glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD_V ); + + glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + + for ( dimension = 0; dimension < 2; dimension++ ) + { + /* load outline coordinates into glyph */ + psh_glyph_load_points( glyph, dimension ); + + /* compute local extrema */ + psh_glyph_compute_extrema( glyph ); + + /* compute aligned stem/hints positions */ + psh_hint_table_align_hints( &glyph->hint_tables[dimension], + glyph->globals, + dimension, + glyph ); + + /* find strong points, align them, then interpolate others */ + psh_glyph_find_strong_points( glyph, dimension ); + if ( dimension == 1 ) + psh_glyph_find_blue_points( &globals->blues, glyph ); + psh_glyph_interpolate_strong_points( glyph, dimension ); + psh_glyph_interpolate_normal_points( glyph, dimension ); + psh_glyph_interpolate_other_points( glyph, dimension ); + + /* save hinted coordinates back to outline */ + psh_glyph_save_points( glyph, dimension ); + + if ( rescale ) + psh_globals_set_scale( glyph->globals, + old_x_scale, old_y_scale, 0, 0 ); + } + } + + Exit: + +#ifndef DEBUG_HINTER + psh_glyph_done( glyph ); +#endif + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshalgo.h b/Dependencies/freetype/freetype/src/pshinter/pshalgo.h new file mode 100644 index 00000000..fb362f06 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshalgo.h @@ -0,0 +1,233 @@ +/**************************************************************************** + * + * pshalgo.h + * + * PostScript hinting algorithm (specification). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHALGO_H_ +#define PSHALGO_H_ + + +#include "pshrec.h" +#include "pshglob.h" + + +FT_BEGIN_HEADER + + + /* handle to Hint structure */ + typedef struct PSH_HintRec_* PSH_Hint; + + + /* hint bit-flags */ +#define PSH_HINT_GHOST PS_HINT_FLAG_GHOST +#define PSH_HINT_BOTTOM PS_HINT_FLAG_BOTTOM +#define PSH_HINT_ACTIVE 4U +#define PSH_HINT_FITTED 8U + + +#define psh_hint_is_active( x ) ( ( (x)->flags & PSH_HINT_ACTIVE ) != 0 ) +#define psh_hint_is_ghost( x ) ( ( (x)->flags & PSH_HINT_GHOST ) != 0 ) +#define psh_hint_is_fitted( x ) ( ( (x)->flags & PSH_HINT_FITTED ) != 0 ) + +#define psh_hint_activate( x ) (x)->flags |= PSH_HINT_ACTIVE +#define psh_hint_deactivate( x ) (x)->flags &= ~PSH_HINT_ACTIVE +#define psh_hint_set_fitted( x ) (x)->flags |= PSH_HINT_FITTED + + + /* hint structure */ + typedef struct PSH_HintRec_ + { + FT_Int org_pos; + FT_Int org_len; + FT_Pos cur_pos; + FT_Pos cur_len; + FT_UInt flags; + PSH_Hint parent; + FT_Int order; + + } PSH_HintRec; + + + /* this is an interpolation zone used for strong points; */ + /* weak points are interpolated according to their strong */ + /* neighbours */ + typedef struct PSH_ZoneRec_ + { + FT_Fixed scale; + FT_Fixed delta; + FT_Pos min; + FT_Pos max; + + } PSH_ZoneRec, *PSH_Zone; + + + typedef struct PSH_Hint_TableRec_ + { + FT_UInt max_hints; + FT_UInt num_hints; + PSH_Hint hints; + PSH_Hint* sort; + PSH_Hint* sort_global; + FT_UInt num_zones; + PSH_ZoneRec* zones; + PSH_Zone zone; + PS_Mask_Table hint_masks; + PS_Mask_Table counter_masks; + + } PSH_Hint_TableRec, *PSH_Hint_Table; + + + typedef struct PSH_PointRec_* PSH_Point; + typedef struct PSH_ContourRec_* PSH_Contour; + + typedef enum PSH_Dir_ + { + PSH_DIR_NONE = 0, + PSH_DIR_UP = 1, + PSH_DIR_DOWN = 2, + PSH_DIR_VERTICAL = 1 | 2, + PSH_DIR_LEFT = 4, + PSH_DIR_RIGHT = 8, + PSH_DIR_HORIZONTAL = 4 | 8 + + } PSH_Dir; + + + /* the following bit-flags are computed once by the glyph */ + /* analyzer, for both dimensions */ +#define PSH_POINT_OFF 1U /* point is off the curve */ +#define PSH_POINT_SMOOTH 2U /* point is smooth */ +#define PSH_POINT_INFLEX 4U /* point is inflection */ + + +#define psh_point_is_smooth( p ) ( (p)->flags & PSH_POINT_SMOOTH ) +#define psh_point_is_off( p ) ( (p)->flags & PSH_POINT_OFF ) +#define psh_point_is_inflex( p ) ( (p)->flags & PSH_POINT_INFLEX ) + +#define psh_point_set_smooth( p ) (p)->flags |= PSH_POINT_SMOOTH +#define psh_point_set_off( p ) (p)->flags |= PSH_POINT_OFF +#define psh_point_set_inflex( p ) (p)->flags |= PSH_POINT_INFLEX + + + /* the following bit-flags are re-computed for each dimension */ +#define PSH_POINT_STRONG 16U /* point is strong */ +#define PSH_POINT_FITTED 32U /* point is already fitted */ +#define PSH_POINT_EXTREMUM 64U /* point is local extremum */ +#define PSH_POINT_POSITIVE 128U /* extremum has positive contour flow */ +#define PSH_POINT_NEGATIVE 256U /* extremum has negative contour flow */ +#define PSH_POINT_EDGE_MIN 512U /* point is aligned to left/bottom stem edge */ +#define PSH_POINT_EDGE_MAX 1024U /* point is aligned to top/right stem edge */ + + +#define psh_point_is_strong( p ) ( (p)->flags2 & PSH_POINT_STRONG ) +#define psh_point_is_fitted( p ) ( (p)->flags2 & PSH_POINT_FITTED ) +#define psh_point_is_extremum( p ) ( (p)->flags2 & PSH_POINT_EXTREMUM ) +#define psh_point_is_positive( p ) ( (p)->flags2 & PSH_POINT_POSITIVE ) +#define psh_point_is_negative( p ) ( (p)->flags2 & PSH_POINT_NEGATIVE ) +#define psh_point_is_edge_min( p ) ( (p)->flags2 & PSH_POINT_EDGE_MIN ) +#define psh_point_is_edge_max( p ) ( (p)->flags2 & PSH_POINT_EDGE_MAX ) + +#define psh_point_set_strong( p ) (p)->flags2 |= PSH_POINT_STRONG +#define psh_point_set_fitted( p ) (p)->flags2 |= PSH_POINT_FITTED +#define psh_point_set_extremum( p ) (p)->flags2 |= PSH_POINT_EXTREMUM +#define psh_point_set_positive( p ) (p)->flags2 |= PSH_POINT_POSITIVE +#define psh_point_set_negative( p ) (p)->flags2 |= PSH_POINT_NEGATIVE +#define psh_point_set_edge_min( p ) (p)->flags2 |= PSH_POINT_EDGE_MIN +#define psh_point_set_edge_max( p ) (p)->flags2 |= PSH_POINT_EDGE_MAX + + + typedef struct PSH_PointRec_ + { + PSH_Point prev; + PSH_Point next; + PSH_Contour contour; + FT_UInt flags; + FT_UInt flags2; + PSH_Dir dir_in; + PSH_Dir dir_out; + PSH_Hint hint; + FT_Pos org_u; + FT_Pos org_v; + FT_Pos cur_u; +#ifdef DEBUG_HINTER + FT_Pos org_x; + FT_Pos cur_x; + FT_Pos org_y; + FT_Pos cur_y; + FT_UInt flags_x; + FT_UInt flags_y; +#endif + + } PSH_PointRec; + + + typedef struct PSH_ContourRec_ + { + PSH_Point start; + FT_UInt count; + + } PSH_ContourRec; + + + typedef struct PSH_GlyphRec_ + { + FT_UInt num_points; + FT_UInt num_contours; + + PSH_Point points; + PSH_Contour contours; + + FT_Memory memory; + FT_Outline* outline; + PSH_Globals globals; + PSH_Hint_TableRec hint_tables[2]; + + FT_Bool do_horz_hints; + FT_Bool do_vert_hints; + FT_Bool do_horz_snapping; + FT_Bool do_vert_snapping; + FT_Bool do_stem_adjust; + + } PSH_GlyphRec, *PSH_Glyph; + + +#ifdef DEBUG_HINTER + extern PSH_Hint_Table ps_debug_hint_table; + + typedef void + (*PSH_HintFunc)( PSH_Hint hint, + FT_Bool vertical ); + + extern PSH_HintFunc ps_debug_hint_func; + + extern PSH_Glyph ps_debug_glyph; +#endif + + + extern FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); + + +FT_END_HEADER + + +#endif /* PSHALGO_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshglob.c b/Dependencies/freetype/freetype/src/pshinter/pshglob.c new file mode 100644 index 00000000..435f4583 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshglob.c @@ -0,0 +1,795 @@ +/**************************************************************************** + * + * pshglob.c + * + * PostScript hinter global hinting management (body). + * Inspired by the new auto-hinter module. + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "pshglob.h" + +#ifdef DEBUG_HINTER + PSH_Globals ps_debug_globals = NULL; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** STANDARD WIDTHS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* scale the widths/heights table */ + static void + psh_globals_scale_widths( PSH_Globals globals, + FT_UInt direction ) + { + PSH_Dimension dim = &globals->dimension[direction]; + PSH_Widths stdw = &dim->stdw; + FT_UInt count = stdw->count; + PSH_Width width = stdw->widths; + PSH_Width stand = width; /* standard width/height */ + FT_Fixed scale = dim->scale_mult; + + + if ( count > 0 ) + { + width->cur = FT_MulFix( width->org, scale ); + width->fit = FT_PIX_ROUND( width->cur ); + + width++; + count--; + + for ( ; count > 0; count--, width++ ) + { + FT_Pos w, dist; + + + w = FT_MulFix( width->org, scale ); + dist = w - stand->cur; + + if ( dist < 0 ) + dist = -dist; + + if ( dist < 128 ) + w = stand->cur; + + width->cur = w; + width->fit = FT_PIX_ROUND( w ); + } + } + } + + +#if 0 + + /* org_width is in font units, result in device pixels, 26.6 format */ + FT_LOCAL_DEF( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ) + { + FT_UInt n; + FT_Pos width = FT_MulFix( org_width, dimension->scale_mult ); + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + + + for ( n = 0; n < dimension->stdw.count; n++ ) + { + FT_Pos w; + FT_Pos dist; + + + w = dimension->stdw.widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + + if ( width >= reference ) + { + width -= 0x21; + if ( width < reference ) + width = reference; + } + else + { + width += 0x21; + if ( width > reference ) + width = reference; + } + + return width; + } + +#endif /* 0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** BLUE ZONES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_blues_set_zones_0( PSH_Blues target, + FT_Bool is_others, + FT_UInt read_count, + FT_Short* read, + PSH_Blue_Table top_table, + PSH_Blue_Table bot_table ) + { + FT_UInt count_top = top_table->count; + FT_UInt count_bot = bot_table->count; + FT_Bool first = 1; + + FT_UNUSED( target ); + + + for ( ; read_count > 1; read_count -= 2 ) + { + FT_Int reference, delta; + FT_UInt count; + PSH_Blue_Zone zones, zone; + FT_Bool top; + + + /* read blue zone entry, and select target top/bottom zone */ + top = 0; + if ( first || is_others ) + { + reference = read[1]; + delta = read[0] - reference; + + zones = bot_table->zones; + count = count_bot; + first = 0; + } + else + { + reference = read[0]; + delta = read[1] - reference; + + zones = top_table->zones; + count = count_top; + top = 1; + } + + /* insert into sorted table */ + zone = zones; + for ( ; count > 0; count--, zone++ ) + { + if ( reference < zone->org_ref ) + break; + + if ( reference == zone->org_ref ) + { + FT_Int delta0 = zone->org_delta; + + + /* we have two zones on the same reference position -- */ + /* only keep the largest one */ + if ( delta < 0 ) + { + if ( delta < delta0 ) + zone->org_delta = delta; + } + else + { + if ( delta > delta0 ) + zone->org_delta = delta; + } + goto Skip; + } + } + + for ( ; count > 0; count-- ) + zone[count] = zone[count-1]; + + zone->org_ref = reference; + zone->org_delta = delta; + + if ( top ) + count_top++; + else + count_bot++; + + Skip: + read += 2; + } + + top_table->count = count_top; + bot_table->count = count_bot; + } + + + /* Re-read blue zones from the original fonts and store them into our */ + /* private structure. This function re-orders, sanitizes, and */ + /* fuzz-expands the zones as well. */ + static void + psh_blues_set_zones( PSH_Blues target, + FT_UInt count, + FT_Short* blues, + FT_UInt count_others, + FT_Short* other_blues, + FT_Int fuzz, + FT_Int family ) + { + PSH_Blue_Table top_table, bot_table; + FT_UInt count_top, count_bot; + + + if ( family ) + { + top_table = &target->family_top; + bot_table = &target->family_bottom; + } + else + { + top_table = &target->normal_top; + bot_table = &target->normal_bottom; + } + + /* read the input blue zones, and build two sorted tables */ + /* (one for the top zones, the other for the bottom zones) */ + top_table->count = 0; + bot_table->count = 0; + + /* first, the blues */ + psh_blues_set_zones_0( target, 0, + count, blues, top_table, bot_table ); + psh_blues_set_zones_0( target, 1, + count_others, other_blues, top_table, bot_table ); + + count_top = top_table->count; + count_bot = bot_table->count; + + /* sanitize top table */ + if ( count_top > 0 ) + { + PSH_Blue_Zone zone = top_table->zones; + + + for ( count = count_top; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[1].org_ref - zone[0].org_ref; + if ( zone->org_delta > delta ) + zone->org_delta = delta; + } + + zone->org_bottom = zone->org_ref; + zone->org_top = zone->org_delta + zone->org_ref; + } + } + + /* sanitize bottom table */ + if ( count_bot > 0 ) + { + PSH_Blue_Zone zone = bot_table->zones; + + + for ( count = count_bot; count > 0; count--, zone++ ) + { + FT_Int delta; + + + if ( count > 1 ) + { + delta = zone[0].org_ref - zone[1].org_ref; + if ( zone->org_delta < delta ) + zone->org_delta = delta; + } + + zone->org_top = zone->org_ref; + zone->org_bottom = zone->org_delta + zone->org_ref; + } + } + + /* expand top and bottom tables with blue fuzz */ + { + FT_Int dim, top, bot, delta; + PSH_Blue_Zone zone; + + + zone = top_table->zones; + count = count_top; + + for ( dim = 1; dim >= 0; dim-- ) + { + if ( count > 0 ) + { + /* expand the bottom of the lowest zone normally */ + zone->org_bottom -= fuzz; + + /* expand the top and bottom of intermediate zones; */ + /* checking that the interval is smaller than the fuzz */ + top = zone->org_top; + + for ( count--; count > 0; count-- ) + { + bot = zone[1].org_bottom; + delta = bot - top; + + if ( delta / 2 < fuzz ) + zone[0].org_top = zone[1].org_bottom = top + delta / 2; + else + { + zone[0].org_top = top + fuzz; + zone[1].org_bottom = bot - fuzz; + } + + zone++; + top = zone->org_top; + } + + /* expand the top of the highest zone normally */ + zone->org_top = top + fuzz; + } + zone = bot_table->zones; + count = count_bot; + } + } + } + + + /* reset the blues table when the device transform changes */ + static void + psh_blues_scale_zones( PSH_Blues blues, + FT_Fixed scale, + FT_Pos delta ) + { + FT_UInt count; + FT_UInt num; + PSH_Blue_Table table = NULL; + + /* */ + /* Determine whether we need to suppress overshoots or */ + /* not. We simply need to compare the vertical scale */ + /* parameter to the raw bluescale value. Here is why: */ + /* */ + /* We need to suppress overshoots for all pointsizes. */ + /* At 300dpi that satisfies: */ + /* */ + /* pointsize < 240*bluescale + 0.49 */ + /* */ + /* This corresponds to: */ + /* */ + /* pixelsize < 1000*bluescale + 49/24 */ + /* */ + /* scale*EM_Size < 1000*bluescale + 49/24 */ + /* */ + /* However, for normal Type 1 fonts, EM_Size is 1000! */ + /* We thus only check: */ + /* */ + /* scale < bluescale + 49/24000 */ + /* */ + /* which we shorten to */ + /* */ + /* "scale < bluescale" */ + /* */ + /* Note that `blue_scale' is stored 1000 times its real */ + /* value, and that `scale' converts from font units to */ + /* fractional pixels. */ + /* */ + + /* 1000 / 64 = 125 / 8 */ + if ( scale >= 0x20C49BAL ) + blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 ); + else + blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 ); + + /* */ + /* The blue threshold is the font units distance under */ + /* which overshoots are suppressed due to the BlueShift */ + /* even if the scale is greater than BlueScale. */ + /* */ + /* It is the smallest distance such that */ + /* */ + /* dist <= BlueShift && dist*scale <= 0.5 pixels */ + /* */ + { + FT_Int threshold = blues->blue_shift; + + + while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 ) + threshold--; + + blues->blue_threshold = threshold; + } + + for ( num = 0; num < 4; num++ ) + { + PSH_Blue_Zone zone; + + + switch ( num ) + { + case 0: + table = &blues->normal_top; + break; + case 1: + table = &blues->normal_bottom; + break; + case 2: + table = &blues->family_top; + break; + default: + table = &blues->family_bottom; + break; + } + + zone = table->zones; + count = table->count; + for ( ; count > 0; count--, zone++ ) + { + zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta; + zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta; + zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta; + zone->cur_delta = FT_MulFix( zone->org_delta, scale ); + + /* round scaled reference position */ + zone->cur_ref = FT_PIX_ROUND( zone->cur_ref ); + +#if 0 + if ( zone->cur_ref > zone->cur_top ) + zone->cur_ref -= 64; + else if ( zone->cur_ref < zone->cur_bottom ) + zone->cur_ref += 64; +#endif + } + } + + /* process the families now */ + + for ( num = 0; num < 2; num++ ) + { + PSH_Blue_Zone zone1, zone2; + FT_UInt count1, count2; + PSH_Blue_Table normal, family; + + + switch ( num ) + { + case 0: + normal = &blues->normal_top; + family = &blues->family_top; + break; + + default: + normal = &blues->normal_bottom; + family = &blues->family_bottom; + } + + zone1 = normal->zones; + count1 = normal->count; + + for ( ; count1 > 0; count1--, zone1++ ) + { + /* try to find a family zone whose reference position is less */ + /* than 1 pixel far from the current zone */ + zone2 = family->zones; + count2 = family->count; + + for ( ; count2 > 0; count2--, zone2++ ) + { + FT_Pos Delta; + + + Delta = zone1->org_ref - zone2->org_ref; + if ( Delta < 0 ) + Delta = -Delta; + + if ( FT_MulFix( Delta, scale ) < 64 ) + { + zone1->cur_top = zone2->cur_top; + zone1->cur_bottom = zone2->cur_bottom; + zone1->cur_ref = zone2->cur_ref; + zone1->cur_delta = zone2->cur_delta; + break; + } + } + } + } + } + + + /* calculate the maximum height of given blue zones */ + static FT_Short + psh_calc_max_height( FT_UInt num, + const FT_Short* values, + FT_Short cur_max ) + { + FT_UInt count; + + + for ( count = 0; count < num; count += 2 ) + { + FT_Short cur_height = values[count + 1] - values[count]; + + + if ( cur_height > cur_max ) + cur_max = cur_height; + } + + return cur_max; + } + + + FT_LOCAL_DEF( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ) + { + PSH_Blue_Table table; + FT_UInt count; + FT_Pos delta; + PSH_Blue_Zone zone; + FT_Int no_shoots; + + + alignment->align = PSH_BLUE_ALIGN_NONE; + + no_shoots = blues->no_overshoots; + + /* look up stem top in top zones table */ + table = &blues->normal_top; + count = table->count; + zone = table->zones; + + for ( ; count > 0; count--, zone++ ) + { + delta = SUB_LONG( stem_top, zone->org_bottom ); + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_top <= zone->org_top + blues->blue_fuzz ) + { + if ( no_shoots || delta <= blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_TOP; + alignment->align_top = zone->cur_ref; + } + break; + } + } + + /* look up stem bottom in bottom zones table */ + table = &blues->normal_bottom; + count = table->count; + zone = table->zones + count-1; + + for ( ; count > 0; count--, zone-- ) + { + delta = SUB_LONG( zone->org_top, stem_bot ); + if ( delta < -blues->blue_fuzz ) + break; + + if ( stem_bot >= zone->org_bottom - blues->blue_fuzz ) + { + if ( no_shoots || delta < blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_BOT; + alignment->align_bot = zone->cur_ref; + } + break; + } + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + psh_globals_destroy( PSH_Globals globals ) + { + if ( globals ) + { + FT_Memory memory; + + + memory = globals->memory; + globals->dimension[0].stdw.count = 0; + globals->dimension[1].stdw.count = 0; + + globals->blues.normal_top.count = 0; + globals->blues.normal_bottom.count = 0; + globals->blues.family_top.count = 0; + globals->blues.family_bottom.count = 0; + + FT_FREE( globals ); + +#ifdef DEBUG_HINTER + ps_debug_globals = NULL; +#endif + } + } + + + static FT_Error + psh_globals_new( FT_Memory memory, + T1_Private* priv, + PSH_Globals *aglobals ) + { + PSH_Globals globals = NULL; + FT_Error error; + + + if ( !FT_QNEW( globals ) ) + { + FT_UInt count; + FT_Short* read; + + + globals->memory = memory; + + /* copy standard widths */ + { + PSH_Dimension dim = &globals->dimension[1]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_width[0]; + write++; + + read = priv->snap_widths; + for ( count = priv->num_snap_widths; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_widths + 1; + } + + /* copy standard heights */ + { + PSH_Dimension dim = &globals->dimension[0]; + PSH_Width write = dim->stdw.widths; + + + write->org = priv->standard_height[0]; + write++; + read = priv->snap_heights; + for ( count = priv->num_snap_heights; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + + dim->stdw.count = priv->num_snap_heights + 1; + } + + /* copy blue zones */ + psh_blues_set_zones( &globals->blues, priv->num_blue_values, + priv->blue_values, priv->num_other_blues, + priv->other_blues, priv->blue_fuzz, 0 ); + + psh_blues_set_zones( &globals->blues, priv->num_family_blues, + priv->family_blues, priv->num_family_other_blues, + priv->family_other_blues, priv->blue_fuzz, 1 ); + + /* limit the BlueScale value to `1 / max_of_blue_zone_heights' */ + { + FT_Fixed max_scale; + FT_Short max_height = 1; + + + max_height = psh_calc_max_height( priv->num_blue_values, + priv->blue_values, + max_height ); + max_height = psh_calc_max_height( priv->num_other_blues, + priv->other_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_blues, + priv->family_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_other_blues, + priv->family_other_blues, + max_height ); + + /* BlueScale is scaled 1000 times */ + max_scale = FT_DivFix( 1000, max_height ); + globals->blues.blue_scale = priv->blue_scale < max_scale + ? priv->blue_scale + : max_scale; + } + + globals->blues.blue_shift = priv->blue_shift; + globals->blues.blue_fuzz = priv->blue_fuzz; + + globals->dimension[0].scale_mult = 0; + globals->dimension[0].scale_delta = 0; + globals->dimension[1].scale_mult = 0; + globals->dimension[1].scale_delta = 0; + +#ifdef DEBUG_HINTER + ps_debug_globals = globals; +#endif + } + + *aglobals = globals; + return error; + } + + + FT_LOCAL_DEF( void ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ) + { + PSH_Dimension dim; + + + dim = &globals->dimension[0]; + if ( x_scale != dim->scale_mult || + x_delta != dim->scale_delta ) + { + dim->scale_mult = x_scale; + dim->scale_delta = x_delta; + + psh_globals_scale_widths( globals, 0 ); + } + + dim = &globals->dimension[1]; + if ( y_scale != dim->scale_mult || + y_delta != dim->scale_delta ) + { + dim->scale_mult = y_scale; + dim->scale_delta = y_delta; + + psh_globals_scale_widths( globals, 1 ); + psh_blues_scale_zones( &globals->blues, y_scale, y_delta ); + } + } + + + FT_LOCAL_DEF( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ) + { + funcs->create = psh_globals_new; + funcs->set_scale = psh_globals_set_scale; + funcs->destroy = psh_globals_destroy; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshglob.h b/Dependencies/freetype/freetype/src/pshinter/pshglob.h new file mode 100644 index 00000000..c5a5c913 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshglob.h @@ -0,0 +1,196 @@ +/**************************************************************************** + * + * pshglob.h + * + * PostScript hinter global hinting management. + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHGLOB_H_ +#define PSHGLOB_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLOBAL HINTS INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @constant: + * PS_GLOBALS_MAX_BLUE_ZONES + * + * @description: + * The maximum number of blue zones in a font global hints structure. + * See @PS_Globals_BluesRec. + */ +#define PS_GLOBALS_MAX_BLUE_ZONES 16 + + + /************************************************************************** + * + * @constant: + * PS_GLOBALS_MAX_STD_WIDTHS + * + * @description: + * The maximum number of standard and snap widths in either the + * horizontal or vertical direction. See @PS_Globals_WidthsRec. + */ +#define PS_GLOBALS_MAX_STD_WIDTHS 16 + + + /* standard and snap width */ + typedef struct PSH_WidthRec_ + { + FT_Int org; + FT_Pos cur; + FT_Pos fit; + + } PSH_WidthRec, *PSH_Width; + + + /* standard and snap widths table */ + typedef struct PSH_WidthsRec_ + { + FT_UInt count; + PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS]; + + } PSH_WidthsRec, *PSH_Widths; + + + typedef struct PSH_DimensionRec_ + { + PSH_WidthsRec stdw; + FT_Fixed scale_mult; + FT_Fixed scale_delta; + + } PSH_DimensionRec, *PSH_Dimension; + + + /* blue zone descriptor */ + typedef struct PSH_Blue_ZoneRec_ + { + FT_Int org_ref; + FT_Int org_delta; + FT_Int org_top; + FT_Int org_bottom; + + FT_Pos cur_ref; + FT_Pos cur_delta; + FT_Pos cur_bottom; + FT_Pos cur_top; + + } PSH_Blue_ZoneRec, *PSH_Blue_Zone; + + + typedef struct PSH_Blue_TableRec_ + { + FT_UInt count; + PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES]; + + } PSH_Blue_TableRec, *PSH_Blue_Table; + + + /* blue zones table */ + typedef struct PSH_BluesRec_ + { + PSH_Blue_TableRec normal_top; + PSH_Blue_TableRec normal_bottom; + PSH_Blue_TableRec family_top; + PSH_Blue_TableRec family_bottom; + + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_threshold; + FT_Int blue_fuzz; + FT_Bool no_overshoots; + + } PSH_BluesRec, *PSH_Blues; + + + /* font globals. */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PSH_GlobalsRec_ + { + FT_Memory memory; + PSH_DimensionRec dimension[2]; + PSH_BluesRec blues; + + } PSH_GlobalsRec; + + +#define PSH_BLUE_ALIGN_NONE 0 +#define PSH_BLUE_ALIGN_TOP 1 +#define PSH_BLUE_ALIGN_BOT 2 + + + typedef struct PSH_AlignmentRec_ + { + int align; + FT_Pos align_top; + FT_Pos align_bot; + + } PSH_AlignmentRec, *PSH_Alignment; + + + FT_LOCAL( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ); + + +#if 0 + /* snap a stem width to fitter coordinates. `org_width' is in font */ + /* units. The result is in device pixels (26.6 format). */ + FT_LOCAL( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ); +#endif + + FT_LOCAL( void ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + + /* snap a stem to one or two blue zones */ + FT_LOCAL( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ); + /* */ + +#ifdef DEBUG_HINTER + extern PSH_Globals ps_debug_globals; +#endif + + +FT_END_HEADER + + +#endif /* PSHGLOB_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshinter.c b/Dependencies/freetype/freetype/src/pshinter/pshinter.c new file mode 100644 index 00000000..ae2b53fe --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshinter.c @@ -0,0 +1,27 @@ +/**************************************************************************** + * + * pshinter.c + * + * FreeType PostScript Hinting module + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pshalgo.c" +#include "pshglob.c" +#include "pshmod.c" +#include "pshrec.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshmod.c b/Dependencies/freetype/freetype/src/pshinter/pshmod.c new file mode 100644 index 00000000..9965d5b1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshmod.c @@ -0,0 +1,125 @@ +/**************************************************************************** + * + * pshmod.c + * + * FreeType PostScript hinter module implementation (body). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include "pshrec.h" +#include "pshalgo.h" +#include "pshmod.h" + + + /* the Postscript Hinter module structure */ + typedef struct PS_Hinter_Module_Rec_ + { + FT_ModuleRec root; + PS_HintsRec ps_hints; + + PSH_Globals_FuncsRec globals_funcs; + T1_Hints_FuncsRec t1_funcs; + T2_Hints_FuncsRec t2_funcs; + + } PS_Hinter_ModuleRec, *PS_Hinter_Module; + + + /* finalize module */ + FT_CALLBACK_DEF( void ) + ps_hinter_done( FT_Module module_ ) /* PS_Hinter_Module */ + { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + + + module->t1_funcs.hints = NULL; + module->t2_funcs.hints = NULL; + + ps_hints_done( &module->ps_hints ); + } + + + /* initialize module, create hints recorder and the interface */ + FT_CALLBACK_DEF( FT_Error ) + ps_hinter_init( FT_Module module_ ) /* PS_Hinter_Module */ + { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + + FT_Memory memory = module->root.memory; + void* ph = &module->ps_hints; + + + ps_hints_init( &module->ps_hints, memory ); + + psh_globals_funcs_init( &module->globals_funcs ); + + t1_hints_funcs_init( &module->t1_funcs ); + module->t1_funcs.hints = (T1_Hints)ph; + + t2_hints_funcs_init( &module->t2_funcs ); + module->t2_funcs.hints = (T2_Hints)ph; + + return 0; + } + + + /* returns global hints interface */ + FT_CALLBACK_DEF( PSH_Globals_Funcs ) + pshinter_get_globals_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->globals_funcs; + } + + + /* return Type 1 hints interface */ + FT_CALLBACK_DEF( T1_Hints_Funcs ) + pshinter_get_t1_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t1_funcs; + } + + + /* return Type 2 hints interface */ + FT_CALLBACK_DEF( T2_Hints_Funcs ) + pshinter_get_t2_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t2_funcs; + } + + + FT_DEFINE_PSHINTER_INTERFACE( + pshinter_interface, + + pshinter_get_globals_funcs, + pshinter_get_t1_funcs, + pshinter_get_t2_funcs + ) + + + FT_DEFINE_MODULE( + pshinter_module_class, + + 0, + sizeof ( PS_Hinter_ModuleRec ), + "pshinter", + 0x10000L, + 0x20000L, + + &pshinter_interface, /* module-specific interface */ + + (FT_Module_Constructor)ps_hinter_init, /* module_init */ + (FT_Module_Destructor) ps_hinter_done, /* module_done */ + (FT_Module_Requester) NULL /* get_interface */ + ) + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshmod.h b/Dependencies/freetype/freetype/src/pshinter/pshmod.h new file mode 100644 index 00000000..62ac0a60 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshmod.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * pshmod.h + * + * PostScript hinter module interface (specification). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSHMOD_H_ +#define PSHMOD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_MODULE( pshinter_module_class ) + + +FT_END_HEADER + + +#endif /* PSHMOD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshnterr.h b/Dependencies/freetype/freetype/src/pshinter/pshnterr.h new file mode 100644 index 00000000..e9641340 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshnterr.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * pshnterr.h + * + * PS Hinter error codes (specification only). + * + * Copyright (C) 2003-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PSHinter error enumeration constants. + * + */ + +#ifndef PSHNTERR_H_ +#define PSHNTERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSH_Err_ +#define FT_ERR_BASE FT_Mod_Err_PShinter + +#include + +#endif /* PSHNTERR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshrec.c b/Dependencies/freetype/freetype/src/pshinter/pshrec.c new file mode 100644 index 00000000..0b2b549f --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshrec.c @@ -0,0 +1,1224 @@ +/**************************************************************************** + * + * pshrec.c + * + * FreeType PostScript hints recorder (body). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "pshrec.h" +#include "pshalgo.h" + +#include "pshnterr.h" + +#undef FT_COMPONENT +#define FT_COMPONENT pshrec + +#ifdef DEBUG_HINTER + PS_Hints ps_debug_hints = NULL; + int ps_debug_no_horz_hints = 0; + int ps_debug_no_vert_hints = 0; +#endif + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_HINT MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy hints table */ + static void + ps_hint_table_done( PS_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + } + + + /* ensure that a table can contain "count" elements */ + static FT_Error + ps_hint_table_ensure( PS_Hint_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_hints; + FT_UInt new_max = count; + FT_Error error; + + + /* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_QRENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + + return error; + } + + + static FT_Error + ps_hint_table_alloc( PS_Hint_Table table, + FT_Memory memory, + PS_Hint *ahint ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + PS_Hint hint = NULL; + + + count = table->num_hints; + count++; + + if ( count > table->max_hints ) + { + error = ps_hint_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + hint = table->hints + count - 1; /* initialized upstream */ + + table->num_hints = count; + + Exit: + *ahint = hint; + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_MASK MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* destroy mask */ + static void + ps_mask_done( PS_Mask mask, + FT_Memory memory ) + { + FT_FREE( mask->bytes ); + mask->num_bits = 0; + mask->max_bits = 0; + mask->end_point = 0; + } + + + /* ensure that a mask can contain "count" bits */ + static FT_Error + ps_mask_ensure( PS_Mask mask, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = mask->max_bits >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + /* added bytes are zeroed here */ + if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) + mask->max_bits = new_max * 8; + } + return error; + } + + + /* test a bit value in a given mask */ + static FT_Int + ps_mask_test_bit( PS_Mask mask, + FT_UInt idx ) + { + if ( idx >= mask->num_bits ) + return 0; + + return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); + } + + + /* set a given bit, possibly grow the mask */ + static FT_Error + ps_mask_set_bit( PS_Mask mask, + FT_UInt idx, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* p; + + + if ( idx >= mask->num_bits ) + { + error = ps_mask_ensure( mask, idx + 1, memory ); + if ( error ) + goto Exit; + + mask->num_bits = idx + 1; + } + + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); + + Exit: + return error; + } + + + /* destroy mask table */ + static void + ps_mask_table_done( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt count = table->max_masks; + PS_Mask mask = table->masks; + + + for ( ; count > 0; count--, mask++ ) + ps_mask_done( mask, memory ); + + FT_FREE( table->masks ); + table->num_masks = 0; + table->max_masks = 0; + } + + + /* ensure that a mask table can contain "count" masks */ + static FT_Error + ps_mask_table_ensure( PS_Mask_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_masks; + FT_UInt new_max = count; + FT_Error error = FT_Err_Ok; + + + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) + table->max_masks = new_max; + } + return error; + } + + + /* allocate a new mask in a table */ + static FT_Error + ps_mask_table_alloc( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_UInt count; + FT_Error error = FT_Err_Ok; + PS_Mask mask = NULL; + + + count = table->num_masks; + count++; + + if ( count > table->max_masks ) + { + error = ps_mask_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + + mask = table->masks + count - 1; + mask->num_bits = 0; + mask->end_point = 0; + /* reused mask must be cleared */ + if ( mask->max_bits ) + FT_MEM_ZERO( mask->bytes, mask->max_bits >> 3 ); + + table->num_masks = count; + + Exit: + *amask = mask; + return error; + } + + + /* return last hint mask in a table, create one if the table is empty */ + static FT_Error + ps_mask_table_last( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count; + PS_Mask mask; + + + count = table->num_masks; + if ( count == 0 ) + { + error = ps_mask_table_alloc( table, memory, &mask ); + if ( error ) + goto Exit; + } + else + mask = table->masks + count - 1; + + Exit: + *amask = mask; + return error; + } + + + /* set a new mask to a given bit range */ + static FT_Error + ps_mask_table_set_bits( PS_Mask_Table table, + const FT_Byte* source, + FT_UInt bit_pos, + FT_UInt bit_count, + FT_Memory memory ) + { + FT_Error error; + PS_Mask mask; + + + error = ps_mask_table_last( table, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_ensure( mask, bit_count, memory ); + if ( error ) + goto Exit; + + mask->num_bits = bit_count; + + /* now, copy bits */ + { + FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); + FT_Int rmask = 0x80 >> ( bit_pos & 7 ); + FT_Byte* write = mask->bytes; + FT_Int wmask = 0x80; + FT_Int val; + + + for ( ; bit_count > 0; bit_count-- ) + { + val = write[0] & ~wmask; + + if ( read[0] & rmask ) + val |= wmask; + + write[0] = (FT_Byte)val; + + rmask >>= 1; + if ( rmask == 0 ) + { + read++; + rmask = 0x80; + } + + wmask >>= 1; + if ( wmask == 0 ) + { + write++; + wmask = 0x80; + } + } + } + + Exit: + return error; + } + + + /* test whether two masks in a table intersect */ + static FT_Int + ps_mask_table_test_intersect( PS_Mask_Table table, + FT_UInt index1, + FT_UInt index2 ) + { + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_Byte* p1 = mask1->bytes; + FT_Byte* p2 = mask2->bytes; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt count; + + + count = FT_MIN( count1, count2 ); + for ( ; count >= 8; count -= 8 ) + { + if ( p1[0] & p2[0] ) + return 1; + + p1++; + p2++; + } + + if ( count == 0 ) + return 0; + + return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); + } + + + /* merge two masks, used by ps_mask_table_merge_all */ + static FT_Error + ps_mask_table_merge( PS_Mask_Table table, + FT_UInt index1, + FT_UInt index2, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + + + /* swap index1 and index2 so that index1 < index2 */ + if ( index1 > index2 ) + { + FT_UInt temp; + + + temp = index1; + index1 = index2; + index2 = temp; + } + + if ( index1 < index2 && index2 < table->num_masks ) + { + /* we need to merge the bitsets of index1 and index2 with a */ + /* simple union */ + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt delta; + + + if ( count2 > 0 ) + { + FT_UInt pos; + FT_Byte* read; + FT_Byte* write; + + + /* if "count2" is greater than "count1", we need to grow the */ + /* first bitset */ + if ( count2 > count1 ) + { + error = ps_mask_ensure( mask1, count2, memory ); + if ( error ) + goto Exit; + + mask1->num_bits = count2; + } + + /* merge (unite) the bitsets */ + read = mask2->bytes; + write = mask1->bytes; + pos = ( count2 + 7 ) >> 3; + + for ( ; pos > 0; pos-- ) + { + write[0] = (FT_Byte)( write[0] | read[0] ); + write++; + read++; + } + } + + /* Now, remove "mask2" from the list. We need to keep the masks */ + /* sorted in order of importance, so move table elements. */ + mask2->num_bits = 0; + mask2->end_point = 0; + + /* number of masks to move */ + delta = table->num_masks - 1 - index2; + if ( delta > 0 ) + { + /* move to end of table for reuse */ + PS_MaskRec dummy = *mask2; + + + ft_memmove( mask2, + mask2 + 1, + delta * sizeof ( PS_MaskRec ) ); + + mask2[delta] = dummy; + } + + table->num_masks--; + } + else + FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + index1, index2 )); + + Exit: + return error; + } + + + /* Try to merge all masks in a given table. This is used to merge */ + /* all counter masks into independent counter "paths". */ + /* */ + static FT_Error + ps_mask_table_merge_all( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt index1, index2; + FT_Error error = FT_Err_Ok; + + + /* the loops stop when unsigned indices wrap around after 0 */ + for ( index1 = table->num_masks - 1; index1 < table->num_masks; index1-- ) + { + for ( index2 = index1 - 1; index2 < index1; index2-- ) + { + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) + { + error = ps_mask_table_merge( table, index2, index1, memory ); + if ( error ) + goto Exit; + + break; + } + } + } + + Exit: + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_DIMENSION MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* finalize a given dimension */ + static void + ps_dimension_done( PS_Dimension dimension, + FT_Memory memory ) + { + ps_mask_table_done( &dimension->counters, memory ); + ps_mask_table_done( &dimension->masks, memory ); + ps_hint_table_done( &dimension->hints, memory ); + } + + + /* initialize a given dimension */ + static void + ps_dimension_init( PS_Dimension dimension ) + { + dimension->hints.num_hints = 0; + dimension->masks.num_masks = 0; + dimension->counters.num_masks = 0; + } + + +#if 0 + + /* set a bit at a given index in the current hint mask */ + static FT_Error + ps_dimension_set_mask_bit( PS_Dimension dim, + FT_UInt idx, + FT_Memory memory ) + { + PS_Mask mask; + FT_Error error = FT_Err_Ok; + + + /* get last hint mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + + Exit: + return error; + } + +#endif + + /* set the end point in a mask, called from "End" & "Reset" methods */ + static void + ps_dimension_end_mask( PS_Dimension dim, + FT_UInt end_point ) + { + FT_UInt count = dim->masks.num_masks; + + + if ( count > 0 ) + { + PS_Mask mask = dim->masks.masks + count - 1; + + + mask->end_point = end_point; + } + } + + + /* set the end point in the current mask, then create a new empty one */ + /* (called by "Reset" method) */ + static FT_Error + ps_dimension_reset_mask( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + PS_Mask mask; + + + /* end current mask */ + ps_dimension_end_mask( dim, end_point ); + + /* allocate new one */ + return ps_mask_table_alloc( &dim->masks, memory, &mask ); + } + + + /* set a new mask, called from the "T2Stem" method */ + static FT_Error + ps_dimension_set_mask_bits( PS_Dimension dim, + const FT_Byte* source, + FT_UInt source_pos, + FT_UInt source_bits, + FT_UInt end_point, + FT_Memory memory ) + { + FT_Error error; + + + /* reset current mask, if any */ + error = ps_dimension_reset_mask( dim, end_point, memory ); + if ( error ) + goto Exit; + + /* set bits in new mask */ + error = ps_mask_table_set_bits( &dim->masks, source, + source_pos, source_bits, memory ); + + Exit: + return error; + } + + + /* add a new single stem (called from "T1Stem" method) */ + static FT_Error + ps_dimension_add_t1stem( PS_Dimension dim, + FT_Int pos, + FT_Int len, + FT_Memory memory, + FT_UInt *aindex ) + { + FT_Error error = FT_Err_Ok; + FT_UInt flags = 0; + + + /* detect ghost stem */ + if ( len < 0 ) + { + flags |= PS_HINT_FLAG_GHOST; + if ( len == -21 ) + { + flags |= PS_HINT_FLAG_BOTTOM; + pos = ADD_INT( pos, len ); + } + len = 0; + } + + /* now, lookup stem in the current hints table */ + { + PS_Mask mask; + FT_UInt idx; + FT_UInt max = dim->hints.num_hints; + PS_Hint hint = dim->hints.hints; + + + for ( idx = 0; idx < max; idx++, hint++ ) + { + if ( hint->pos == pos && hint->len == len ) + break; + } + + /* we need to create a new hint in the table */ + if ( idx >= max ) + { + error = ps_hint_table_alloc( &dim->hints, memory, &hint ); + if ( error ) + goto Exit; + + hint->pos = pos; + hint->len = len; + hint->flags = flags; + } + + /* now, store the hint in the current mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( mask, idx, memory ); + if ( error ) + goto Exit; + + if ( aindex ) + *aindex = idx; + } + + Exit: + return error; + } + + + /* add a "hstem3/vstem3" counter to our dimension table */ + static FT_Error + ps_dimension_add_counter( PS_Dimension dim, + FT_UInt hint1, + FT_UInt hint2, + FT_UInt hint3, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_UInt count = dim->counters.num_masks; + PS_Mask counter = dim->counters.masks; + + + /* try to find an existing counter mask that already uses */ + /* one of these stems here */ + for ( ; count > 0; count--, counter++ ) + { + if ( ps_mask_test_bit( counter, hint1 ) || + ps_mask_test_bit( counter, hint2 ) || + ps_mask_test_bit( counter, hint3 ) ) + break; + } + + /* create a new counter when needed */ + if ( count == 0 ) + { + error = ps_mask_table_alloc( &dim->counters, memory, &counter ); + if ( error ) + goto Exit; + } + + /* now, set the bits for our hints in the counter mask */ + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; + + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; + + Exit: + return error; + } + + + /* end of recording session for a given dimension */ + static FT_Error + ps_dimension_end( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + /* end hint mask table */ + ps_dimension_end_mask( dim, end_point ); + + /* merge all counter masks into independent "paths" */ + return ps_mask_table_merge_all( &dim->counters, memory ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** PS_RECORDER MANAGEMENT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* destroy hints */ + FT_LOCAL_DEF( void ) + ps_hints_done( PS_Hints hints ) + { + FT_Memory memory = hints->memory; + + + ps_dimension_done( &hints->dimension[0], memory ); + ps_dimension_done( &hints->dimension[1], memory ); + + hints->error = FT_Err_Ok; + hints->memory = NULL; + } + + + FT_LOCAL_DEF( void ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ) + { + FT_ZERO( hints ); + hints->memory = memory; + } + + + /* initialize a hints for a new session */ + static void + ps_hints_open( PS_Hints hints, + PS_Hint_Type hint_type ) + { + hints->error = FT_Err_Ok; + hints->hint_type = hint_type; + + ps_dimension_init( &hints->dimension[0] ); + ps_dimension_init( &hints->dimension[1] ); + } + + + /* add one or more stems to the current hints table */ + static void + ps_hints_stem( PS_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Pos* stems ) + { + PS_Dimension dim; + + + if ( hints->error ) + return; + + /* limit "dimension" to 0..1 */ + if ( dimension > 1 ) + { + FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + /* record the stems in the current hints/masks table */ + /* (Type 1 & 2's `hstem' or `vstem' operators) */ + dim = &hints->dimension[dimension]; + + for ( ; count > 0; count--, stems += 2 ) + { + FT_Error error; + FT_Memory memory = hints->memory; + + + error = ps_dimension_add_t1stem( dim, + (FT_Int)stems[0], + (FT_Int)stems[1], + memory, + NULL ); + if ( error ) + { + FT_ERROR(( "ps_hints_stem: could not add stem" + " (%ld,%ld) to hints table\n", stems[0], stems[1] )); + + hints->error = error; + return; + } + } + } + + + /* add one Type1 counter stem to the current hints table */ + static void + ps_hints_t1stem3( T1_Hints hints_, /* PS_Hints */ + FT_UInt dimension, + FT_Fixed* stems ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error = FT_Err_Ok; + + + if ( !hints->error ) + { + PS_Dimension dim; + FT_Memory memory = hints->memory; + FT_Int count; + FT_UInt idx[3]; + + + /* limit "dimension" to 0..1 */ + if ( dimension > 1 ) + { + FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + + dim = &hints->dimension[dimension]; + + /* there must be 6 elements in the 'stem' array */ + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + /* add the three stems to our hints/masks table */ + for ( count = 0; count < 3; count++, stems += 2 ) + { + error = ps_dimension_add_t1stem( dim, + (FT_Int)FIXED_TO_INT( stems[0] ), + (FT_Int)FIXED_TO_INT( stems[1] ), + memory, &idx[count] ); + if ( error ) + goto Fail; + } + + /* now, add the hints to the counters table */ + error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], + memory ); + if ( error ) + goto Fail; + } + else + { + FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + } + + return; + + Fail: + FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); + hints->error = error; + } + + + /* reset hints (only with Type 1 hints) */ + static void + ps_hints_t1reset( T1_Hints hints_, /* PS_Hints */ + FT_UInt end_point ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error = FT_Err_Ok; + + + if ( !hints->error ) + { + FT_Memory memory = hints->memory; + + + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + error = ps_dimension_reset_mask( &hints->dimension[0], + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_reset_mask( &hints->dimension[1], + end_point, memory ); + if ( error ) + goto Fail; + } + else + { + /* invalid hint type */ + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + } + return; + + Fail: + hints->error = error; + } + + + /* Type2 "hintmask" operator, add a new hintmask to each direction */ + static void + ps_hints_t2mask( T2_Hints hints_, /* PS_Hints */ + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count; must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2mask:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, + end_point, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, + end_point, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + static void + ps_hints_t2counter( T2_Hints hints_, /* PS_Hints */ + FT_UInt bit_count, + const FT_Byte* bytes ) + { + PS_Hints hints = (PS_Hints)hints_; + FT_Error error; + + + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; + + + /* check bit count, must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2counter:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); + + /* simply ignore the operator */ + return; + } + + /* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, + 0, memory ); + if ( error ) + goto Fail; + + error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, + 0, memory ); + if ( error ) + goto Fail; + } + return; + + Fail: + hints->error = error; + } + + + /* end recording session */ + static FT_Error + ps_hints_close( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error; + + + error = hints->error; + if ( !error ) + { + FT_Memory memory = hints->memory; + PS_Dimension dim = hints->dimension; + + + error = ps_dimension_end( &dim[0], end_point, memory ); + if ( !error ) + { + error = ps_dimension_end( &dim[1], end_point, memory ); + } + } + +#ifdef DEBUG_HINTER + if ( !error ) + ps_debug_hints = hints; +#endif + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t1_hints_open( T1_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); + } + + static FT_Error + t1_hints_close( T1_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + + static void + t1_hints_stem( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ) + { + FT_Pos stems[2]; + + + stems[0] = FIXED_TO_INT( coords[0] ); + stems[1] = FIXED_TO_INT( coords[1] ); + + ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); + } + + + static FT_Error + t1_hints_apply( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + + FT_LOCAL_DEF( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) + { + FT_ZERO( funcs ); + + funcs->open = (T1_Hints_OpenFunc) t1_hints_open; + funcs->close = (T1_Hints_CloseFunc) t1_hints_close; + funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; + funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; + funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; + funcs->apply = (T1_Hints_ApplyFunc) t1_hints_apply; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 2 HINTS RECORDING INTERFACE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + t2_hints_open( T2_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); + } + + + static FT_Error + t2_hints_close( T2_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + + + static void + t2_hints_stems( T2_Hints hints, + FT_UInt dimension, + FT_Int count, + FT_Fixed* coords ) + { + FT_Pos stems[32], y; + FT_Int total = count, n; + + + y = 0; + while ( total > 0 ) + { + /* determine number of stems to write */ + count = total; + if ( count > 16 ) + count = 16; + + /* compute integer stem positions in font units */ + for ( n = 0; n < count * 2; n++ ) + { + y = ADD_LONG( y, coords[n] ); + stems[n] = FIXED_TO_INT( y ); + } + + /* compute lengths */ + for ( n = 0; n < count * 2; n += 2 ) + stems[n + 1] = stems[n + 1] - stems[n]; + + /* add them to the current dimension */ + ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); + + total -= count; + } + } + + + static FT_Error + t2_hints_apply( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + + FT_LOCAL_DEF( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) + { + FT_ZERO( funcs ); + + funcs->open = (T2_Hints_OpenFunc) t2_hints_open; + funcs->close = (T2_Hints_CloseFunc) t2_hints_close; + funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; + funcs->hintmask = (T2_Hints_MaskFunc) ps_hints_t2mask; + funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; + funcs->apply = (T2_Hints_ApplyFunc) t2_hints_apply; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/pshinter/pshrec.h b/Dependencies/freetype/freetype/src/pshinter/pshrec.h new file mode 100644 index 00000000..7e375af7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/pshinter/pshrec.h @@ -0,0 +1,171 @@ +/**************************************************************************** + * + * pshrec.h + * + * Postscript (Type1/Type2) hints recorder (specification). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /*************************************************************************** + * + * The functions defined here are called from the Type 1, CID and CFF + * font drivers to record the hints of a given character/glyph. + * + * The hints are recorded in a unified format, and are later processed + * by the `optimizer' and `fitter' to adjust the outlines to the pixel + * grid. + * + */ + + +#ifndef PSHREC_H_ +#define PSHREC_H_ + + +#include +#include "pshglob.h" + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GLYPH HINTS RECORDER INTERNALS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to hint record */ + typedef struct PS_HintRec_* PS_Hint; + + /* hint types */ + typedef enum PS_Hint_Type_ + { + PS_HINT_TYPE_1 = 1, + PS_HINT_TYPE_2 = 2 + + } PS_Hint_Type; + + + /* hint flags */ +#define PS_HINT_FLAG_GHOST 1U +#define PS_HINT_FLAG_BOTTOM 2U + + + /* hint descriptor */ + typedef struct PS_HintRec_ + { + FT_Int pos; + FT_Int len; + FT_UInt flags; + + } PS_HintRec; + + +#define ps_hint_is_active( x ) ( (x)->flags & PS_HINT_FLAG_ACTIVE ) +#define ps_hint_is_ghost( x ) ( (x)->flags & PS_HINT_FLAG_GHOST ) +#define ps_hint_is_bottom( x ) ( (x)->flags & PS_HINT_FLAG_BOTTOM ) + + + /* hints table descriptor */ + typedef struct PS_Hint_TableRec_ + { + FT_UInt num_hints; + FT_UInt max_hints; + PS_Hint hints; + + } PS_Hint_TableRec, *PS_Hint_Table; + + + /* hint and counter mask descriptor */ + typedef struct PS_MaskRec_ + { + FT_UInt num_bits; + FT_UInt max_bits; + FT_Byte* bytes; + FT_UInt end_point; + + } PS_MaskRec, *PS_Mask; + + + /* masks and counters table descriptor */ + typedef struct PS_Mask_TableRec_ + { + FT_UInt num_masks; + FT_UInt max_masks; + PS_Mask masks; + + } PS_Mask_TableRec, *PS_Mask_Table; + + + /* dimension-specific hints descriptor */ + typedef struct PS_DimensionRec_ + { + PS_Hint_TableRec hints; + PS_Mask_TableRec masks; + PS_Mask_TableRec counters; + + } PS_DimensionRec, *PS_Dimension; + + + /* glyph hints descriptor */ + /* dimension 0 => X coordinates + vertical hints/stems */ + /* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PS_HintsRec_ + { + FT_Memory memory; + FT_Error error; + FT_UInt32 magic; + PS_Hint_Type hint_type; + PS_DimensionRec dimension[2]; + + } PS_HintsRec, *PS_Hints; + + /* */ + + /* initialize hints recorder */ + FT_LOCAL( void ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ); + + /* finalize hints recorder */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ); + + /* initialize Type1 hints recorder interface */ + FT_LOCAL( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ); + + /* initialize Type2 hints recorder interface */ + FT_LOCAL( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ); + + +#ifdef DEBUG_HINTER + extern PS_Hints ps_debug_hints; + extern int ps_debug_no_horz_hints; + extern int ps_debug_no_vert_hints; +#endif + + /* */ + + +FT_END_HEADER + + +#endif /* PSHREC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psnames/psmodule.c b/Dependencies/freetype/freetype/src/psnames/psmodule.c new file mode 100644 index 00000000..35d054d1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psnames/psmodule.c @@ -0,0 +1,621 @@ +/**************************************************************************** + * + * psmodule.c + * + * psnames module implementation (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#include "psmodule.h" + + /* + * The file `pstables.h' with its arrays and its function + * `ft_get_adobe_glyph_index' is useful for other projects also (for + * example, `pdfium' is using it). However, if used as a C++ header, + * including it in two different source files makes it necessary to use + * `extern const' for the declaration of its arrays, otherwise the data + * would be duplicated as mandated by the C++ standard. + * + * For this reason, we use `DEFINE_PS_TABLES' to guard the function + * definitions, and `DEFINE_PS_TABLES_DATA' to provide both proper array + * declarations and definitions. + */ +#include "pstables.h" +#define DEFINE_PS_TABLES +#define DEFINE_PS_TABLES_DATA +#include "pstables.h" + +#include "psnamerr.h" + + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + +#define VARIANT_BIT 0x80000000UL +#define BASE_GLYPH( code ) ( (FT_UInt32)( (code) & ~VARIANT_BIT ) ) + + + /* Return the Unicode value corresponding to a given glyph. Note that */ + /* we do deal with glyph variants by detecting a non-initial dot in */ + /* the name, as in `A.swash' or `e.final'; in this case, the */ + /* VARIANT_BIT is set in the return value. */ + /* */ + FT_CALLBACK_DEF( FT_UInt32 ) + ps_unicode_value( const char* glyph_name ) + { + /* If the name begins with `uni', then the glyph name may be a */ + /* hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' && + glyph_name[1] == 'n' && + glyph_name[2] == 'i' ) + { + /* determine whether the next four characters following are */ + /* hexadecimal. */ + + /* XXX: Add code to deal with ligatures, i.e. glyph names like */ + /* `uniXXXXYYYYZZZZ'... */ + + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 3; + + + for ( count = 4; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + /* Exit if a non-uppercase hexadecimal character was found */ + /* -- this also catches character codes below `0' since such */ + /* negative numbers cast to `unsigned int' are far too big. */ + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + /* there must be exactly four hex digits */ + if ( count == 0 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } + + /* If the name begins with `u', followed by four to six uppercase */ + /* hexadecimal digits, it is a hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' ) + { + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 1; + + + for ( count = 6; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + + + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + + if ( d >= 16 ) + break; + + value = ( value << 4 ) + d; + } + + if ( count <= 2 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } + + /* Look for a non-initial dot in the glyph name in order to */ + /* find variants like `A.swash', `e.final', etc. */ + { + FT_UInt32 value = 0; + const char* p = glyph_name; + + + for ( ; *p && *p != '.'; p++ ) + ; + + /* now look up the glyph in the Adobe Glyph List; */ + /* `.notdef', `.null' and the empty name are short cut */ + if ( p > glyph_name ) + { + value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); + + if ( *p == '.' ) + value |= (FT_UInt32)VARIANT_BIT; + } + + return value; + } + } + + + /* ft_qsort callback to sort the unicode map */ + FT_COMPARE_DEF( int ) + compare_uni_maps( const void* a, + const void* b ) + { + PS_UniMap* map1 = (PS_UniMap*)a; + PS_UniMap* map2 = (PS_UniMap*)b; + FT_UInt32 unicode1 = BASE_GLYPH( map1->unicode ); + FT_UInt32 unicode2 = BASE_GLYPH( map2->unicode ); + + + /* sort base glyphs before glyph variants */ + if ( unicode1 == unicode2 ) + { + if ( map1->unicode > map2->unicode ) + return 1; + else if ( map1->unicode < map2->unicode ) + return -1; + else + return 0; + } + else + { + if ( unicode1 > unicode2 ) + return 1; + else if ( unicode1 < unicode2 ) + return -1; + else + return 0; + } + } + + + /* support for extra glyphs not handled (well) in AGL; */ + /* we add extra mappings for them if necessary */ + +#define EXTRA_GLYPH_LIST_SIZE 10 + + static const FT_UInt32 ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] = + { + /* WGL 4 */ + 0x0394, + 0x03A9, + 0x2215, + 0x00AD, + 0x02C9, + 0x03BC, + 0x2219, + 0x00A0, + /* Romanian */ + 0x021A, + 0x021B + }; + + static const char ft_extra_glyph_names[] = + { + 'D','e','l','t','a',0, + 'O','m','e','g','a',0, + 'f','r','a','c','t','i','o','n',0, + 'h','y','p','h','e','n',0, + 'm','a','c','r','o','n',0, + 'm','u',0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0, + 's','p','a','c','e',0, + 'T','c','o','m','m','a','a','c','c','e','n','t',0, + 't','c','o','m','m','a','a','c','c','e','n','t',0 + }; + + static const FT_Int + ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] = + { + 0, + 6, + 12, + 21, + 28, + 35, + 38, + 53, + 59, + 72 + }; + + + static void + ps_check_extra_glyph_name( const char* gname, + FT_UInt glyph, + FT_UInt* extra_glyphs, + FT_UInt *states ) + { + FT_UInt n; + + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( ft_strcmp( ft_extra_glyph_names + + ft_extra_glyph_name_offsets[n], gname ) == 0 ) + { + if ( states[n] == 0 ) + { + /* mark this extra glyph as a candidate for the cmap */ + states[n] = 1; + extra_glyphs[n] = glyph; + } + + return; + } + } + } + + + static void + ps_check_extra_glyph_unicode( FT_UInt32 uni_char, + FT_UInt *states ) + { + FT_UInt n; + + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( uni_char == ft_extra_glyph_unicodes[n] ) + { + /* disable this extra glyph from being added to the cmap */ + states[n] = 2; + + return; + } + } + } + + + /* Build a table that maps Unicode values to glyph indices. */ + FT_CALLBACK_DEF( FT_Error ) + ps_unicodes_init( FT_Memory memory, + PS_Unicodes table, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ) + { + FT_Error error; + + FT_UInt extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + FT_UInt extra_glyphs[EXTRA_GLYPH_LIST_SIZE]; + + + /* we first allocate the table */ + table->num_maps = 0; + + if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) + { + FT_UInt n; + FT_UInt count; + PS_UniMap* map; + FT_UInt32 uni_char; + + + map = table->maps; + + for ( n = 0; n < num_glyphs; n++ ) + { + const char* gname = get_glyph_name( glyph_data, n ); + + + if ( gname && *gname ) + { + ps_check_extra_glyph_name( gname, n, + extra_glyphs, extra_glyph_list_states ); + uni_char = ps_unicode_value( gname ); + + if ( BASE_GLYPH( uni_char ) != 0 ) + { + ps_check_extra_glyph_unicode( uni_char, + extra_glyph_list_states ); + map->unicode = uni_char; + map->glyph_index = n; + map++; + } + + if ( free_glyph_name ) + free_glyph_name( glyph_data, gname ); + } + } + + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( extra_glyph_list_states[n] == 1 ) + { + /* This glyph name has an additional representation. */ + /* Add it to the cmap. */ + + map->unicode = ft_extra_glyph_unicodes[n]; + map->glyph_index = extra_glyphs[n]; + map++; + } + } + + /* now compress the table a bit */ + count = (FT_UInt)( map - table->maps ); + + if ( count == 0 ) + { + /* No unicode chars here! */ + FT_FREE( table->maps ); + if ( !error ) + error = FT_THROW( No_Unicode_Glyph_Name ); + } + else + { + /* Reallocate if the number of used entries is much smaller. */ + if ( count < num_glyphs / 2 ) + { + FT_MEM_QRENEW_ARRAY( table->maps, + num_glyphs + EXTRA_GLYPH_LIST_SIZE, + count ); + error = FT_Err_Ok; + } + + /* Sort the table in increasing order of unicode values, */ + /* taking care of glyph variants. */ + ft_qsort( table->maps, count, sizeof ( PS_UniMap ), + compare_uni_maps ); + } + + table->num_maps = count; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ps_unicodes_char_index( PS_Unicodes table, + FT_UInt32 unicode ) + { + PS_UniMap *result = NULL; + PS_UniMap *min = table->maps; + PS_UniMap *max = min + table->num_maps; + PS_UniMap *mid = min + ( ( max - min ) >> 1 ); + + + /* Perform a binary search on the table. */ + while ( min < max ) + { + FT_UInt32 base_glyph; + + + if ( mid->unicode == unicode ) + { + result = mid; + break; + } + + base_glyph = BASE_GLYPH( mid->unicode ); + + if ( base_glyph == unicode ) + result = mid; /* remember match but continue search for base glyph */ + + if ( base_glyph < unicode ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += unicode - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( ( max - min ) >> 1 ); + } + + if ( result ) + return result->glyph_index; + else + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + ps_unicodes_char_next( PS_Unicodes table, + FT_UInt32 *unicode ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *unicode + 1; + + + { + FT_UInt min = 0; + FT_UInt max = table->num_maps; + FT_UInt mid = min + ( ( max - min ) >> 1 ); + PS_UniMap* map; + FT_UInt32 base_glyph; + + + while ( min < max ) + { + map = table->maps + mid; + + if ( map->unicode == char_code ) + { + result = map->glyph_index; + goto Exit; + } + + base_glyph = BASE_GLYPH( map->unicode ); + + if ( base_glyph == char_code ) + result = map->glyph_index; + + if ( base_glyph < char_code ) + min = mid + 1; + else + max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; + } + + if ( result ) + goto Exit; /* we have a variant glyph */ + + /* we didn't find it; check whether we have a map just above it */ + char_code = 0; + + if ( min < table->num_maps ) + { + map = table->maps + min; + result = map->glyph_index; + char_code = BASE_GLYPH( map->unicode ); + } + } + + Exit: + *unicode = char_code; + return result; + } + + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + FT_CALLBACK_DEF( const char* ) + ps_get_macintosh_name( FT_UInt name_index ) + { + if ( name_index >= FT_NUM_MAC_NAMES ) + name_index = 0; + + return ft_standard_glyph_names + ft_mac_names[name_index]; + } + + + FT_CALLBACK_DEF( const char* ) + ps_get_standard_strings( FT_UInt sid ) + { + if ( sid >= FT_NUM_SID_NAMES ) + return 0; + + return ft_standard_glyph_names + ft_sid_names[sid]; + } + + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + + FT_DEFINE_SERVICE_PSCMAPSREC( + pscmaps_interface, + + ps_unicode_value, /* PS_Unicode_ValueFunc unicode_value */ + ps_unicodes_init, /* PS_Unicodes_InitFunc unicodes_init */ + ps_unicodes_char_index, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + ps_unicodes_char_next, /* PS_Unicodes_CharNextFunc unicodes_char_next */ + + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ + + t1_standard_encoding, /* adobe_std_encoding */ + t1_expert_encoding /* adobe_expert_encoding */ + ) + +#else + + FT_DEFINE_SERVICE_PSCMAPSREC( + pscmaps_interface, + + NULL, /* PS_Unicode_ValueFunc unicode_value */ + NULL, /* PS_Unicodes_InitFunc unicodes_init */ + NULL, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + NULL, /* PS_Unicodes_CharNextFunc unicodes_char_next */ + + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ + + t1_standard_encoding, /* adobe_std_encoding */ + t1_expert_encoding /* adobe_expert_encoding */ + ) + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + + FT_DEFINE_SERVICEDESCREC1( + pscmaps_services, + + FT_SERVICE_ID_POSTSCRIPT_CMAPS, &pscmaps_interface ) + + + static FT_Pointer + psnames_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( pscmaps_services, service_id ); + } + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + +#ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES +#define PUT_PS_NAMES_SERVICE( a ) NULL +#else +#define PUT_PS_NAMES_SERVICE( a ) a +#endif + + FT_DEFINE_MODULE( + psnames_module_class, + + 0, /* this is not a font driver, nor a renderer */ + sizeof ( FT_ModuleRec ), + + "psnames", /* driver name */ + 0x10000L, /* driver version */ + 0x20000L, /* driver requires FreeType 2 or above */ + + PUT_PS_NAMES_SERVICE( + (void*)&pscmaps_interface ), /* module specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + PUT_PS_NAMES_SERVICE( psnames_get_service ) /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psnames/psmodule.h b/Dependencies/freetype/freetype/src/psnames/psmodule.h new file mode 100644 index 00000000..77045831 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psnames/psmodule.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * psmodule.h + * + * High-level psnames module interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PSMODULE_H_ +#define PSMODULE_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_MODULE( psnames_module_class ) + + +FT_END_HEADER + +#endif /* PSMODULE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psnames/psnamerr.h b/Dependencies/freetype/freetype/src/psnames/psnamerr.h new file mode 100644 index 00000000..e123eb65 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psnames/psnamerr.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * psnamerr.h + * + * PS names module error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the PS names module error enumeration + * constants. + * + */ + +#ifndef PSNAMERR_H_ +#define PSNAMERR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSnames_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSnames + +#include + +#endif /* PSNAMERR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psnames/psnames.c b/Dependencies/freetype/freetype/src/psnames/psnames.c new file mode 100644 index 00000000..2933af1b --- /dev/null +++ b/Dependencies/freetype/freetype/src/psnames/psnames.c @@ -0,0 +1,24 @@ +/**************************************************************************** + * + * psnames.c + * + * FreeType psnames module component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "psmodule.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/psnames/pstables.h b/Dependencies/freetype/freetype/src/psnames/pstables.h new file mode 100644 index 00000000..2a941b04 --- /dev/null +++ b/Dependencies/freetype/freetype/src/psnames/pstables.h @@ -0,0 +1,4238 @@ +/**************************************************************************** + * + * pstables.h + * + * PostScript glyph names. + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /* This file has been generated automatically -- do not edit! */ + + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const char ft_standard_glyph_names[3696] +#ifdef DEFINE_PS_TABLES_DATA + = + { + '.','n','u','l','l', 0, + 'n','o','n','m','a','r','k','i','n','g','r','e','t','u','r','n', 0, + 'n','o','t','e','q','u','a','l', 0, + 'i','n','f','i','n','i','t','y', 0, + 'l','e','s','s','e','q','u','a','l', 0, + 'g','r','e','a','t','e','r','e','q','u','a','l', 0, + 'p','a','r','t','i','a','l','d','i','f','f', 0, + 's','u','m','m','a','t','i','o','n', 0, + 'p','r','o','d','u','c','t', 0, + 'p','i', 0, + 'i','n','t','e','g','r','a','l', 0, + 'O','m','e','g','a', 0, + 'r','a','d','i','c','a','l', 0, + 'a','p','p','r','o','x','e','q','u','a','l', 0, + 'D','e','l','t','a', 0, + 'n','o','n','b','r','e','a','k','i','n','g','s','p','a','c','e', 0, + 'l','o','z','e','n','g','e', 0, + 'a','p','p','l','e', 0, + 'f','r','a','n','c', 0, + 'G','b','r','e','v','e', 0, + 'g','b','r','e','v','e', 0, + 'I','d','o','t','a','c','c','e','n','t', 0, + 'S','c','e','d','i','l','l','a', 0, + 's','c','e','d','i','l','l','a', 0, + 'C','a','c','u','t','e', 0, + 'c','a','c','u','t','e', 0, + 'C','c','a','r','o','n', 0, + 'c','c','a','r','o','n', 0, + 'd','c','r','o','a','t', 0, + '.','n','o','t','d','e','f', 0, + 's','p','a','c','e', 0, + 'e','x','c','l','a','m', 0, + 'q','u','o','t','e','d','b','l', 0, + 'n','u','m','b','e','r','s','i','g','n', 0, + 'd','o','l','l','a','r', 0, + 'p','e','r','c','e','n','t', 0, + 'a','m','p','e','r','s','a','n','d', 0, + 'q','u','o','t','e','r','i','g','h','t', 0, + 'p','a','r','e','n','l','e','f','t', 0, + 'p','a','r','e','n','r','i','g','h','t', 0, + 'a','s','t','e','r','i','s','k', 0, + 'p','l','u','s', 0, + 'c','o','m','m','a', 0, + 'h','y','p','h','e','n', 0, + 'p','e','r','i','o','d', 0, + 's','l','a','s','h', 0, + 'z','e','r','o', 0, + 'o','n','e', 0, + 't','w','o', 0, + 't','h','r','e','e', 0, + 'f','o','u','r', 0, + 'f','i','v','e', 0, + 's','i','x', 0, + 's','e','v','e','n', 0, + 'e','i','g','h','t', 0, + 'n','i','n','e', 0, + 'c','o','l','o','n', 0, + 's','e','m','i','c','o','l','o','n', 0, + 'l','e','s','s', 0, + 'e','q','u','a','l', 0, + 'g','r','e','a','t','e','r', 0, + 'q','u','e','s','t','i','o','n', 0, + 'a','t', 0, + 'A', 0, + 'B', 0, + 'C', 0, + 'D', 0, + 'E', 0, + 'F', 0, + 'G', 0, + 'H', 0, + 'I', 0, + 'J', 0, + 'K', 0, + 'L', 0, + 'M', 0, + 'N', 0, + 'O', 0, + 'P', 0, + 'Q', 0, + 'R', 0, + 'S', 0, + 'T', 0, + 'U', 0, + 'V', 0, + 'W', 0, + 'X', 0, + 'Y', 0, + 'Z', 0, + 'b','r','a','c','k','e','t','l','e','f','t', 0, + 'b','a','c','k','s','l','a','s','h', 0, + 'b','r','a','c','k','e','t','r','i','g','h','t', 0, + 'a','s','c','i','i','c','i','r','c','u','m', 0, + 'u','n','d','e','r','s','c','o','r','e', 0, + 'q','u','o','t','e','l','e','f','t', 0, + 'a', 0, + 'b', 0, + 'c', 0, + 'd', 0, + 'e', 0, + 'f', 0, + 'g', 0, + 'h', 0, + 'i', 0, + 'j', 0, + 'k', 0, + 'l', 0, + 'm', 0, + 'n', 0, + 'o', 0, + 'p', 0, + 'q', 0, + 'r', 0, + 's', 0, + 't', 0, + 'u', 0, + 'v', 0, + 'w', 0, + 'x', 0, + 'y', 0, + 'z', 0, + 'b','r','a','c','e','l','e','f','t', 0, + 'b','a','r', 0, + 'b','r','a','c','e','r','i','g','h','t', 0, + 'a','s','c','i','i','t','i','l','d','e', 0, + 'e','x','c','l','a','m','d','o','w','n', 0, + 'c','e','n','t', 0, + 's','t','e','r','l','i','n','g', 0, + 'f','r','a','c','t','i','o','n', 0, + 'y','e','n', 0, + 'f','l','o','r','i','n', 0, + 's','e','c','t','i','o','n', 0, + 'c','u','r','r','e','n','c','y', 0, + 'q','u','o','t','e','s','i','n','g','l','e', 0, + 'q','u','o','t','e','d','b','l','l','e','f','t', 0, + 'g','u','i','l','l','e','m','o','t','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','r','i','g','h','t', 0, + 'f','i', 0, + 'f','l', 0, + 'e','n','d','a','s','h', 0, + 'd','a','g','g','e','r', 0, + 'd','a','g','g','e','r','d','b','l', 0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d', 0, + 'p','a','r','a','g','r','a','p','h', 0, + 'b','u','l','l','e','t', 0, + 'q','u','o','t','e','s','i','n','g','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','r','i','g','h','t', 0, + 'g','u','i','l','l','e','m','o','t','r','i','g','h','t', 0, + 'e','l','l','i','p','s','i','s', 0, + 'p','e','r','t','h','o','u','s','a','n','d', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n', 0, + 'g','r','a','v','e', 0, + 'a','c','u','t','e', 0, + 'c','i','r','c','u','m','f','l','e','x', 0, + 't','i','l','d','e', 0, + 'm','a','c','r','o','n', 0, + 'b','r','e','v','e', 0, + 'd','o','t','a','c','c','e','n','t', 0, + 'd','i','e','r','e','s','i','s', 0, + 'r','i','n','g', 0, + 'c','e','d','i','l','l','a', 0, + 'h','u','n','g','a','r','u','m','l','a','u','t', 0, + 'o','g','o','n','e','k', 0, + 'c','a','r','o','n', 0, + 'e','m','d','a','s','h', 0, + 'A','E', 0, + 'o','r','d','f','e','m','i','n','i','n','e', 0, + 'L','s','l','a','s','h', 0, + 'O','s','l','a','s','h', 0, + 'O','E', 0, + 'o','r','d','m','a','s','c','u','l','i','n','e', 0, + 'a','e', 0, + 'd','o','t','l','e','s','s','i', 0, + 'l','s','l','a','s','h', 0, + 'o','s','l','a','s','h', 0, + 'o','e', 0, + 'g','e','r','m','a','n','d','b','l','s', 0, + 'o','n','e','s','u','p','e','r','i','o','r', 0, + 'l','o','g','i','c','a','l','n','o','t', 0, + 'm','u', 0, + 't','r','a','d','e','m','a','r','k', 0, + 'E','t','h', 0, + 'o','n','e','h','a','l','f', 0, + 'p','l','u','s','m','i','n','u','s', 0, + 'T','h','o','r','n', 0, + 'o','n','e','q','u','a','r','t','e','r', 0, + 'd','i','v','i','d','e', 0, + 'b','r','o','k','e','n','b','a','r', 0, + 'd','e','g','r','e','e', 0, + 't','h','o','r','n', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s', 0, + 't','w','o','s','u','p','e','r','i','o','r', 0, + 'r','e','g','i','s','t','e','r','e','d', 0, + 'm','i','n','u','s', 0, + 'e','t','h', 0, + 'm','u','l','t','i','p','l','y', 0, + 't','h','r','e','e','s','u','p','e','r','i','o','r', 0, + 'c','o','p','y','r','i','g','h','t', 0, + 'A','a','c','u','t','e', 0, + 'A','c','i','r','c','u','m','f','l','e','x', 0, + 'A','d','i','e','r','e','s','i','s', 0, + 'A','g','r','a','v','e', 0, + 'A','r','i','n','g', 0, + 'A','t','i','l','d','e', 0, + 'C','c','e','d','i','l','l','a', 0, + 'E','a','c','u','t','e', 0, + 'E','c','i','r','c','u','m','f','l','e','x', 0, + 'E','d','i','e','r','e','s','i','s', 0, + 'E','g','r','a','v','e', 0, + 'I','a','c','u','t','e', 0, + 'I','c','i','r','c','u','m','f','l','e','x', 0, + 'I','d','i','e','r','e','s','i','s', 0, + 'I','g','r','a','v','e', 0, + 'N','t','i','l','d','e', 0, + 'O','a','c','u','t','e', 0, + 'O','c','i','r','c','u','m','f','l','e','x', 0, + 'O','d','i','e','r','e','s','i','s', 0, + 'O','g','r','a','v','e', 0, + 'O','t','i','l','d','e', 0, + 'S','c','a','r','o','n', 0, + 'U','a','c','u','t','e', 0, + 'U','c','i','r','c','u','m','f','l','e','x', 0, + 'U','d','i','e','r','e','s','i','s', 0, + 'U','g','r','a','v','e', 0, + 'Y','a','c','u','t','e', 0, + 'Y','d','i','e','r','e','s','i','s', 0, + 'Z','c','a','r','o','n', 0, + 'a','a','c','u','t','e', 0, + 'a','c','i','r','c','u','m','f','l','e','x', 0, + 'a','d','i','e','r','e','s','i','s', 0, + 'a','g','r','a','v','e', 0, + 'a','r','i','n','g', 0, + 'a','t','i','l','d','e', 0, + 'c','c','e','d','i','l','l','a', 0, + 'e','a','c','u','t','e', 0, + 'e','c','i','r','c','u','m','f','l','e','x', 0, + 'e','d','i','e','r','e','s','i','s', 0, + 'e','g','r','a','v','e', 0, + 'i','a','c','u','t','e', 0, + 'i','c','i','r','c','u','m','f','l','e','x', 0, + 'i','d','i','e','r','e','s','i','s', 0, + 'i','g','r','a','v','e', 0, + 'n','t','i','l','d','e', 0, + 'o','a','c','u','t','e', 0, + 'o','c','i','r','c','u','m','f','l','e','x', 0, + 'o','d','i','e','r','e','s','i','s', 0, + 'o','g','r','a','v','e', 0, + 'o','t','i','l','d','e', 0, + 's','c','a','r','o','n', 0, + 'u','a','c','u','t','e', 0, + 'u','c','i','r','c','u','m','f','l','e','x', 0, + 'u','d','i','e','r','e','s','i','s', 0, + 'u','g','r','a','v','e', 0, + 'y','a','c','u','t','e', 0, + 'y','d','i','e','r','e','s','i','s', 0, + 'z','c','a','r','o','n', 0, + 'e','x','c','l','a','m','s','m','a','l','l', 0, + 'H','u','n','g','a','r','u','m','l','a','u','t','s','m','a','l','l', 0, + 'd','o','l','l','a','r','o','l','d','s','t','y','l','e', 0, + 'd','o','l','l','a','r','s','u','p','e','r','i','o','r', 0, + 'a','m','p','e','r','s','a','n','d','s','m','a','l','l', 0, + 'A','c','u','t','e','s','m','a','l','l', 0, + 'p','a','r','e','n','l','e','f','t','s','u','p','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 't','w','o','d','o','t','e','n','l','e','a','d','e','r', 0, + 'o','n','e','d','o','t','e','n','l','e','a','d','e','r', 0, + 'z','e','r','o','o','l','d','s','t','y','l','e', 0, + 'o','n','e','o','l','d','s','t','y','l','e', 0, + 't','w','o','o','l','d','s','t','y','l','e', 0, + 't','h','r','e','e','o','l','d','s','t','y','l','e', 0, + 'f','o','u','r','o','l','d','s','t','y','l','e', 0, + 'f','i','v','e','o','l','d','s','t','y','l','e', 0, + 's','i','x','o','l','d','s','t','y','l','e', 0, + 's','e','v','e','n','o','l','d','s','t','y','l','e', 0, + 'e','i','g','h','t','o','l','d','s','t','y','l','e', 0, + 'n','i','n','e','o','l','d','s','t','y','l','e', 0, + 'c','o','m','m','a','s','u','p','e','r','i','o','r', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s','e','m','d','a','s','h', 0, + 'p','e','r','i','o','d','s','u','p','e','r','i','o','r', 0, + 'q','u','e','s','t','i','o','n','s','m','a','l','l', 0, + 'a','s','u','p','e','r','i','o','r', 0, + 'b','s','u','p','e','r','i','o','r', 0, + 'c','e','n','t','s','u','p','e','r','i','o','r', 0, + 'd','s','u','p','e','r','i','o','r', 0, + 'e','s','u','p','e','r','i','o','r', 0, + 'i','s','u','p','e','r','i','o','r', 0, + 'l','s','u','p','e','r','i','o','r', 0, + 'm','s','u','p','e','r','i','o','r', 0, + 'n','s','u','p','e','r','i','o','r', 0, + 'o','s','u','p','e','r','i','o','r', 0, + 'r','s','u','p','e','r','i','o','r', 0, + 's','s','u','p','e','r','i','o','r', 0, + 't','s','u','p','e','r','i','o','r', 0, + 'f','f', 0, + 'f','f','i', 0, + 'f','f','l', 0, + 'p','a','r','e','n','l','e','f','t','i','n','f','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'C','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'h','y','p','h','e','n','s','u','p','e','r','i','o','r', 0, + 'G','r','a','v','e','s','m','a','l','l', 0, + 'A','s','m','a','l','l', 0, + 'B','s','m','a','l','l', 0, + 'C','s','m','a','l','l', 0, + 'D','s','m','a','l','l', 0, + 'E','s','m','a','l','l', 0, + 'F','s','m','a','l','l', 0, + 'G','s','m','a','l','l', 0, + 'H','s','m','a','l','l', 0, + 'I','s','m','a','l','l', 0, + 'J','s','m','a','l','l', 0, + 'K','s','m','a','l','l', 0, + 'L','s','m','a','l','l', 0, + 'M','s','m','a','l','l', 0, + 'N','s','m','a','l','l', 0, + 'O','s','m','a','l','l', 0, + 'P','s','m','a','l','l', 0, + 'Q','s','m','a','l','l', 0, + 'R','s','m','a','l','l', 0, + 'S','s','m','a','l','l', 0, + 'T','s','m','a','l','l', 0, + 'U','s','m','a','l','l', 0, + 'V','s','m','a','l','l', 0, + 'W','s','m','a','l','l', 0, + 'X','s','m','a','l','l', 0, + 'Y','s','m','a','l','l', 0, + 'Z','s','m','a','l','l', 0, + 'c','o','l','o','n','m','o','n','e','t','a','r','y', 0, + 'o','n','e','f','i','t','t','e','d', 0, + 'r','u','p','i','a','h', 0, + 'T','i','l','d','e','s','m','a','l','l', 0, + 'e','x','c','l','a','m','d','o','w','n','s','m','a','l','l', 0, + 'c','e','n','t','o','l','d','s','t','y','l','e', 0, + 'L','s','l','a','s','h','s','m','a','l','l', 0, + 'S','c','a','r','o','n','s','m','a','l','l', 0, + 'Z','c','a','r','o','n','s','m','a','l','l', 0, + 'D','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'B','r','e','v','e','s','m','a','l','l', 0, + 'C','a','r','o','n','s','m','a','l','l', 0, + 'D','o','t','a','c','c','e','n','t','s','m','a','l','l', 0, + 'M','a','c','r','o','n','s','m','a','l','l', 0, + 'f','i','g','u','r','e','d','a','s','h', 0, + 'h','y','p','h','e','n','i','n','f','e','r','i','o','r', 0, + 'O','g','o','n','e','k','s','m','a','l','l', 0, + 'R','i','n','g','s','m','a','l','l', 0, + 'C','e','d','i','l','l','a','s','m','a','l','l', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n','s','m','a','l','l', 0, + 'o','n','e','e','i','g','h','t','h', 0, + 't','h','r','e','e','e','i','g','h','t','h','s', 0, + 'f','i','v','e','e','i','g','h','t','h','s', 0, + 's','e','v','e','n','e','i','g','h','t','h','s', 0, + 'o','n','e','t','h','i','r','d', 0, + 't','w','o','t','h','i','r','d','s', 0, + 'z','e','r','o','s','u','p','e','r','i','o','r', 0, + 'f','o','u','r','s','u','p','e','r','i','o','r', 0, + 'f','i','v','e','s','u','p','e','r','i','o','r', 0, + 's','i','x','s','u','p','e','r','i','o','r', 0, + 's','e','v','e','n','s','u','p','e','r','i','o','r', 0, + 'e','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 'n','i','n','e','s','u','p','e','r','i','o','r', 0, + 'z','e','r','o','i','n','f','e','r','i','o','r', 0, + 'o','n','e','i','n','f','e','r','i','o','r', 0, + 't','w','o','i','n','f','e','r','i','o','r', 0, + 't','h','r','e','e','i','n','f','e','r','i','o','r', 0, + 'f','o','u','r','i','n','f','e','r','i','o','r', 0, + 'f','i','v','e','i','n','f','e','r','i','o','r', 0, + 's','i','x','i','n','f','e','r','i','o','r', 0, + 's','e','v','e','n','i','n','f','e','r','i','o','r', 0, + 'e','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'n','i','n','e','i','n','f','e','r','i','o','r', 0, + 'c','e','n','t','i','n','f','e','r','i','o','r', 0, + 'd','o','l','l','a','r','i','n','f','e','r','i','o','r', 0, + 'p','e','r','i','o','d','i','n','f','e','r','i','o','r', 0, + 'c','o','m','m','a','i','n','f','e','r','i','o','r', 0, + 'A','g','r','a','v','e','s','m','a','l','l', 0, + 'A','a','c','u','t','e','s','m','a','l','l', 0, + 'A','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'A','t','i','l','d','e','s','m','a','l','l', 0, + 'A','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'A','r','i','n','g','s','m','a','l','l', 0, + 'A','E','s','m','a','l','l', 0, + 'C','c','e','d','i','l','l','a','s','m','a','l','l', 0, + 'E','g','r','a','v','e','s','m','a','l','l', 0, + 'E','a','c','u','t','e','s','m','a','l','l', 0, + 'E','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'E','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'I','g','r','a','v','e','s','m','a','l','l', 0, + 'I','a','c','u','t','e','s','m','a','l','l', 0, + 'I','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'I','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'E','t','h','s','m','a','l','l', 0, + 'N','t','i','l','d','e','s','m','a','l','l', 0, + 'O','g','r','a','v','e','s','m','a','l','l', 0, + 'O','a','c','u','t','e','s','m','a','l','l', 0, + 'O','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'O','t','i','l','d','e','s','m','a','l','l', 0, + 'O','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'O','E','s','m','a','l','l', 0, + 'O','s','l','a','s','h','s','m','a','l','l', 0, + 'U','g','r','a','v','e','s','m','a','l','l', 0, + 'U','a','c','u','t','e','s','m','a','l','l', 0, + 'U','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'U','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'Y','a','c','u','t','e','s','m','a','l','l', 0, + 'T','h','o','r','n','s','m','a','l','l', 0, + 'Y','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + '0','0','1','.','0','0','0', 0, + '0','0','1','.','0','0','1', 0, + '0','0','1','.','0','0','2', 0, + '0','0','1','.','0','0','3', 0, + 'B','l','a','c','k', 0, + 'B','o','l','d', 0, + 'B','o','o','k', 0, + 'L','i','g','h','t', 0, + 'M','e','d','i','u','m', 0, + 'R','e','g','u','l','a','r', 0, + 'R','o','m','a','n', 0, + 'S','e','m','i','b','o','l','d', 0, + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#define FT_NUM_MAC_NAMES 258 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const short ft_mac_names[FT_NUM_MAC_NAMES] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 253, 0, 6, 261, 267, 274, 283, 294, 301, 309, 758, 330, 340, 351, + 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, + 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, + 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, + 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 979, 608, 610, + 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, + 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, + 1375,1392,1405,1414,1486,1512,1562,1603,1632,1610,1622,1645,1639,1652, + 1661,1690,1668,1680,1697,1726,1704,1716,1733,1740,1769,1747,1759,1776, + 1790,1819,1797,1809, 839,1263, 707, 712, 741, 881, 871,1160,1302,1346, + 1197, 985,1031, 23,1086,1108, 32,1219, 41, 51, 730,1194, 64, 76, + 86, 94, 97,1089,1118, 106,1131,1150, 966, 696,1183, 112, 734, 120, + 132, 783, 930, 945, 138,1385,1398,1529,1115,1157, 832,1079, 770, 916, + 598, 319,1246, 155,1833,1586, 721, 749, 797, 811, 826, 829, 846, 856, + 888, 903, 954,1363,1421,1356,1433,1443,1450,1457,1469,1479,1493,1500, + 163,1522,1543,1550,1572,1134, 991,1002,1008,1015,1021,1040,1045,1053, + 1066,1073,1101,1143,1536,1783,1596,1843,1253,1207,1319,1579,1826,1229, + 1270,1313,1323,1171,1290,1332,1211,1235,1276, 169, 175, 182, 189, 200, + 209, 218, 225, 232, 239, 246 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#define FT_NUM_SID_NAMES 391 + + /* Values are offsets into the `ft_standard_glyph_names' table */ + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const short ft_sid_names[FT_NUM_SID_NAMES] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 253, 261, 267, 274, 283, 294, 301, 309, 319, 330, 340, 351, 360, 365, + 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, + 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, + 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, + 532, 534, 536, 538, 540, 552, 562, 575, 587, 598, 608, 610, 612, 614, + 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, + 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 696, 707, + 712, 721, 730, 734, 741, 749, 758, 770, 783, 797, 811, 826, 829, 832, + 839, 846, 856, 871, 881, 888, 903, 916, 930, 945, 954, 966, 979, 985, + 991,1002,1008,1015,1021,1031,1040,1045,1053,1066,1073,1079,1086,1089, + 1101,1108,1115,1118,1131,1134,1143,1150,1157,1160,1171,1183,1194,1197, + 1207,1211,1219,1229,1235,1246,1253,1263,1270,1276,1290,1302,1313,1319, + 1323,1332,1346,1356,1363,1375,1385,1392,1398,1405,1414,1421,1433,1443, + 1450,1457,1469,1479,1486,1493,1500,1512,1522,1529,1536,1543,1550,1562, + 1572,1579,1586,1596,1603,1610,1622,1632,1639,1645,1652,1661,1668,1680, + 1690,1697,1704,1716,1726,1733,1740,1747,1759,1769,1776,1783,1790,1797, + 1809,1819,1826,1833,1843,1850,1862,1880,1895,1910,1925,1936,1954,1973, + 1988,2003,2016,2028,2040,2054,2067,2080,2092,2106,2120,2133,2147,2167, + 2182,2196,2206,2216,2229,2239,2249,2259,2269,2279,2289,2299,2309,2319, + 2329,2332,2336,2340,2358,2377,2393,2408,2419,2426,2433,2440,2447,2454, + 2461,2468,2475,2482,2489,2496,2503,2510,2517,2524,2531,2538,2545,2552, + 2559,2566,2573,2580,2587,2594,2601,2615,2625,2632,2643,2659,2672,2684, + 2696,2708,2722,2733,2744,2759,2771,2782,2797,2809,2819,2832,2850,2860, + 2873,2885,2898,2907,2917,2930,2943,2956,2968,2982,2996,3009,3022,3034, + 3046,3060,3073,3086,3098,3112,3126,3139,3152,3167,3182,3196,3208,3220, + 3237,3249,3264,3275,3283,3297,3309,3321,3338,3353,3365,3377,3394,3409, + 3418,3430,3442,3454,3471,3483,3498,3506,3518,3530,3542,3559,3574,3586, + 3597,3612,3620,3628,3636,3644,3650,3655,3660,3666,3673,3681,3687 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* the following are indices into the SID name table */ +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned short t1_standard_encoding[256] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110, + 0,111,112,113,114, 0,115,116,117,118,119,120,121,122, 0,123, + 0,124,125,126,127,128,129,130,131, 0,132,133, 0,134,135,136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,138, 0,139, 0, 0, 0, 0,140,141,142,143, 0, 0, 0, 0, + 0,144, 0, 0, 0,145, 0, 0,146,147,148,149, 0, 0, 0, 0 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* the following are indices into the SID name table */ +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned short t1_expert_encoding[256] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1,229,230, 0,231,232,233,234,235,236,237,238, 13, 14, 15, 99, + 239,240,241,242,243,244,245,246,247,248, 27, 28,249,250,251,252, + 0,253,254,255,256,257, 0, 0, 0,258, 0, 0,259,260,261,262, + 0, 0,263,264,265, 0,266,109,110,267,268,269, 0,270,271,272, + 273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, + 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,304,305,306, 0, 0,307,308,309,310,311, 0,312, 0, 0,313, + 0, 0,314,315, 0, 0,316,317,318, 0, 0, 0,158,155,163,319, + 320,321,322,323,324,325, 0, 0,326,150,164,169,327,328,329,330, + 331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346, + 347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362, + 363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + + /* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + +#ifndef DEFINE_PS_TABLES_DATA +#ifdef __cplusplus + extern "C" +#else + extern +#endif +#endif + const unsigned char ft_adobe_glyph_list[55997L] +#ifdef DEFINE_PS_TABLES_DATA + = + { + 0, 52, 0,106, 2,167, 3, 63, 4,220, 6,125, 9,143, 10, 23, + 11,137, 12,199, 14,246, 15, 87, 16,233, 17,219, 18,104, 19, 88, + 22,110, 23, 32, 23, 71, 24, 77, 27,156, 29, 73, 31,247, 32,107, + 32,222, 33, 55, 34,154, 35,218, 58, 10, 64,122, 72,188, 80,109, + 88,104, 93, 61, 98,168,106, 91,114,111,115,237,122,180,127,255, + 135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199, + 202, 25,204,166,208,209,209, 81,215, 26, 65,143, 0, 65, 0,140, + 0,175, 0,193, 1, 15, 1,147, 1,233, 1,251, 2, 7, 2, 40, + 2, 57, 2, 82, 2, 91, 2,128, 2,136, 2,154, 69,131, 0,198, + 0,150, 0,158, 0,167,225,227,245,244,101,128, 1,252,237,225, + 227,242,239,110,128, 1,226,243,237,225,236,108,128,247,230,225, + 227,245,244,101,129, 0,193, 0,185,243,237,225,236,108,128,247, + 225,226,242,229,246,101,134, 1, 2, 0,213, 0,221, 0,232, 0, + 243, 0,251, 1, 7,225,227,245,244,101,128, 30,174,227,249,242, + 233,236,236,233, 99,128, 4,208,228,239,244,226,229,236,239,119, + 128, 30,182,231,242,225,246,101,128, 30,176,232,239,239,235,225, + 226,239,246,101,128, 30,178,244,233,236,228,101,128, 30,180, 99, + 4, 1, 25, 1, 32, 1,121, 1,137,225,242,239,110,128, 1,205, + 233,242, 99, 2, 1, 40, 1, 45,236,101,128, 36,182,245,237,230, + 236,229,120,134, 0,194, 1, 66, 1, 74, 1, 85, 1, 93, 1,105, + 1,113,225,227,245,244,101,128, 30,164,228,239,244,226,229,236, + 239,119,128, 30,172,231,242,225,246,101,128, 30,166,232,239,239, + 235,225,226,239,246,101,128, 30,168,243,237,225,236,108,128,247, + 226,244,233,236,228,101,128, 30,170,245,244,101,129,246,201, 1, + 129,243,237,225,236,108,128,247,180,249,242,233,236,236,233, 99, + 128, 4, 16,100, 3, 1,155, 1,165, 1,209,226,236,231,242,225, + 246,101,128, 2, 0,233,229,242,229,243,233,115,131, 0,196, 1, + 181, 1,192, 1,201,227,249,242,233,236,236,233, 99,128, 4,210, + 237,225,227,242,239,110,128, 1,222,243,237,225,236,108,128,247, + 228,239,116, 2, 1,216, 1,224,226,229,236,239,119,128, 30,160, + 237,225,227,242,239,110,128, 1,224,231,242,225,246,101,129, 0, + 192, 1,243,243,237,225,236,108,128,247,224,232,239,239,235,225, + 226,239,246,101,128, 30,162,105, 2, 2, 13, 2, 25,229,227,249, + 242,233,236,236,233, 99,128, 4,212,238,246,229,242,244,229,228, + 226,242,229,246,101,128, 2, 2,236,240,232, 97,129, 3,145, 2, + 49,244,239,238,239,115,128, 3,134,109, 2, 2, 63, 2, 71,225, + 227,242,239,110,128, 1, 0,239,238,239,243,240,225,227,101,128, + 255, 33,239,231,239,238,229,107,128, 1, 4,242,233,238,103,131, + 0,197, 2,104, 2,112, 2,120,225,227,245,244,101,128, 1,250, + 226,229,236,239,119,128, 30, 0,243,237,225,236,108,128,247,229, + 243,237,225,236,108,128,247, 97,244,233,236,228,101,129, 0,195, + 2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229, + 238,233,225,110,128, 5, 49, 66,137, 0, 66, 2,189, 2,198, 2, + 223, 3, 3, 3, 10, 3, 22, 3, 34, 3, 46, 3, 54,227,233,242, + 227,236,101,128, 36,183,228,239,116, 2, 2,206, 2,215,225,227, + 227,229,238,116,128, 30, 2,226,229,236,239,119,128, 30, 4,101, + 3, 2,231, 2,242, 2,254,227,249,242,233,236,236,233, 99,128, + 4, 17,238,225,242,237,229,238,233,225,110,128, 5, 50,244, 97, + 128, 3,146,232,239,239,107,128, 1,129,236,233,238,229,226,229, + 236,239,119,128, 30, 6,237,239,238,239,243,240,225,227,101,128, + 255, 34,242,229,246,229,243,237,225,236,108,128,246,244,243,237, + 225,236,108,128,247, 98,244,239,240,226,225,114,128, 1,130, 67, + 137, 0, 67, 3, 85, 3,127, 3,193, 3,210, 3,224, 4,171, 4, + 188, 4,200, 4,212, 97, 3, 3, 93, 3,104, 3,111,225,242,237, + 229,238,233,225,110,128, 5, 62,227,245,244,101,128, 1, 6,242, + 239,110,129,246,202, 3,119,243,237,225,236,108,128,246,245, 99, + 3, 3,135, 3,142, 3,171,225,242,239,110,128, 1, 12,229,228, + 233,236,236, 97,130, 0,199, 3,155, 3,163,225,227,245,244,101, + 128, 30, 8,243,237,225,236,108,128,247,231,233,242, 99, 2, 3, + 179, 3,184,236,101,128, 36,184,245,237,230,236,229,120,128, 1, + 8,228,239,116,129, 1, 10, 3,201,225,227,227,229,238,116,128, + 1, 10,229,228,233,236,236,225,243,237,225,236,108,128,247,184, + 104, 4, 3,234, 3,246, 4,161, 4,165,225,225,242,237,229,238, + 233,225,110,128, 5, 73,101, 6, 4, 4, 4, 24, 4, 35, 4,103, + 4,115, 4,136,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,188,227,249,242,233,236,236,233, 99, + 128, 4, 39,100, 2, 4, 41, 4, 85,229,243,227,229,238,228,229, + 114, 2, 4, 54, 4, 74,225,226,235,232,225,243,233,225,238,227, + 249,242,233,236,236,233, 99,128, 4,190,227,249,242,233,236,236, + 233, 99,128, 4,182,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,244,232,225,242,237,229,238,233,225,110, + 128, 5, 67,235,232,225,235,225,243,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,203,246,229,242,244,233,227,225,236, + 243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4, + 184,105,128, 3,167,239,239,107,128, 1,135,233,242,227,245,237, + 230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239, + 243,240,225,227,101,128,255, 35,239,225,242,237,229,238,233,225, + 110,128, 5, 81,243,237,225,236,108,128,247, 99, 68,142, 0, 68, + 4,252, 5, 10, 5, 36, 5, 96, 5,121, 5,166, 5,173, 5,231, + 5,244, 6, 0, 6, 12, 6, 28, 6, 48, 6, 57, 90,129, 1,241, + 5, 2,227,225,242,239,110,128, 1,196, 97, 2, 5, 16, 5, 27, + 225,242,237,229,238,233,225,110,128, 5, 52,230,242,233,227,225, + 110,128, 1,137, 99, 4, 5, 46, 5, 53, 5, 62, 5, 89,225,242, + 239,110,128, 1, 14,229,228,233,236,236, 97,128, 30, 16,233,242, + 99, 2, 5, 70, 5, 75,236,101,128, 36,185,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 18,242,239,225,116,128, 1, 16, + 228,239,116, 2, 5,104, 5,113,225,227,227,229,238,116,128, 30, + 10,226,229,236,239,119,128, 30, 12,101, 3, 5,129, 5,140, 5, + 150,227,249,242,233,236,236,233, 99,128, 4, 20,233,227,239,240, + 244,233, 99,128, 3,238,236,244, 97,129, 34, 6, 5,158,231,242, + 229,229,107,128, 3,148,232,239,239,107,128, 1,138,105, 2, 5, + 179, 5,218,229,242,229,243,233,115,131,246,203, 5,194, 5,202, + 5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128, + 246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231, + 242,229,229,107,128, 3,220,234,229,227,249,242,233,236,236,233, + 99,128, 4, 2,236,233,238,229,226,229,236,239,119,128, 30, 14, + 237,239,238,239,243,240,225,227,101,128,255, 36,239,244,225,227, + 227,229,238,244,243,237,225,236,108,128,246,247,115, 2, 6, 34, + 6, 41,236,225,243,104,128, 1, 16,237,225,236,108,128,247,100, + 244,239,240,226,225,114,128, 1,139,122,131, 1,242, 6, 67, 6, + 75, 6,112,227,225,242,239,110,128, 1,197,101, 2, 6, 81, 6, + 101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,224,227,249,242,233,236,236,233, 99,128, 4, 5, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 15, 69,146, 0, + 69, 6,165, 6,183, 6,191, 7, 89, 7,153, 7,165, 7,183, 7, + 211, 8, 7, 8, 36, 8, 94, 8,169, 8,189, 8,208, 8,248, 9, + 44, 9,109, 9,115,225,227,245,244,101,129, 0,201, 6,175,243, + 237,225,236,108,128,247,233,226,242,229,246,101,128, 1, 20, 99, + 5, 6,203, 6,210, 6,224, 6,236, 7, 79,225,242,239,110,128, + 1, 26,229,228,233,236,236,225,226,242,229,246,101,128, 30, 28, + 232,225,242,237,229,238,233,225,110,128, 5, 53,233,242, 99, 2, + 6,244, 6,249,236,101,128, 36,186,245,237,230,236,229,120,135, + 0,202, 7, 16, 7, 24, 7, 32, 7, 43, 7, 51, 7, 63, 7, 71, + 225,227,245,244,101,128, 30,190,226,229,236,239,119,128, 30, 24, + 228,239,244,226,229,236,239,119,128, 30,198,231,242,225,246,101, + 128, 30,192,232,239,239,235,225,226,239,246,101,128, 30,194,243, + 237,225,236,108,128,247,234,244,233,236,228,101,128, 30,196,249, + 242,233,236,236,233, 99,128, 4, 4,100, 3, 7, 97, 7,107, 7, + 127,226,236,231,242,225,246,101,128, 2, 4,233,229,242,229,243, + 233,115,129, 0,203, 7,119,243,237,225,236,108,128,247,235,239, + 116,130, 1, 22, 7,136, 7,145,225,227,227,229,238,116,128, 1, + 22,226,229,236,239,119,128, 30,184,230,227,249,242,233,236,236, + 233, 99,128, 4, 36,231,242,225,246,101,129, 0,200, 7,175,243, + 237,225,236,108,128,247,232,104, 2, 7,189, 7,200,225,242,237, + 229,238,233,225,110,128, 5, 55,239,239,235,225,226,239,246,101, + 128, 30,186,105, 3, 7,219, 7,230, 7,245,231,232,244,242,239, + 237,225,110,128, 33,103,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 6,239,244,233,230,233,229,228,227,249,242,233, + 236,236,233, 99,128, 4,100,108, 2, 8, 13, 8, 24,227,249,242, + 233,236,236,233, 99,128, 4, 27,229,246,229,238,242,239,237,225, + 110,128, 33,106,109, 3, 8, 44, 8, 72, 8, 83,225,227,242,239, + 110,130, 1, 18, 8, 56, 8, 64,225,227,245,244,101,128, 30, 22, + 231,242,225,246,101,128, 30, 20,227,249,242,233,236,236,233, 99, + 128, 4, 28,239,238,239,243,240,225,227,101,128,255, 37,110, 4, + 8,104, 8,115, 8,135, 8,154,227,249,242,233,236,236,233, 99, + 128, 4, 29,228,229,243,227,229,238,228,229,242,227,249,242,233, + 236,236,233, 99,128, 4,162,103,129, 1, 74, 8,141,232,229,227, + 249,242,233,236,236,233, 99,128, 4,164,232,239,239,235,227,249, + 242,233,236,236,233, 99,128, 4,199,111, 2, 8,175, 8,183,231, + 239,238,229,107,128, 1, 24,240,229,110,128, 1,144,240,243,233, + 236,239,110,129, 3,149, 8,200,244,239,238,239,115,128, 3,136, + 114, 2, 8,214, 8,225,227,249,242,233,236,236,233, 99,128, 4, + 32,229,246,229,242,243,229,100,129, 1,142, 8,237,227,249,242, + 233,236,236,233, 99,128, 4, 45,115, 4, 9, 2, 9, 13, 9, 33, + 9, 37,227,249,242,233,236,236,233, 99,128, 4, 33,228,229,243, + 227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4, + 170,104,128, 1,169,237,225,236,108,128,247,101,116, 3, 9, 52, + 9, 78, 9, 92, 97,130, 3,151, 9, 60, 9, 70,242,237,229,238, + 233,225,110,128, 5, 56,244,239,238,239,115,128, 3,137,104,129, + 0,208, 9, 84,243,237,225,236,108,128,247,240,233,236,228,101, + 129, 30,188, 9,101,226,229,236,239,119,128, 30, 26,245,242,111, + 128, 32,172,250,104,130, 1,183, 9,124, 9,132,227,225,242,239, + 110,128, 1,238,242,229,246,229,242,243,229,100,128, 1,184, 70, + 136, 0, 70, 9,163, 9,172, 9,184, 9,212, 9,219, 9,248, 10, + 4, 10, 15,227,233,242,227,236,101,128, 36,187,228,239,244,225, + 227,227,229,238,116,128, 30, 30,101, 2, 9,190, 9,202,232,225, + 242,237,229,238,233,225,110,128, 5, 86,233,227,239,240,244,233, + 99,128, 3,228,232,239,239,107,128, 1,145,105, 2, 9,225, 9, + 238,244,225,227,249,242,233,236,236,233, 99,128, 4,114,246,229, + 242,239,237,225,110,128, 33,100,237,239,238,239,243,240,225,227, + 101,128,255, 38,239,245,242,242,239,237,225,110,128, 33, 99,243, + 237,225,236,108,128,247,102, 71,140, 0, 71, 10, 51, 10, 61, 10, + 107, 10,115, 10,176, 10,193, 10,205, 11, 39, 11, 52, 11, 65, 11, + 90, 11,107,194,243,241,245,225,242,101,128, 51,135, 97, 3, 10, + 69, 10, 76, 10, 94,227,245,244,101,128, 1,244,237,237, 97,129, + 3,147, 10, 84,225,230,242,233,227,225,110,128, 1,148,238,231, + 233,225,227,239,240,244,233, 99,128, 3,234,226,242,229,246,101, + 128, 1, 30, 99, 4, 10,125, 10,132, 10,141, 10,163,225,242,239, + 110,128, 1,230,229,228,233,236,236, 97,128, 1, 34,233,242, 99, + 2, 10,149, 10,154,236,101,128, 36,188,245,237,230,236,229,120, + 128, 1, 28,239,237,237,225,225,227,227,229,238,116,128, 1, 34, + 228,239,116,129, 1, 32, 10,184,225,227,227,229,238,116,128, 1, + 32,229,227,249,242,233,236,236,233, 99,128, 4, 19,104, 3, 10, + 213, 10,226, 11, 33,225,228,225,242,237,229,238,233,225,110,128, + 5, 66,101, 3, 10,234, 10,255, 11, 16,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,148,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,146, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 144,239,239,107,128, 1,147,233,237,225,242,237,229,238,233,225, + 110,128, 5, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, + 3,109, 2, 11, 71, 11, 79,225,227,242,239,110,128, 30, 32,239, + 238,239,243,240,225,227,101,128,255, 39,242,225,246,101,129,246, + 206, 11, 99,243,237,225,236,108,128,247, 96,115, 2, 11,113, 11, + 129,237,225,236,108,129,247,103, 11,122,232,239,239,107,128, 2, + 155,244,242,239,235,101,128, 1,228, 72,140, 0, 72, 11,165, 11, + 190, 11,198, 11,208, 12, 17, 12, 40, 12, 77, 12,117, 12,129, 12, + 157, 12,165, 12,189,177,184, 53, 3, 11,175, 11,180, 11,185,179, + 51,128, 37,207,180, 51,128, 37,170,181, 49,128, 37,171,178,178, + 176,183, 51,128, 37,161,208,243,241,245,225,242,101,128, 51,203, + 97, 3, 11,216, 11,236, 12, 0,225,226,235,232,225,243,233,225, + 238,227,249,242,233,236,236,233, 99,128, 4,168,228,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,178, + 242,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, + 42, 98, 2, 12, 23, 12, 28,225,114,128, 1, 38,242,229,246,229, + 226,229,236,239,119,128, 30, 42, 99, 2, 12, 46, 12, 55,229,228, + 233,236,236, 97,128, 30, 40,233,242, 99, 2, 12, 63, 12, 68,236, + 101,128, 36,189,245,237,230,236,229,120,128, 1, 36,100, 2, 12, + 83, 12, 93,233,229,242,229,243,233,115,128, 30, 38,239,116, 2, + 12,100, 12,109,225,227,227,229,238,116,128, 30, 34,226,229,236, + 239,119,128, 30, 36,237,239,238,239,243,240,225,227,101,128,255, + 40,111, 2, 12,135, 12,146,225,242,237,229,238,233,225,110,128, + 5, 64,242,233,227,239,240,244,233, 99,128, 3,232,243,237,225, + 236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116, + 129,246,207, 12,181,243,237,225,236,108,128,246,248,250,243,241, + 245,225,242,101,128, 51,144, 73,146, 0, 73, 12,239, 12,251, 12, + 255, 13, 11, 13, 29, 13, 37, 13, 94, 13,181, 13,214, 13,224, 13, + 242, 13,254, 14, 48, 14, 86, 14, 99, 14,166, 14,187, 14,205,193, + 227,249,242,233,236,236,233, 99,128, 4, 47, 74,128, 1, 50,213, + 227,249,242,233,236,236,233, 99,128, 4, 46,225,227,245,244,101, + 129, 0,205, 13, 21,243,237,225,236,108,128,247,237,226,242,229, + 246,101,128, 1, 44, 99, 3, 13, 45, 13, 52, 13, 84,225,242,239, + 110,128, 1,207,233,242, 99, 2, 13, 60, 13, 65,236,101,128, 36, + 190,245,237,230,236,229,120,129, 0,206, 13, 76,243,237,225,236, + 108,128,247,238,249,242,233,236,236,233, 99,128, 4, 6,100, 3, + 13,102, 13,112, 13,155,226,236,231,242,225,246,101,128, 2, 8, + 233,229,242,229,243,233,115,131, 0,207, 13,128, 13,136, 13,147, + 225,227,245,244,101,128, 30, 46,227,249,242,233,236,236,233, 99, + 128, 4,228,243,237,225,236,108,128,247,239,239,116,130, 1, 48, + 13,164, 13,173,225,227,227,229,238,116,128, 1, 48,226,229,236, + 239,119,128, 30,202,101, 2, 13,187, 13,203,226,242,229,246,229, + 227,249,242,233,236,236,233, 99,128, 4,214,227,249,242,233,236, + 236,233, 99,128, 4, 21,230,242,225,235,244,245,114,128, 33, 17, + 231,242,225,246,101,129, 0,204, 13,234,243,237,225,236,108,128, + 247,236,232,239,239,235,225,226,239,246,101,128, 30,200,105, 3, + 14, 6, 14, 17, 14, 32,227,249,242,233,236,236,233, 99,128, 4, + 24,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 10, + 243,232,239,242,244,227,249,242,233,236,236,233, 99,128, 4, 25, + 109, 2, 14, 54, 14, 75,225,227,242,239,110,129, 1, 42, 14, 64, + 227,249,242,233,236,236,233, 99,128, 4,226,239,238,239,243,240, + 225,227,101,128,255, 41,238,233,225,242,237,229,238,233,225,110, + 128, 5, 59,111, 3, 14,107, 14,118, 14,126,227,249,242,233,236, + 236,233, 99,128, 4, 1,231,239,238,229,107,128, 1, 46,244, 97, + 131, 3,153, 14,137, 14,147, 14,158,225,230,242,233,227,225,110, + 128, 1,150,228,233,229,242,229,243,233,115,128, 3,170,244,239, + 238,239,115,128, 3,138,115, 2, 14,172, 14,179,237,225,236,108, + 128,247,105,244,242,239,235,101,128, 1,151,244,233,236,228,101, + 129, 1, 40, 14,197,226,229,236,239,119,128, 30, 44,250,232,233, + 244,243, 97, 2, 14,216, 14,227,227,249,242,233,236,236,233, 99, + 128, 4,116,228,226,236,231,242,225,246,229,227,249,242,233,236, + 236,233, 99,128, 4,118, 74,134, 0, 74, 15, 6, 15, 18, 15, 41, + 15, 53, 15, 67, 15, 79,225,225,242,237,229,238,233,225,110,128, + 5, 65,227,233,242, 99, 2, 15, 27, 15, 32,236,101,128, 36,191, + 245,237,230,236,229,120,128, 1, 52,229,227,249,242,233,236,236, + 233, 99,128, 4, 8,232,229,232,225,242,237,229,238,233,225,110, + 128, 5, 75,237,239,238,239,243,240,225,227,101,128,255, 42,243, + 237,225,236,108,128,247,106, 75,140, 0, 75, 15,115, 15,125, 15, + 135, 16, 18, 16, 65, 16, 76, 16,106, 16,143, 16,156, 16,168, 16, + 180, 16,208,194,243,241,245,225,242,101,128, 51,133,203,243,241, + 245,225,242,101,128, 51,205, 97, 7, 15,151, 15,169, 15,191, 15, + 211, 15,226, 15,232, 15,249,226,225,243,232,235,233,242,227,249, + 242,233,236,236,233, 99,128, 4,160, 99, 2, 15,175, 15,181,245, + 244,101,128, 30, 48,249,242,233,236,236,233, 99,128, 4, 26,228, + 229,243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99, + 128, 4,154,232,239,239,235,227,249,242,233,236,236,233, 99,128, + 4,195,240,240, 97,128, 3,154,243,244,242,239,235,229,227,249, + 242,233,236,236,233, 99,128, 4,158,246,229,242,244,233,227,225, + 236,243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, + 4,156, 99, 4, 16, 28, 16, 35, 16, 44, 16, 52,225,242,239,110, + 128, 1,232,229,228,233,236,236, 97,128, 1, 54,233,242,227,236, + 101,128, 36,192,239,237,237,225,225,227,227,229,238,116,128, 1, + 54,228,239,244,226,229,236,239,119,128, 30, 50,101, 2, 16, 82, + 16, 94,232,225,242,237,229,238,233,225,110,128, 5, 84,238,225, + 242,237,229,238,233,225,110,128, 5, 63,104, 3, 16,114, 16,126, + 16,137,225,227,249,242,233,236,236,233, 99,128, 4, 37,229,233, + 227,239,240,244,233, 99,128, 3,230,239,239,107,128, 1,152,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 12,236,233,238,229, + 226,229,236,239,119,128, 30, 52,237,239,238,239,243,240,225,227, + 101,128,255, 43,239,240,240, 97, 2, 16,189, 16,200,227,249,242, + 233,236,236,233, 99,128, 4,128,231,242,229,229,107,128, 3,222, + 115, 2, 16,214, 16,226,233,227,249,242,233,236,236,233, 99,128, + 4,110,237,225,236,108,128,247,107, 76,138, 0, 76, 17, 1, 17, + 5, 17, 9, 17, 29, 17, 95, 17,133, 17,147, 17,165, 17,177, 17, + 189, 74,128, 1,199, 76,128,246,191, 97, 2, 17, 15, 17, 22,227, + 245,244,101,128, 1, 57,237,226,228, 97,128, 3,155, 99, 4, 17, + 39, 17, 46, 17, 55, 17, 82,225,242,239,110,128, 1, 61,229,228, + 233,236,236, 97,128, 1, 59,233,242, 99, 2, 17, 63, 17, 68,236, + 101,128, 36,193,245,237,230,236,229,248,226,229,236,239,119,128, + 30, 60,239,237,237,225,225,227,227,229,238,116,128, 1, 59,228, + 239,116,130, 1, 63, 17,105, 17,114,225,227,227,229,238,116,128, + 1, 63,226,229,236,239,119,129, 30, 54, 17,124,237,225,227,242, + 239,110,128, 30, 56,233,247,238,225,242,237,229,238,233,225,110, + 128, 5, 60,106,129, 1,200, 17,153,229,227,249,242,233,236,236, + 233, 99,128, 4, 9,236,233,238,229,226,229,236,239,119,128, 30, + 58,237,239,238,239,243,240,225,227,101,128,255, 44,115, 2, 17, + 195, 17,212,236,225,243,104,129, 1, 65, 17,204,243,237,225,236, + 108,128,246,249,237,225,236,108,128,247,108, 77,137, 0, 77, 17, + 241, 17,251, 18, 24, 18, 33, 18, 58, 18, 71, 18, 83, 18, 91, 18, + 100,194,243,241,245,225,242,101,128, 51,134,225, 99, 2, 18, 2, + 18, 18,242,239,110,129,246,208, 18, 10,243,237,225,236,108,128, + 247,175,245,244,101,128, 30, 62,227,233,242,227,236,101,128, 36, + 194,228,239,116, 2, 18, 41, 18, 50,225,227,227,229,238,116,128, + 30, 64,226,229,236,239,119,128, 30, 66,229,238,225,242,237,229, + 238,233,225,110,128, 5, 68,237,239,238,239,243,240,225,227,101, + 128,255, 45,243,237,225,236,108,128,247,109,244,245,242,238,229, + 100,128, 1,156,117,128, 3,156, 78,141, 0, 78, 18,134, 18,138, + 18,146, 18,212, 18,237, 18,248, 19, 3, 19, 21, 19, 33, 19, 45, + 19, 58, 19, 66, 19, 84, 74,128, 1,202,225,227,245,244,101,128, + 1, 67, 99, 4, 18,156, 18,163, 18,172, 18,199,225,242,239,110, + 128, 1, 71,229,228,233,236,236, 97,128, 1, 69,233,242, 99, 2, + 18,180, 18,185,236,101,128, 36,195,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 74,239,237,237,225,225,227,227,229,238, + 116,128, 1, 69,228,239,116, 2, 18,220, 18,229,225,227,227,229, + 238,116,128, 30, 68,226,229,236,239,119,128, 30, 70,232,239,239, + 235,236,229,230,116,128, 1,157,233,238,229,242,239,237,225,110, + 128, 33,104,106,129, 1,203, 19, 9,229,227,249,242,233,236,236, + 233, 99,128, 4, 10,236,233,238,229,226,229,236,239,119,128, 30, + 72,237,239,238,239,243,240,225,227,101,128,255, 46,239,247,225, + 242,237,229,238,233,225,110,128, 5, 70,243,237,225,236,108,128, + 247,110,244,233,236,228,101,129, 0,209, 19, 76,243,237,225,236, + 108,128,247,241,117,128, 3,157, 79,141, 0, 79, 19,118, 19,132, + 19,150, 19,203, 20, 78, 20,152, 20,187, 21, 48, 21, 69, 21,213, + 21,223, 21,254, 22, 53, 69,129, 1, 82, 19,124,243,237,225,236, + 108,128,246,250,225,227,245,244,101,129, 0,211, 19,142,243,237, + 225,236,108,128,247,243, 98, 2, 19,156, 19,196,225,242,242,229, + 100, 2, 19,166, 19,177,227,249,242,233,236,236,233, 99,128, 4, + 232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,234,242,229,246,101,128, 1, 78, 99, 4, 19,213, 19, + 220, 19,235, 20, 68,225,242,239,110,128, 1,209,229,238,244,229, + 242,229,228,244,233,236,228,101,128, 1,159,233,242, 99, 2, 19, + 243, 19,248,236,101,128, 36,196,245,237,230,236,229,120,134, 0, + 212, 20, 13, 20, 21, 20, 32, 20, 40, 20, 52, 20, 60,225,227,245, + 244,101,128, 30,208,228,239,244,226,229,236,239,119,128, 30,216, + 231,242,225,246,101,128, 30,210,232,239,239,235,225,226,239,246, + 101,128, 30,212,243,237,225,236,108,128,247,244,244,233,236,228, + 101,128, 30,214,249,242,233,236,236,233, 99,128, 4, 30,100, 3, + 20, 86, 20,109, 20,142,226,108, 2, 20, 93, 20,101,225,227,245, + 244,101,128, 1, 80,231,242,225,246,101,128, 2, 12,233,229,242, + 229,243,233,115,130, 0,214, 20,123, 20,134,227,249,242,233,236, + 236,233, 99,128, 4,230,243,237,225,236,108,128,247,246,239,244, + 226,229,236,239,119,128, 30,204,103, 2, 20,158, 20,170,239,238, + 229,235,243,237,225,236,108,128,246,251,242,225,246,101,129, 0, + 210, 20,179,243,237,225,236,108,128,247,242,104, 4, 20,197, 20, + 208, 20,212, 21, 34,225,242,237,229,238,233,225,110,128, 5, 85, + 109,128, 33, 38,111, 2, 20,218, 20,228,239,235,225,226,239,246, + 101,128, 30,206,242,110,133, 1,160, 20,243, 20,251, 21, 6, 21, + 14, 21, 26,225,227,245,244,101,128, 30,218,228,239,244,226,229, + 236,239,119,128, 30,226,231,242,225,246,101,128, 30,220,232,239, + 239,235,225,226,239,246,101,128, 30,222,244,233,236,228,101,128, + 30,224,245,238,231,225,242,245,237,236,225,245,116,128, 1, 80, + 105,129, 1,162, 21, 54,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 14,109, 4, 21, 79, 21,107, 21,184, 21,202,225, + 227,242,239,110,130, 1, 76, 21, 91, 21, 99,225,227,245,244,101, + 128, 30, 82,231,242,225,246,101,128, 30, 80,229,231, 97,132, 33, + 38, 21,121, 21,132, 21,140, 21,156,227,249,242,233,236,236,233, + 99,128, 4, 96,231,242,229,229,107,128, 3,169,242,239,245,238, + 228,227,249,242,233,236,236,233, 99,128, 4,122,116, 2, 21,162, + 21,177,233,244,236,239,227,249,242,233,236,236,233, 99,128, 4, + 124,239,238,239,115,128, 3,143,233,227,242,239,110,129, 3,159, + 21,194,244,239,238,239,115,128, 3,140,239,238,239,243,240,225, + 227,101,128,255, 47,238,229,242,239,237,225,110,128, 33, 96,111, + 2, 21,229, 21,248,231,239,238,229,107,129, 1,234, 21,239,237, + 225,227,242,239,110,128, 1,236,240,229,110,128, 1,134,115, 3, + 22, 6, 22, 33, 22, 40,236,225,243,104,130, 0,216, 22, 17, 22, + 25,225,227,245,244,101,128, 1,254,243,237,225,236,108,128,247, + 248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245, + 244,101,128, 1,254,116, 2, 22, 59, 22, 70,227,249,242,233,236, + 236,233, 99,128, 4,126,233,236,228,101,131, 0,213, 22, 83, 22, + 91, 22,102,225,227,245,244,101,128, 30, 76,228,233,229,242,229, + 243,233,115,128, 30, 78,243,237,225,236,108,128,247,245, 80,136, + 0, 80, 22,130, 22,138, 22,147, 22,159, 22,211, 22,227, 22,246, + 23, 2,225,227,245,244,101,128, 30, 84,227,233,242,227,236,101, + 128, 36,197,228,239,244,225,227,227,229,238,116,128, 30, 86,101, + 3, 22,167, 22,178, 22,190,227,249,242,233,236,236,233, 99,128, + 4, 31,232,225,242,237,229,238,233,225,110,128, 5, 74,237,233, + 228,228,236,229,232,239,239,235,227,249,242,233,236,236,233, 99, + 128, 4,166,104, 2, 22,217, 22,221,105,128, 3,166,239,239,107, + 128, 1,164,105,129, 3,160, 22,233,247,242,225,242,237,229,238, + 233,225,110,128, 5, 83,237,239,238,239,243,240,225,227,101,128, + 255, 48,115, 2, 23, 8, 23, 25,105,129, 3,168, 23, 14,227,249, + 242,233,236,236,233, 99,128, 4,112,237,225,236,108,128,247,112, + 81,131, 0, 81, 23, 42, 23, 51, 23, 63,227,233,242,227,236,101, + 128, 36,198,237,239,238,239,243,240,225,227,101,128,255, 49,243, + 237,225,236,108,128,247,113, 82,138, 0, 82, 23, 95, 23,119, 23, + 166, 23,217, 23,230, 23,240, 23,245, 24, 19, 24, 31, 24, 43, 97, + 2, 23,101, 23,112,225,242,237,229,238,233,225,110,128, 5, 76, + 227,245,244,101,128, 1, 84, 99, 4, 23,129, 23,136, 23,145, 23, + 153,225,242,239,110,128, 1, 88,229,228,233,236,236, 97,128, 1, + 86,233,242,227,236,101,128, 36,199,239,237,237,225,225,227,227, + 229,238,116,128, 1, 86,100, 2, 23,172, 23,182,226,236,231,242, + 225,246,101,128, 2, 16,239,116, 2, 23,189, 23,198,225,227,227, + 229,238,116,128, 30, 88,226,229,236,239,119,129, 30, 90, 23,208, + 237,225,227,242,239,110,128, 30, 92,229,232,225,242,237,229,238, + 233,225,110,128, 5, 80,230,242,225,235,244,245,114,128, 33, 28, + 232,111,128, 3,161,233,110, 2, 23,252, 24, 5,231,243,237,225, + 236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101, + 128, 2, 18,236,233,238,229,226,229,236,239,119,128, 30, 94,237, + 239,238,239,243,240,225,227,101,128,255, 50,243,237,225,236,108, + 129,247,114, 24, 53,233,238,246,229,242,244,229,100,129, 2,129, + 24, 66,243,245,240,229,242,233,239,114,128, 2,182, 83,139, 0, + 83, 24,103, 26, 17, 26, 55, 26,182, 26,221, 26,250, 27, 84, 27, + 105, 27,117, 27,135, 27,143, 70, 6, 24,117, 24,209, 24,241, 25, + 77, 25,119, 25,221, 48, 9, 24,137, 24,145, 24,153, 24,161, 24, + 169, 24,177, 24,185, 24,193, 24,201,177,176,176,176, 48,128, 37, + 12,178,176,176,176, 48,128, 37, 20,179,176,176,176, 48,128, 37, + 16,180,176,176,176, 48,128, 37, 24,181,176,176,176, 48,128, 37, + 60,182,176,176,176, 48,128, 37, 44,183,176,176,176, 48,128, 37, + 52,184,176,176,176, 48,128, 37, 28,185,176,176,176, 48,128, 37, + 36, 49, 3, 24,217, 24,225, 24,233,176,176,176,176, 48,128, 37, + 0,177,176,176,176, 48,128, 37, 2,185,176,176,176, 48,128, 37, + 97, 50, 9, 25, 5, 25, 13, 25, 21, 25, 29, 25, 37, 25, 45, 25, + 53, 25, 61, 25, 69,176,176,176,176, 48,128, 37, 98,177,176,176, + 176, 48,128, 37, 86,178,176,176,176, 48,128, 37, 85,179,176,176, + 176, 48,128, 37, 99,180,176,176,176, 48,128, 37, 81,181,176,176, + 176, 48,128, 37, 87,182,176,176,176, 48,128, 37, 93,183,176,176, + 176, 48,128, 37, 92,184,176,176,176, 48,128, 37, 91, 51, 4, 25, + 87, 25, 95, 25,103, 25,111,182,176,176,176, 48,128, 37, 94,183, + 176,176,176, 48,128, 37, 95,184,176,176,176, 48,128, 37, 90,185, + 176,176,176, 48,128, 37, 84, 52, 10, 25,141, 25,149, 25,157, 25, + 165, 25,173, 25,181, 25,189, 25,197, 25,205, 25,213,176,176,176, + 176, 48,128, 37,105,177,176,176,176, 48,128, 37,102,178,176,176, + 176, 48,128, 37, 96,179,176,176,176, 48,128, 37, 80,180,176,176, + 176, 48,128, 37,108,181,176,176,176, 48,128, 37,103,182,176,176, + 176, 48,128, 37,104,183,176,176,176, 48,128, 37,100,184,176,176, + 176, 48,128, 37,101,185,176,176,176, 48,128, 37, 89, 53, 5, 25, + 233, 25,241, 25,249, 26, 1, 26, 9,176,176,176,176, 48,128, 37, + 88,177,176,176,176, 48,128, 37, 82,178,176,176,176, 48,128, 37, + 83,179,176,176,176, 48,128, 37,107,180,176,176,176, 48,128, 37, + 106, 97, 2, 26, 23, 26, 44,227,245,244,101,129, 1, 90, 26, 32, + 228,239,244,225,227,227,229,238,116,128, 30,100,237,240,233,231, + 242,229,229,107,128, 3,224, 99, 5, 26, 67, 26, 98, 26,107, 26, + 147, 26,169,225,242,239,110,130, 1, 96, 26, 78, 26, 90,228,239, + 244,225,227,227,229,238,116,128, 30,102,243,237,225,236,108,128, + 246,253,229,228,233,236,236, 97,128, 1, 94,232,247, 97,130, 1, + 143, 26,117, 26,128,227,249,242,233,236,236,233, 99,128, 4,216, + 228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99, + 128, 4,218,233,242, 99, 2, 26,155, 26,160,236,101,128, 36,200, + 245,237,230,236,229,120,128, 1, 92,239,237,237,225,225,227,227, + 229,238,116,128, 2, 24,228,239,116, 2, 26,190, 26,199,225,227, + 227,229,238,116,128, 30, 96,226,229,236,239,119,129, 30, 98, 26, + 209,228,239,244,225,227,227,229,238,116,128, 30,104,101, 2, 26, + 227, 26,239,232,225,242,237,229,238,233,225,110,128, 5, 77,246, + 229,238,242,239,237,225,110,128, 33,102,104, 5, 27, 6, 27, 34, + 27, 48, 27, 59, 27, 72, 97, 2, 27, 12, 27, 23,225,242,237,229, + 238,233,225,110,128, 5, 71,227,249,242,233,236,236,233, 99,128, + 4, 40,227,232,225,227,249,242,233,236,236,233, 99,128, 4, 41, + 229,233,227,239,240,244,233, 99,128, 3,226,232,225,227,249,242, + 233,236,236,233, 99,128, 4,186,233,237,225,227,239,240,244,233, + 99,128, 3,236,105, 2, 27, 90, 27, 96,231,237, 97,128, 3,163, + 248,242,239,237,225,110,128, 33,101,237,239,238,239,243,240,225, + 227,101,128,255, 51,239,230,244,243,233,231,238,227,249,242,233, + 236,236,233, 99,128, 4, 44,243,237,225,236,108,128,247,115,244, + 233,231,237,225,231,242,229,229,107,128, 3,218, 84,141, 0, 84, + 27,186, 27,191, 27,197, 28, 7, 28, 32, 28, 96, 28,147, 28,177, + 28,189, 28,201, 28,246, 29, 6, 29, 46,225,117,128, 3,164,226, + 225,114,128, 1,102, 99, 4, 27,207, 27,214, 27,223, 27,250,225, + 242,239,110,128, 1,100,229,228,233,236,236, 97,128, 1, 98,233, + 242, 99, 2, 27,231, 27,236,236,101,128, 36,201,245,237,230,236, + 229,248,226,229,236,239,119,128, 30,112,239,237,237,225,225,227, + 227,229,238,116,128, 1, 98,228,239,116, 2, 28, 15, 28, 24,225, + 227,227,229,238,116,128, 30,106,226,229,236,239,119,128, 30,108, + 101, 4, 28, 42, 28, 53, 28, 73, 28, 82,227,249,242,233,236,236, + 233, 99,128, 4, 34,228,229,243,227,229,238,228,229,242,227,249, + 242,233,236,236,233, 99,128, 4,172,238,242,239,237,225,110,128, + 33,105,244,243,229,227,249,242,233,236,236,233, 99,128, 4,180, + 104, 3, 28,104, 28,110, 28,136,229,244, 97,128, 3,152,111, 2, + 28,116, 28,121,239,107,128, 1,172,242,110,129, 0,222, 28,128, + 243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110, + 128, 33, 98,105, 2, 28,153, 28,164,236,228,229,243,237,225,236, + 108,128,246,254,247,238,225,242,237,229,238,233,225,110,128, 5, + 79,236,233,238,229,226,229,236,239,119,128, 30,110,237,239,238, + 239,243,240,225,227,101,128,255, 52,111, 2, 28,207, 28,218,225, + 242,237,229,238,233,225,110,128, 5, 57,238,101, 3, 28,227, 28, + 234, 28,240,230,233,246,101,128, 1,188,243,233,120,128, 1,132, + 244,247,111,128, 1,167,242,229,244,242,239,230,236,229,248,232, + 239,239,107,128, 1,174,115, 3, 29, 14, 29, 26, 29, 39,229,227, + 249,242,233,236,236,233, 99,128, 4, 38,232,229,227,249,242,233, + 236,236,233, 99,128, 4, 11,237,225,236,108,128,247,116,119, 2, + 29, 52, 29, 64,229,236,246,229,242,239,237,225,110,128, 33,107, + 239,242,239,237,225,110,128, 33, 97, 85,142, 0, 85, 29,105, 29, + 123, 29,131, 29,198, 30, 69, 30, 87, 30,198, 30,214, 30,226, 31, + 21, 31, 30, 31,142, 31,149, 31,219,225,227,245,244,101,129, 0, + 218, 29,115,243,237,225,236,108,128,247,250,226,242,229,246,101, + 128, 1,108, 99, 3, 29,139, 29,146, 29,188,225,242,239,110,128, + 1,211,233,242, 99, 2, 29,154, 29,159,236,101,128, 36,202,245, + 237,230,236,229,120,130, 0,219, 29,172, 29,180,226,229,236,239, + 119,128, 30,118,243,237,225,236,108,128,247,251,249,242,233,236, + 236,233, 99,128, 4, 35,100, 3, 29,206, 29,229, 30, 59,226,108, + 2, 29,213, 29,221,225,227,245,244,101,128, 1,112,231,242,225, + 246,101,128, 2, 20,233,229,242,229,243,233,115,134, 0,220, 29, + 251, 30, 3, 30, 11, 30, 34, 30, 42, 30, 51,225,227,245,244,101, + 128, 1,215,226,229,236,239,119,128, 30,114, 99, 2, 30, 17, 30, + 24,225,242,239,110,128, 1,217,249,242,233,236,236,233, 99,128, + 4,240,231,242,225,246,101,128, 1,219,237,225,227,242,239,110, + 128, 1,213,243,237,225,236,108,128,247,252,239,244,226,229,236, + 239,119,128, 30,228,231,242,225,246,101,129, 0,217, 30, 79,243, + 237,225,236,108,128,247,249,104, 2, 30, 93, 30,171,111, 2, 30, + 99, 30,109,239,235,225,226,239,246,101,128, 30,230,242,110,133, + 1,175, 30,124, 30,132, 30,143, 30,151, 30,163,225,227,245,244, + 101,128, 30,232,228,239,244,226,229,236,239,119,128, 30,240,231, + 242,225,246,101,128, 30,234,232,239,239,235,225,226,239,246,101, + 128, 30,236,244,233,236,228,101,128, 30,238,245,238,231,225,242, + 245,237,236,225,245,116,129, 1,112, 30,187,227,249,242,233,236, + 236,233, 99,128, 4,242,233,238,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 22,235,227,249,242,233,236,236,233, 99,128, + 4,120,109, 2, 30,232, 31, 10,225,227,242,239,110,130, 1,106, + 30,244, 30,255,227,249,242,233,236,236,233, 99,128, 4,238,228, + 233,229,242,229,243,233,115,128, 30,122,239,238,239,243,240,225, + 227,101,128,255, 53,239,231,239,238,229,107,128, 1,114,240,243, + 233,236,239,110,133, 3,165, 31, 49, 31, 53, 31, 90, 31,121, 31, + 134, 49,128, 3,210, 97, 2, 31, 59, 31, 81,227,245,244,229,232, + 239,239,235,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 211,230,242,233,227,225,110,128, 1,177,228,233,229,242,229,243, + 233,115,129, 3,171, 31,103,232,239,239,235,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,212,232,239,239,235,243,249,237, + 226,239,108,128, 3,210,244,239,238,239,115,128, 3,142,242,233, + 238,103,128, 1,110,115, 3, 31,157, 31,172, 31,179,232,239,242, + 244,227,249,242,233,236,236,233, 99,128, 4, 14,237,225,236,108, + 128,247,117,244,242,225,233,231,232,116, 2, 31,191, 31,202,227, + 249,242,233,236,236,233, 99,128, 4,174,243,244,242,239,235,229, + 227,249,242,233,236,236,233, 99,128, 4,176,244,233,236,228,101, + 130, 1,104, 31,231, 31,239,225,227,245,244,101,128, 30,120,226, + 229,236,239,119,128, 30,116, 86,136, 0, 86, 32, 11, 32, 20, 32, + 31, 32, 60, 32, 67, 32, 79, 32, 91, 32, 99,227,233,242,227,236, + 101,128, 36,203,228,239,244,226,229,236,239,119,128, 30,126,101, + 2, 32, 37, 32, 48,227,249,242,233,236,236,233, 99,128, 4, 18, + 247,225,242,237,229,238,233,225,110,128, 5, 78,232,239,239,107, + 128, 1,178,237,239,238,239,243,240,225,227,101,128,255, 54,239, + 225,242,237,229,238,233,225,110,128, 5, 72,243,237,225,236,108, + 128,247,118,244,233,236,228,101,128, 30,124, 87,134, 0, 87, 32, + 123, 32,131, 32,154, 32,194, 32,202, 32,214,225,227,245,244,101, + 128, 30,130,227,233,242, 99, 2, 32,140, 32,145,236,101,128, 36, + 204,245,237,230,236,229,120,128, 1,116,100, 2, 32,160, 32,170, + 233,229,242,229,243,233,115,128, 30,132,239,116, 2, 32,177, 32, + 186,225,227,227,229,238,116,128, 30,134,226,229,236,239,119,128, + 30,136,231,242,225,246,101,128, 30,128,237,239,238,239,243,240, + 225,227,101,128,255, 55,243,237,225,236,108,128,247,119, 88,134, + 0, 88, 32,238, 32,247, 33, 18, 33, 31, 33, 35, 33, 47,227,233, + 242,227,236,101,128, 36,205,100, 2, 32,253, 33, 7,233,229,242, + 229,243,233,115,128, 30,140,239,244,225,227,227,229,238,116,128, + 30,138,229,232,225,242,237,229,238,233,225,110,128, 5, 61,105, + 128, 3,158,237,239,238,239,243,240,225,227,101,128,255, 56,243, + 237,225,236,108,128,247,120, 89,139, 0, 89, 33, 81, 33,116, 33, + 139, 33,189, 33,228, 33,236, 33,253, 34, 40, 34, 52, 34, 60, 34, + 68, 97, 2, 33, 87, 33,104,227,245,244,101,129, 0,221, 33, 96, + 243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233, + 99,128, 4, 98,227,233,242, 99, 2, 33,125, 33,130,236,101,128, + 36,206,245,237,230,236,229,120,128, 1,118,100, 2, 33,145, 33, + 165,233,229,242,229,243,233,115,129, 1,120, 33,157,243,237,225, + 236,108,128,247,255,239,116, 2, 33,172, 33,181,225,227,227,229, + 238,116,128, 30,142,226,229,236,239,119,128, 30,244,229,114, 2, + 33,196, 33,208,233,227,249,242,233,236,236,233, 99,128, 4, 43, + 245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,248,231,242,225,246,101,128, 30,242,232,239,239,107, + 129, 1,179, 33,245,225,226,239,246,101,128, 30,246,105, 3, 34, + 5, 34, 16, 34, 27,225,242,237,229,238,233,225,110,128, 5, 69, + 227,249,242,233,236,236,233, 99,128, 4, 7,247,238,225,242,237, + 229,238,233,225,110,128, 5, 82,237,239,238,239,243,240,225,227, + 101,128,255, 57,243,237,225,236,108,128,247,121,244,233,236,228, + 101,128, 30,248,245,115, 2, 34, 75, 34,113,226,233,103, 2, 34, + 83, 34, 94,227,249,242,233,236,236,233, 99,128, 4,106,233,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 108,236,233,244,244,236,101, 2, 34,124, 34,135,227,249,242,233, + 236,236,233, 99,128, 4,102,233,239,244,233,230,233,229,228,227, + 249,242,233,236,236,233, 99,128, 4,104, 90,136, 0, 90, 34,174, + 34,198, 34,243, 35, 14, 35, 81, 35,173, 35,185, 35,197, 97, 2, + 34,180, 34,191,225,242,237,229,238,233,225,110,128, 5, 54,227, + 245,244,101,128, 1,121, 99, 2, 34,204, 34,221,225,242,239,110, + 129, 1,125, 34,213,243,237,225,236,108,128,246,255,233,242, 99, + 2, 34,229, 34,234,236,101,128, 36,207,245,237,230,236,229,120, + 128, 30,144,228,239,116,130, 1,123, 34,253, 35, 6,225,227,227, + 229,238,116,128, 1,123,226,229,236,239,119,128, 30,146,101, 3, + 35, 22, 35, 33, 35, 76,227,249,242,233,236,236,233, 99,128, 4, + 23,100, 2, 35, 39, 35, 58,229,243,227,229,238,228,229,242,227, + 249,242,233,236,236,233, 99,128, 4,152,233,229,242,229,243,233, + 243,227,249,242,233,236,236,233, 99,128, 4,222,244, 97,128, 3, + 150,232,101, 4, 35, 92, 35,103, 35,119, 35,130,225,242,237,229, + 238,233,225,110,128, 5, 58,226,242,229,246,229,227,249,242,233, + 236,236,233, 99,128, 4,193,227,249,242,233,236,236,233, 99,128, + 4, 22,100, 2, 35,136, 35,155,229,243,227,229,238,228,229,242, + 227,249,242,233,236,236,233, 99,128, 4,150,233,229,242,229,243, + 233,243,227,249,242,233,236,236,233, 99,128, 4,220,236,233,238, + 229,226,229,236,239,119,128, 30,148,237,239,238,239,243,240,225, + 227,101,128,255, 58,115, 2, 35,203, 35,210,237,225,236,108,128, + 247,122,244,242,239,235,101,128, 1,181, 97,158, 0, 97, 36, 26, + 38,154, 39, 4, 39, 68, 39,132, 39,196, 40, 4, 40, 68, 40,126, + 40,190, 41, 70, 41,217, 42,137, 42,237, 43, 17, 49,192, 49,229, + 50, 0, 50,225, 51, 7, 52, 96, 52,168, 53,123, 53,132, 54, 5, + 56, 13, 57, 3, 57, 50, 57,201, 57,215, 49,138, 39, 1, 36, 50, + 36,114, 36,154, 36,218, 37, 26, 37, 90, 37,154, 37,218, 38, 26, + 38, 90, 48,138, 39, 33, 36, 74, 36, 78, 36, 82, 36, 86, 36, 90, + 36, 94, 36, 98, 36,102, 36,106, 36,110, 48,128, 39, 94, 49,128, + 39, 97, 50,128, 39, 98, 51,128, 39, 99, 52,128, 39,100, 53,128, + 39, 16, 54,128, 39,101, 55,128, 39,102, 56,128, 39,103, 57,128, + 38, 96, 49,134, 38, 27, 36,130, 36,134, 36,138, 36,142, 36,146, + 36,150, 48,128, 38,101, 49,128, 38,102, 50,128, 38, 99, 55,128, + 39, 9, 56,128, 39, 8, 57,128, 39, 7, 50,138, 38, 30, 36,178, + 36,182, 36,186, 36,190, 36,194, 36,198, 36,202, 36,206, 36,210, + 36,214, 48,128, 36, 96, 49,128, 36, 97, 50,128, 36, 98, 51,128, + 36, 99, 52,128, 36,100, 53,128, 36,101, 54,128, 36,102, 55,128, + 36,103, 56,128, 36,104, 57,128, 36,105, 51,138, 39, 12, 36,242, + 36,246, 36,250, 36,254, 37, 2, 37, 6, 37, 10, 37, 14, 37, 18, + 37, 22, 48,128, 39,118, 49,128, 39,119, 50,128, 39,120, 51,128, + 39,121, 52,128, 39,122, 53,128, 39,123, 54,128, 39,124, 55,128, + 39,125, 56,128, 39,126, 57,128, 39,127, 52,138, 39, 13, 37, 50, + 37, 54, 37, 58, 37, 62, 37, 66, 37, 70, 37, 74, 37, 78, 37, 82, + 37, 86, 48,128, 39,128, 49,128, 39,129, 50,128, 39,130, 51,128, + 39,131, 52,128, 39,132, 53,128, 39,133, 54,128, 39,134, 55,128, + 39,135, 56,128, 39,136, 57,128, 39,137, 53,138, 39, 14, 37,114, + 37,118, 37,122, 37,126, 37,130, 37,134, 37,138, 37,142, 37,146, + 37,150, 48,128, 39,138, 49,128, 39,139, 50,128, 39,140, 51,128, + 39,141, 52,128, 39,142, 53,128, 39,143, 54,128, 39,144, 55,128, + 39,145, 56,128, 39,146, 57,128, 39,147, 54,138, 39, 15, 37,178, + 37,182, 37,186, 37,190, 37,194, 37,198, 37,202, 37,206, 37,210, + 37,214, 48,128, 39,148, 49,128, 33,146, 50,128, 39,163, 51,128, + 33,148, 52,128, 33,149, 53,128, 39,153, 54,128, 39,155, 55,128, + 39,156, 56,128, 39,157, 57,128, 39,158, 55,138, 39, 17, 37,242, + 37,246, 37,250, 37,254, 38, 2, 38, 6, 38, 10, 38, 14, 38, 18, + 38, 22, 48,128, 39,159, 49,128, 39,160, 50,128, 39,161, 51,128, + 39,162, 52,128, 39,164, 53,128, 39,165, 54,128, 39,166, 55,128, + 39,167, 56,128, 39,168, 57,128, 39,169, 56,138, 39, 18, 38, 50, + 38, 54, 38, 58, 38, 62, 38, 66, 38, 70, 38, 74, 38, 78, 38, 82, + 38, 86, 48,128, 39,171, 49,128, 39,173, 50,128, 39,175, 51,128, + 39,178, 52,128, 39,179, 53,128, 39,181, 54,128, 39,184, 55,128, + 39,186, 56,128, 39,187, 57,128, 39,188, 57,138, 39, 19, 38,114, + 38,118, 38,122, 38,126, 38,130, 38,134, 38,138, 38,142, 38,146, + 38,150, 48,128, 39,189, 49,128, 39,190, 50,128, 39,154, 51,128, + 39,170, 52,128, 39,182, 53,128, 39,185, 54,128, 39,152, 55,128, + 39,180, 56,128, 39,183, 57,128, 39,172, 50,138, 39, 2, 38,178, + 38,224, 38,228, 38,232, 38,236, 38,240, 38,244, 38,248, 38,252, + 39, 0, 48,135, 39, 20, 38,196, 38,200, 38,204, 38,208, 38,212, + 38,216, 38,220, 48,128, 39,174, 49,128, 39,177, 50,128, 39, 3, + 51,128, 39, 80, 52,128, 39, 82, 53,128, 39,110, 54,128, 39,112, + 49,128, 39, 21, 50,128, 39, 22, 51,128, 39, 23, 52,128, 39, 24, + 53,128, 39, 25, 54,128, 39, 26, 55,128, 39, 27, 56,128, 39, 28, + 57,128, 39, 34, 51,138, 39, 4, 39, 28, 39, 32, 39, 36, 39, 40, + 39, 44, 39, 48, 39, 52, 39, 56, 39, 60, 39, 64, 48,128, 39, 35, + 49,128, 39, 36, 50,128, 39, 37, 51,128, 39, 38, 52,128, 39, 39, + 53,128, 38, 5, 54,128, 39, 41, 55,128, 39, 42, 56,128, 39, 43, + 57,128, 39, 44, 52,138, 38, 14, 39, 92, 39, 96, 39,100, 39,104, + 39,108, 39,112, 39,116, 39,120, 39,124, 39,128, 48,128, 39, 45, + 49,128, 39, 46, 50,128, 39, 47, 51,128, 39, 48, 52,128, 39, 49, + 53,128, 39, 50, 54,128, 39, 51, 55,128, 39, 52, 56,128, 39, 53, + 57,128, 39, 54, 53,138, 39, 6, 39,156, 39,160, 39,164, 39,168, + 39,172, 39,176, 39,180, 39,184, 39,188, 39,192, 48,128, 39, 55, + 49,128, 39, 56, 50,128, 39, 57, 51,128, 39, 58, 52,128, 39, 59, + 53,128, 39, 60, 54,128, 39, 61, 55,128, 39, 62, 56,128, 39, 63, + 57,128, 39, 64, 54,138, 39, 29, 39,220, 39,224, 39,228, 39,232, + 39,236, 39,240, 39,244, 39,248, 39,252, 40, 0, 48,128, 39, 65, + 49,128, 39, 66, 50,128, 39, 67, 51,128, 39, 68, 52,128, 39, 69, + 53,128, 39, 70, 54,128, 39, 71, 55,128, 39, 72, 56,128, 39, 73, + 57,128, 39, 74, 55,138, 39, 30, 40, 28, 40, 32, 40, 36, 40, 40, + 40, 44, 40, 48, 40, 52, 40, 56, 40, 60, 40, 64, 48,128, 39, 75, + 49,128, 37,207, 50,128, 39, 77, 51,128, 37,160, 52,128, 39, 79, + 53,128, 39, 81, 54,128, 37,178, 55,128, 37,188, 56,128, 37,198, + 57,128, 39, 86, 56,137, 39, 31, 40, 90, 40, 94, 40, 98, 40,102, + 40,106, 40,110, 40,114, 40,118, 40,122, 49,128, 37,215, 50,128, + 39, 88, 51,128, 39, 89, 52,128, 39, 90, 53,128, 39,111, 54,128, + 39,113, 55,128, 39,114, 56,128, 39,115, 57,128, 39,104, 57,138, + 39, 32, 40,150, 40,154, 40,158, 40,162, 40,166, 40,170, 40,174, + 40,178, 40,182, 40,186, 48,128, 39,105, 49,128, 39,108, 50,128, + 39,109, 51,128, 39,106, 52,128, 39,107, 53,128, 39,116, 54,128, + 39,117, 55,128, 39, 91, 56,128, 39, 92, 57,128, 39, 93, 97, 7, + 40,206, 40,216, 40,223, 40,230, 40,255, 41, 15, 41, 26,226,229, + 238,231,225,236,105,128, 9,134,227,245,244,101,128, 0,225,228, + 229,246, 97,128, 9, 6,231,117, 2, 40,237, 40,246,234,225,242, + 225,244,105,128, 10,134,242,237,245,235,232,105,128, 10, 6,237, + 225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 62,242, + 245,243,241,245,225,242,101,128, 51, 3,246,239,247,229,236,243, + 233,231,110, 3, 41, 42, 41, 52, 41, 59,226,229,238,231,225,236, + 105,128, 9,190,228,229,246, 97,128, 9, 62,231,245,234,225,242, + 225,244,105,128, 10,190, 98, 4, 41, 80, 41,121, 41,130, 41,140, + 226,242,229,246,233,225,244,233,239,110, 2, 41, 95, 41,110,237, + 225,242,235,225,242,237,229,238,233,225,110,128, 5, 95,243,233, + 231,238,228,229,246, 97,128, 9,112,229,238,231,225,236,105,128, + 9,133,239,240,239,237,239,230,111,128, 49, 26,242,229,246,101, + 134, 1, 3, 41,159, 41,167, 41,178, 41,189, 41,197, 41,209,225, + 227,245,244,101,128, 30,175,227,249,242,233,236,236,233, 99,128, + 4,209,228,239,244,226,229,236,239,119,128, 30,183,231,242,225, + 246,101,128, 30,177,232,239,239,235,225,226,239,246,101,128, 30, + 179,244,233,236,228,101,128, 30,181, 99, 4, 41,227, 41,234, 42, + 57, 42,127,225,242,239,110,128, 1,206,233,242, 99, 2, 41,242, + 41,247,236,101,128, 36,208,245,237,230,236,229,120,133, 0,226, + 42, 10, 42, 18, 42, 29, 42, 37, 42, 49,225,227,245,244,101,128, + 30,165,228,239,244,226,229,236,239,119,128, 30,173,231,242,225, + 246,101,128, 30,167,232,239,239,235,225,226,239,246,101,128, 30, + 169,244,233,236,228,101,128, 30,171,245,244,101,133, 0,180, 42, + 73, 42, 84, 42,101, 42,108, 42,117,226,229,236,239,247,227,237, + 98,128, 3, 23, 99, 2, 42, 90, 42, 95,237, 98,128, 3, 1,239, + 237, 98,128, 3, 1,228,229,246, 97,128, 9, 84,236,239,247,237, + 239,100,128, 2,207,244,239,238,229,227,237, 98,128, 3, 65,249, + 242,233,236,236,233, 99,128, 4, 48,100, 5, 42,149, 42,159, 42, + 173, 42,179, 42,213,226,236,231,242,225,246,101,128, 2, 1,228, + 225,235,231,245,242,237,245,235,232,105,128, 10,113,229,246, 97, + 128, 9, 5,233,229,242,229,243,233,115,130, 0,228, 42,193, 42, + 204,227,249,242,233,236,236,233, 99,128, 4,211,237,225,227,242, + 239,110,128, 1,223,239,116, 2, 42,220, 42,228,226,229,236,239, + 119,128, 30,161,237,225,227,242,239,110,128, 1,225,101,131, 0, + 230, 42,247, 42,255, 43, 8,225,227,245,244,101,128, 1,253,235, + 239,242,229,225,110,128, 49, 80,237,225,227,242,239,110,128, 1, + 227,230,233,105, 6, 43, 33, 43, 53, 45,246, 45,252, 46, 11, 49, + 111, 48, 2, 43, 39, 43, 46,176,178,176, 56,128, 32, 21,184,185, + 180, 49,128, 32,164,177, 48, 3, 43, 62, 45, 86, 45,221, 48, 9, + 43, 82, 43,102, 43,164, 43,226, 44, 32, 44, 94, 44,156, 44,218, + 45, 24, 49, 3, 43, 90, 43, 94, 43, 98, 55,128, 4, 16, 56,128, + 4, 17, 57,128, 4, 18, 50, 10, 43,124, 43,128, 43,132, 43,136, + 43,140, 43,144, 43,148, 43,152, 43,156, 43,160, 48,128, 4, 19, + 49,128, 4, 20, 50,128, 4, 21, 51,128, 4, 1, 52,128, 4, 22, + 53,128, 4, 23, 54,128, 4, 24, 55,128, 4, 25, 56,128, 4, 26, + 57,128, 4, 27, 51, 10, 43,186, 43,190, 43,194, 43,198, 43,202, + 43,206, 43,210, 43,214, 43,218, 43,222, 48,128, 4, 28, 49,128, + 4, 29, 50,128, 4, 30, 51,128, 4, 31, 52,128, 4, 32, 53,128, + 4, 33, 54,128, 4, 34, 55,128, 4, 35, 56,128, 4, 36, 57,128, + 4, 37, 52, 10, 43,248, 43,252, 44, 0, 44, 4, 44, 8, 44, 12, + 44, 16, 44, 20, 44, 24, 44, 28, 48,128, 4, 38, 49,128, 4, 39, + 50,128, 4, 40, 51,128, 4, 41, 52,128, 4, 42, 53,128, 4, 43, + 54,128, 4, 44, 55,128, 4, 45, 56,128, 4, 46, 57,128, 4, 47, + 53, 10, 44, 54, 44, 58, 44, 62, 44, 66, 44, 70, 44, 74, 44, 78, + 44, 82, 44, 86, 44, 90, 48,128, 4,144, 49,128, 4, 2, 50,128, + 4, 3, 51,128, 4, 4, 52,128, 4, 5, 53,128, 4, 6, 54,128, + 4, 7, 55,128, 4, 8, 56,128, 4, 9, 57,128, 4, 10, 54, 10, + 44,116, 44,120, 44,124, 44,128, 44,132, 44,136, 44,140, 44,144, + 44,148, 44,152, 48,128, 4, 11, 49,128, 4, 12, 50,128, 4, 14, + 51,128,246,196, 52,128,246,197, 53,128, 4, 48, 54,128, 4, 49, + 55,128, 4, 50, 56,128, 4, 51, 57,128, 4, 52, 55, 10, 44,178, + 44,182, 44,186, 44,190, 44,194, 44,198, 44,202, 44,206, 44,210, + 44,214, 48,128, 4, 53, 49,128, 4, 81, 50,128, 4, 54, 51,128, + 4, 55, 52,128, 4, 56, 53,128, 4, 57, 54,128, 4, 58, 55,128, + 4, 59, 56,128, 4, 60, 57,128, 4, 61, 56, 10, 44,240, 44,244, + 44,248, 44,252, 45, 0, 45, 4, 45, 8, 45, 12, 45, 16, 45, 20, + 48,128, 4, 62, 49,128, 4, 63, 50,128, 4, 64, 51,128, 4, 65, + 52,128, 4, 66, 53,128, 4, 67, 54,128, 4, 68, 55,128, 4, 69, + 56,128, 4, 70, 57,128, 4, 71, 57, 10, 45, 46, 45, 50, 45, 54, + 45, 58, 45, 62, 45, 66, 45, 70, 45, 74, 45, 78, 45, 82, 48,128, + 4, 72, 49,128, 4, 73, 50,128, 4, 74, 51,128, 4, 75, 52,128, + 4, 76, 53,128, 4, 77, 54,128, 4, 78, 55,128, 4, 79, 56,128, + 4,145, 57,128, 4, 82, 49, 4, 45, 96, 45,158, 45,163, 45,189, + 48, 10, 45,118, 45,122, 45,126, 45,130, 45,134, 45,138, 45,142, + 45,146, 45,150, 45,154, 48,128, 4, 83, 49,128, 4, 84, 50,128, + 4, 85, 51,128, 4, 86, 52,128, 4, 87, 53,128, 4, 88, 54,128, + 4, 89, 55,128, 4, 90, 56,128, 4, 91, 57,128, 4, 92,177, 48, + 128, 4, 94, 52, 4, 45,173, 45,177, 45,181, 45,185, 53,128, 4, + 15, 54,128, 4, 98, 55,128, 4,114, 56,128, 4,116, 57, 5, 45, + 201, 45,205, 45,209, 45,213, 45,217, 50,128,246,198, 51,128, 4, + 95, 52,128, 4, 99, 53,128, 4,115, 54,128, 4,117, 56, 2, 45, + 227, 45,241, 51, 2, 45,233, 45,237, 49,128,246,199, 50,128,246, + 200,180, 54,128, 4,217,178,185, 57,128, 32, 14,179, 48, 2, 46, + 3, 46, 7, 48,128, 32, 15, 49,128, 32, 13,181, 55, 7, 46, 28, + 46, 98, 47,163, 47,240, 48,197, 49, 34, 49,105, 51, 2, 46, 34, + 46, 48, 56, 2, 46, 40, 46, 44, 49,128, 6,106, 56,128, 6, 12, + 57, 8, 46, 66, 46, 70, 46, 74, 46, 78, 46, 82, 46, 86, 46, 90, + 46, 94, 50,128, 6, 96, 51,128, 6, 97, 52,128, 6, 98, 53,128, + 6, 99, 54,128, 6,100, 55,128, 6,101, 56,128, 6,102, 57,128, + 6,103, 52, 7, 46,114, 46,146, 46,208, 47, 14, 47, 46, 47,102, + 47,158, 48, 5, 46,126, 46,130, 46,134, 46,138, 46,142, 48,128, + 6,104, 49,128, 6,105, 51,128, 6, 27, 55,128, 6, 31, 57,128, + 6, 33, 49, 10, 46,168, 46,172, 46,176, 46,180, 46,184, 46,188, + 46,192, 46,196, 46,200, 46,204, 48,128, 6, 34, 49,128, 6, 35, + 50,128, 6, 36, 51,128, 6, 37, 52,128, 6, 38, 53,128, 6, 39, + 54,128, 6, 40, 55,128, 6, 41, 56,128, 6, 42, 57,128, 6, 43, + 50, 10, 46,230, 46,234, 46,238, 46,242, 46,246, 46,250, 46,254, + 47, 2, 47, 6, 47, 10, 48,128, 6, 44, 49,128, 6, 45, 50,128, + 6, 46, 51,128, 6, 47, 52,128, 6, 48, 53,128, 6, 49, 54,128, + 6, 50, 55,128, 6, 51, 56,128, 6, 52, 57,128, 6, 53, 51, 5, + 47, 26, 47, 30, 47, 34, 47, 38, 47, 42, 48,128, 6, 54, 49,128, + 6, 55, 50,128, 6, 56, 51,128, 6, 57, 52,128, 6, 58, 52, 9, + 47, 66, 47, 70, 47, 74, 47, 78, 47, 82, 47, 86, 47, 90, 47, 94, + 47, 98, 48,128, 6, 64, 49,128, 6, 65, 50,128, 6, 66, 51,128, + 6, 67, 52,128, 6, 68, 53,128, 6, 69, 54,128, 6, 70, 56,128, + 6, 72, 57,128, 6, 73, 53, 9, 47,122, 47,126, 47,130, 47,134, + 47,138, 47,142, 47,146, 47,150, 47,154, 48,128, 6, 74, 49,128, + 6, 75, 50,128, 6, 76, 51,128, 6, 77, 52,128, 6, 78, 53,128, + 6, 79, 54,128, 6, 80, 55,128, 6, 81, 56,128, 6, 82,183, 48, + 128, 6, 71, 53, 3, 47,171, 47,203, 47,235, 48, 5, 47,183, 47, + 187, 47,191, 47,195, 47,199, 53,128, 6,164, 54,128, 6,126, 55, + 128, 6,134, 56,128, 6,152, 57,128, 6,175, 49, 5, 47,215, 47, + 219, 47,223, 47,227, 47,231, 49,128, 6,121, 50,128, 6,136, 51, + 128, 6,145, 52,128, 6,186, 57,128, 6,210,179, 52,128, 6,213, + 54, 7, 48, 0, 48, 5, 48, 10, 48, 15, 48, 53, 48,115, 48,177, + 179, 54,128, 32,170,180, 53,128, 5,190,181, 56,128, 5,195, 54, + 6, 48, 29, 48, 33, 48, 37, 48, 41, 48, 45, 48, 49, 52,128, 5, + 208, 53,128, 5,209, 54,128, 5,210, 55,128, 5,211, 56,128, 5, + 212, 57,128, 5,213, 55, 10, 48, 75, 48, 79, 48, 83, 48, 87, 48, + 91, 48, 95, 48, 99, 48,103, 48,107, 48,111, 48,128, 5,214, 49, + 128, 5,215, 50,128, 5,216, 51,128, 5,217, 52,128, 5,218, 53, + 128, 5,219, 54,128, 5,220, 55,128, 5,221, 56,128, 5,222, 57, + 128, 5,223, 56, 10, 48,137, 48,141, 48,145, 48,149, 48,153, 48, + 157, 48,161, 48,165, 48,169, 48,173, 48,128, 5,224, 49,128, 5, + 225, 50,128, 5,226, 51,128, 5,227, 52,128, 5,228, 53,128, 5, + 229, 54,128, 5,230, 55,128, 5,231, 56,128, 5,232, 57,128, 5, + 233, 57, 3, 48,185, 48,189, 48,193, 48,128, 5,234, 52,128,251, + 42, 53,128,251, 43, 55, 4, 48,207, 48,221, 48,241, 48,246, 48, + 2, 48,213, 48,217, 48,128,251, 75, 53,128,251, 31, 49, 3, 48, + 229, 48,233, 48,237, 54,128, 5,240, 55,128, 5,241, 56,128, 5, + 242,178, 51,128,251, 53, 57, 7, 49, 6, 49, 10, 49, 14, 49, 18, + 49, 22, 49, 26, 49, 30, 51,128, 5,180, 52,128, 5,181, 53,128, + 5,182, 54,128, 5,187, 55,128, 5,184, 56,128, 5,183, 57,128, + 5,176, 56, 3, 49, 42, 49, 86, 49, 91, 48, 7, 49, 58, 49, 62, + 49, 66, 49, 70, 49, 74, 49, 78, 49, 82, 48,128, 5,178, 49,128, + 5,177, 50,128, 5,179, 51,128, 5,194, 52,128, 5,193, 54,128, + 5,185, 55,128, 5,188,179, 57,128, 5,189, 52, 2, 49, 97, 49, + 101, 49,128, 5,191, 50,128, 5,192,185,178, 57,128, 2,188, 54, + 3, 49,119, 49,178, 49,185, 49, 4, 49,129, 49,145, 49,151, 49, + 172, 50, 2, 49,135, 49,140,180, 56,128, 33, 5,184, 57,128, 33, + 19,179,181, 50,128, 33, 22,181, 55, 3, 49,160, 49,164, 49,168, + 51,128, 32, 44, 52,128, 32, 45, 53,128, 32, 46,182,182, 52,128, + 32, 12,179,177,182, 55,128, 6,109,180,185,179, 55,128, 2,189, + 103, 2, 49,198, 49,205,242,225,246,101,128, 0,224,117, 2, 49, + 211, 49,220,234,225,242,225,244,105,128, 10,133,242,237,245,235, + 232,105,128, 10, 5,104, 2, 49,235, 49,245,233,242,225,231,225, + 238, 97,128, 48, 66,239,239,235,225,226,239,246,101,128, 30,163, + 105, 7, 50, 16, 50, 41, 50, 48, 50, 60, 50, 85, 50,101, 50,181, + 98, 2, 50, 22, 50, 31,229,238,231,225,236,105,128, 9,144,239, + 240,239,237,239,230,111,128, 49, 30,228,229,246, 97,128, 9, 16, + 229,227,249,242,233,236,236,233, 99,128, 4,213,231,117, 2, 50, + 67, 50, 76,234,225,242,225,244,105,128, 10,144,242,237,245,235, + 232,105,128, 10, 16,237,225,244,242,225,231,245,242,237,245,235, + 232,105,128, 10, 72,110, 5, 50,113, 50,122, 50,136, 50,152, 50, + 167,225,242,225,226,233, 99,128, 6, 57,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,202,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,203,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,204,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 3,246,239,247,229,236,243,233,231,110, 3, 50, + 197, 50,207, 50,214,226,229,238,231,225,236,105,128, 9,200,228, + 229,246, 97,128, 9, 72,231,245,234,225,242,225,244,105,128, 10, + 200,107, 2, 50,231, 50,255,225,244,225,235,225,238, 97,129, 48, + 162, 50,243,232,225,236,230,247,233,228,244,104,128,255,113,239, + 242,229,225,110,128, 49, 79,108, 3, 51, 15, 52, 71, 52, 80,101, + 2, 51, 21, 52, 66,102,136, 5,208, 51, 41, 51, 50, 51, 65, 51, + 79, 51,168, 51,182, 52, 37, 52, 51,225,242,225,226,233, 99,128, + 6, 39,228,225,231,229,243,232,232,229,226,242,229,119,128,251, + 48,230,233,238,225,236,225,242,225,226,233, 99,128,254,142,104, + 2, 51, 85, 51,160,225,237,250, 97, 2, 51, 94, 51,127,225,226, + 239,246,101, 2, 51,104, 51,113,225,242,225,226,233, 99,128, 6, + 35,230,233,238,225,236,225,242,225,226,233, 99,128,254,132,226, + 229,236,239,119, 2, 51,137, 51,146,225,242,225,226,233, 99,128, + 6, 37,230,233,238,225,236,225,242,225,226,233, 99,128,254,136, + 229,226,242,229,119,128, 5,208,236,225,237,229,228,232,229,226, + 242,229,119,128,251, 79,237, 97, 2, 51,189, 51,225,228,228,225, + 225,226,239,246,101, 2, 51,202, 51,211,225,242,225,226,233, 99, + 128, 6, 34,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 130,235,243,245,242, 97, 4, 51,239, 51,248, 52, 6, 52, 22,225, + 242,225,226,233, 99,128, 6, 73,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,240,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,243,237,229,228,233,225,236,225,242,225,226, + 233, 99,128,254,244,240,225,244,225,232,232,229,226,242,229,119, + 128,251, 46,241,225,237,225,244,243,232,229,226,242,229,119,128, + 251, 47,240,104,128, 33, 53,236,229,241,245,225,108,128, 34, 76, + 240,232, 97,129, 3,177, 52, 88,244,239,238,239,115,128, 3,172, + 109, 4, 52,106, 52,114, 52,125, 52,159,225,227,242,239,110,128, + 1, 1,239,238,239,243,240,225,227,101,128,255, 65,240,229,242, + 243,225,238,100,130, 0, 38, 52,139, 52,151,237,239,238,239,243, + 240,225,227,101,128,255, 6,243,237,225,236,108,128,247, 38,243, + 241,245,225,242,101,128, 51,194,110, 4, 52,178, 52,189, 53, 55, + 53, 65,226,239,240,239,237,239,230,111,128, 49, 34,103, 4, 52, + 199, 52,210, 52,224, 53, 47,226,239,240,239,237,239,230,111,128, + 49, 36,235,232,225,238,235,232,245,244,232,225,105,128, 14, 90, + 236,101,131, 34, 32, 52,235, 53, 32, 53, 39,226,242,225,227,235, + 229,116, 2, 52,247, 53, 11,236,229,230,116,129, 48, 8, 53, 0, + 246,229,242,244,233,227,225,108,128,254, 63,242,233,231,232,116, + 129, 48, 9, 53, 21,246,229,242,244,233,227,225,108,128,254, 64, + 236,229,230,116,128, 35, 41,242,233,231,232,116,128, 35, 42,243, + 244,242,239,109,128, 33, 43,239,244,229,236,229,233, 97,128, 3, + 135,117, 2, 53, 71, 53, 83,228,225,244,244,225,228,229,246, 97, + 128, 9, 82,243,246,225,242, 97, 3, 53, 95, 53,105, 53,112,226, + 229,238,231,225,236,105,128, 9,130,228,229,246, 97,128, 9, 2, + 231,245,234,225,242,225,244,105,128, 10,130,239,231,239,238,229, + 107,128, 1, 5,112, 3, 53,140, 53,164, 53,194, 97, 2, 53,146, + 53,158,225,244,239,243,241,245,225,242,101,128, 51, 0,242,229, + 110,128, 36,156,239,243,244,242,239,240,232,101, 2, 53,177, 53, + 188,225,242,237,229,238,233,225,110,128, 5, 90,237,239,100,128, + 2,188,112, 2, 53,200, 53,205,236,101,128,248,255,242,111, 2, + 53,212, 53,220,225,227,232,229,115,128, 34, 80,120, 2, 53,226, + 53,246,229,241,245,225,108,129, 34, 72, 53,236,239,242,233,237, + 225,231,101,128, 34, 82,233,237,225,244,229,236,249,229,241,245, + 225,108,128, 34, 69,114, 4, 54, 15, 54, 42, 54, 46, 54, 91,225, + 229, 97, 2, 54, 23, 54, 33,229,235,239,242,229,225,110,128, 49, + 142,235,239,242,229,225,110,128, 49,141, 99,128, 35, 18,105, 2, + 54, 52, 54, 66,231,232,244,232,225,236,230,242,233,238,103,128, + 30,154,238,103,130, 0,229, 54, 75, 54, 83,225,227,245,244,101, + 128, 1,251,226,229,236,239,119,128, 30, 1,242,239,119, 8, 54, + 111, 54,118, 54,247, 55, 57, 55,107, 55,162, 55,185, 56, 4,226, + 239,244,104,128, 33,148,100, 3, 54,126, 54,165, 54,212,225,243, + 104, 4, 54,138, 54,145, 54,152, 54,160,228,239,247,110,128, 33, + 227,236,229,230,116,128, 33,224,242,233,231,232,116,128, 33,226, + 245,112,128, 33,225,226,108, 5, 54,178, 54,185, 54,192, 54,199, + 54,207,226,239,244,104,128, 33,212,228,239,247,110,128, 33,211, + 236,229,230,116,128, 33,208,242,233,231,232,116,128, 33,210,245, + 112,128, 33,209,239,247,110,131, 33,147, 54,224, 54,231, 54,239, + 236,229,230,116,128, 33,153,242,233,231,232,116,128, 33,152,247, + 232,233,244,101,128, 33,233,104, 2, 54,253, 55, 48,229,225,100, + 4, 55, 9, 55, 19, 55, 29, 55, 40,228,239,247,238,237,239,100, + 128, 2,197,236,229,230,244,237,239,100,128, 2,194,242,233,231, + 232,244,237,239,100,128, 2,195,245,240,237,239,100,128, 2,196, + 239,242,233,250,229,120,128,248,231,236,229,230,116,131, 33,144, + 55, 70, 55, 87, 55, 99,228,226,108,129, 33,208, 55, 78,243,244, + 242,239,235,101,128, 33,205,239,246,229,242,242,233,231,232,116, + 128, 33,198,247,232,233,244,101,128, 33,230,242,233,231,232,116, + 132, 33,146, 55,123, 55,135, 55,143, 55,154,228,226,236,243,244, + 242,239,235,101,128, 33,207,232,229,225,246,121,128, 39,158,239, + 246,229,242,236,229,230,116,128, 33,196,247,232,233,244,101,128, + 33,232,244,225, 98, 2, 55,170, 55,177,236,229,230,116,128, 33, + 228,242,233,231,232,116,128, 33,229,245,112,132, 33,145, 55,198, + 55,226, 55,244, 55,252,100, 2, 55,204, 55,216,110,129, 33,149, + 55,210,226,243,101,128, 33,168,239,247,238,226,225,243,101,128, + 33,168,236,229,230,116,129, 33,150, 55,235,239,230,228,239,247, + 110,128, 33,197,242,233,231,232,116,128, 33,151,247,232,233,244, + 101,128, 33,231,246,229,242,244,229,120,128,248,230,115, 5, 56, + 25, 56,101, 56,146, 56,229, 56,239, 99, 2, 56, 31, 56, 83,233, + 105, 2, 56, 38, 56, 61,227,233,242,227,245,109,129, 0, 94, 56, + 49,237,239,238,239,243,240,225,227,101,128,255, 62,244,233,236, + 228,101,129, 0,126, 56, 71,237,239,238,239,243,240,225,227,101, + 128,255, 94,242,233,240,116,129, 2, 81, 56, 92,244,245,242,238, + 229,100,128, 2, 82,237,225,236,108, 2, 56,110, 56,121,232,233, + 242,225,231,225,238, 97,128, 48, 65,235,225,244,225,235,225,238, + 97,129, 48,161, 56,134,232,225,236,230,247,233,228,244,104,128, + 255,103,244,229,242,233,115, 2, 56,156, 56,225,107,131, 0, 42, + 56,166, 56,194, 56,217, 97, 2, 56,172, 56,186,236,244,239,238, + 229,225,242,225,226,233, 99,128, 6,109,242,225,226,233, 99,128, + 6,109,109, 2, 56,200, 56,206,225,244,104,128, 34, 23,239,238, + 239,243,240,225,227,101,128,255, 10,243,237,225,236,108,128,254, + 97,109,128, 32, 66,245,240,229,242,233,239,114,128,246,233,249, + 237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108, + 128, 34, 67,116,132, 0, 64, 57, 15, 57, 22, 57, 34, 57, 42,233, + 236,228,101,128, 0,227,237,239,238,239,243,240,225,227,101,128, + 255, 32,243,237,225,236,108,128,254,107,245,242,238,229,100,128, + 2, 80,117, 6, 57, 64, 57, 89, 57, 96, 57,121, 57,141, 57,157, + 98, 2, 57, 70, 57, 79,229,238,231,225,236,105,128, 9,148,239, + 240,239,237,239,230,111,128, 49, 32,228,229,246, 97,128, 9, 20, + 231,117, 2, 57,103, 57,112,234,225,242,225,244,105,128, 10,148, + 242,237,245,235,232,105,128, 10, 20,236,229,238,231,244,232,237, + 225,242,235,226,229,238,231,225,236,105,128, 9,215,237,225,244, + 242,225,231,245,242,237,245,235,232,105,128, 10, 76,246,239,247, + 229,236,243,233,231,110, 3, 57,173, 57,183, 57,190,226,229,238, + 231,225,236,105,128, 9,204,228,229,246, 97,128, 9, 76,231,245, + 234,225,242,225,244,105,128, 10,204,246,225,231,242,225,232,225, + 228,229,246, 97,128, 9, 61,121, 2, 57,221, 57,233,226,225,242, + 237,229,238,233,225,110,128, 5, 97,233,110,130, 5,226, 57,242, + 58, 1,225,236,244,239,238,229,232,229,226,242,229,119,128,251, + 32,232,229,226,242,229,119,128, 5,226, 98,144, 0, 98, 58, 46, + 58,181, 58,192, 58,201, 58,226, 60, 11, 60, 73, 60,146, 62, 72, + 62, 84, 62,127, 62,135, 62,145, 64, 15, 64, 39, 64, 48, 97, 7, + 58, 62, 58, 72, 58, 96, 58,103, 58,128, 58,152, 58,163,226,229, + 238,231,225,236,105,128, 9,172,227,235,243,236,225,243,104,129, + 0, 92, 58, 84,237,239,238,239,243,240,225,227,101,128,255, 60, + 228,229,246, 97,128, 9, 44,231,117, 2, 58,110, 58,119,234,225, + 242,225,244,105,128, 10,172,242,237,245,235,232,105,128, 10, 44, + 104, 2, 58,134, 58,144,233,242,225,231,225,238, 97,128, 48,112, + 244,244,232,225,105,128, 14, 63,235,225,244,225,235,225,238, 97, + 128, 48,208,114,129, 0,124, 58,169,237,239,238,239,243,240,225, + 227,101,128,255, 92,226,239,240,239,237,239,230,111,128, 49, 5, + 227,233,242,227,236,101,128, 36,209,228,239,116, 2, 58,209, 58, + 218,225,227,227,229,238,116,128, 30, 3,226,229,236,239,119,128, + 30, 5,101, 6, 58,240, 59, 5, 59, 28, 59,170, 59,181, 59,193, + 225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244, + 229,115,128, 38,108, 99, 2, 59, 11, 59, 18,225,245,243,101,128, + 34, 53,249,242,233,236,236,233, 99,128, 4, 49,104, 5, 59, 40, + 59, 49, 59, 63, 59, 93, 59,152,225,242,225,226,233, 99,128, 6, + 40,230,233,238,225,236,225,242,225,226,233, 99,128,254,144,105, + 2, 59, 69, 59, 84,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,145,242,225,231,225,238, 97,128, 48,121,237,101, 2, + 59,100, 59,113,228,233,225,236,225,242,225,226,233, 99,128,254, + 146,229,237,105, 2, 59,121, 59,136,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,159,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 8,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,109,235,225,244,225,235,225, + 238, 97,128, 48,217,238,225,242,237,229,238,233,225,110,128, 5, + 98,116,132, 5,209, 59,205, 59,225, 59,245, 59,254, 97,129, 3, + 178, 59,211,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 208,228,225,231,229,243,104,129,251, 49, 59,236,232,229,226,242, + 229,119,128,251, 49,232,229,226,242,229,119,128, 5,209,242,225, + 230,229,232,229,226,242,229,119,128,251, 76,104, 2, 60, 17, 60, + 67, 97, 3, 60, 25, 60, 35, 60, 42,226,229,238,231,225,236,105, + 128, 9,173,228,229,246, 97,128, 9, 45,231,117, 2, 60, 49, 60, + 58,234,225,242,225,244,105,128, 10,173,242,237,245,235,232,105, + 128, 10, 45,239,239,107,128, 2, 83,105, 5, 60, 85, 60, 96, 60, + 107, 60,121, 60,135,232,233,242,225,231,225,238, 97,128, 48,115, + 235,225,244,225,235,225,238, 97,128, 48,211,236,225,226,233,225, + 236,227,236,233,227,107,128, 2,152,238,228,233,231,245,242,237, + 245,235,232,105,128, 10, 2,242,245,243,241,245,225,242,101,128, + 51, 49,108, 3, 60,154, 62, 55, 62, 66, 97, 2, 60,160, 62, 50, + 227,107, 6, 60,175, 60,184, 60,221, 61,114, 61,169, 61,221,227, + 233,242,227,236,101,128, 37,207,100, 2, 60,190, 60,199,233,225, + 237,239,238,100,128, 37,198,239,247,238,240,239,233,238,244,233, + 238,231,244,242,233,225,238,231,236,101,128, 37,188,108, 2, 60, + 227, 61, 74,101, 2, 60,233, 61, 13,230,244,240,239,233,238,244, + 233,238,103, 2, 60,248, 61, 2,240,239,233,238,244,229,114,128, + 37,196,244,242,233,225,238,231,236,101,128, 37,192,238,244,233, + 227,245,236,225,242,226,242,225,227,235,229,116, 2, 61, 33, 61, + 53,236,229,230,116,129, 48, 16, 61, 42,246,229,242,244,233,227, + 225,108,128,254, 59,242,233,231,232,116,129, 48, 17, 61, 63,246, + 229,242,244,233,227,225,108,128,254, 60,239,247,229,114, 2, 61, + 83, 61, 98,236,229,230,244,244,242,233,225,238,231,236,101,128, + 37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128, + 37,226,114, 2, 61,120, 61,131,229,227,244,225,238,231,236,101, + 128, 37,172,233,231,232,244,240,239,233,238,244,233,238,103, 2, + 61,148, 61,158,240,239,233,238,244,229,114,128, 37,186,244,242, + 233,225,238,231,236,101,128, 37,182,115, 3, 61,177, 61,207, 61, + 215,109, 2, 61,183, 61,195,225,236,236,243,241,245,225,242,101, + 128, 37,170,233,236,233,238,231,230,225,227,101,128, 38, 59,241, + 245,225,242,101,128, 37,160,244,225,114,128, 38, 5,245,240,112, + 2, 61,229, 62, 11,229,114, 2, 61,236, 61,251,236,229,230,244, + 244,242,233,225,238,231,236,101,128, 37,228,242,233,231,232,244, + 244,242,233,225,238,231,236,101,128, 37,229,239,233,238,244,233, + 238,103, 2, 62, 23, 62, 39,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,180,244,242,233,225,238,231,236,101,128, + 37,178,238,107,128, 36, 35,233,238,229,226,229,236,239,119,128, + 30, 7,239,227,107,128, 37,136,237,239,238,239,243,240,225,227, + 101,128,255, 66,111, 3, 62, 92, 62,105, 62,116,226,225,233,237, + 225,233,244,232,225,105,128, 14, 26,232,233,242,225,231,225,238, + 97,128, 48,124,235,225,244,225,235,225,238, 97,128, 48,220,240, + 225,242,229,110,128, 36,157,241,243,241,245,225,242,101,128, 51, + 195,114, 4, 62,155, 63,149, 63,222, 64, 5,225, 99, 2, 62,162, + 63, 56,101, 3, 62,170, 62,175, 62,243,229,120,128,248,244,236, + 229,230,116,133, 0,123, 62,192, 62,197, 62,219, 62,227, 62,232, + 226,116,128,248,243,109, 2, 62,203, 62,208,233,100,128,248,242, + 239,238,239,243,240,225,227,101,128,255, 91,243,237,225,236,108, + 128,254, 91,244,112,128,248,241,246,229,242,244,233,227,225,108, + 128,254, 55,242,233,231,232,116,133, 0,125, 63, 5, 63, 10, 63, + 32, 63, 40, 63, 45,226,116,128,248,254,109, 2, 63, 16, 63, 21, + 233,100,128,248,253,239,238,239,243,240,225,227,101,128,255, 93, + 243,237,225,236,108,128,254, 92,244,112,128,248,252,246,229,242, + 244,233,227,225,108,128,254, 56,235,229,116, 2, 63, 64, 63,106, + 236,229,230,116,132, 0, 91, 63, 79, 63, 84, 63, 89, 63,101,226, + 116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225, + 227,101,128,255, 59,244,112,128,248,238,242,233,231,232,116,132, + 0, 93, 63,122, 63,127, 63,132, 63,144,226,116,128,248,251,229, + 120,128,248,250,237,239,238,239,243,240,225,227,101,128,255, 61, + 244,112,128,248,249,229,246,101,131, 2,216, 63,161, 63,172, 63, + 178,226,229,236,239,247,227,237, 98,128, 3, 46,227,237, 98,128, + 3, 6,233,238,246,229,242,244,229,100, 3, 63,193, 63,204, 63, + 210,226,229,236,239,247,227,237, 98,128, 3, 47,227,237, 98,128, + 3, 17,228,239,245,226,236,229,227,237, 98,128, 3, 97,233,228, + 231,101, 2, 63,231, 63,242,226,229,236,239,247,227,237, 98,128, + 3, 42,233,238,246,229,242,244,229,228,226,229,236,239,247,227, + 237, 98,128, 3, 58,239,235,229,238,226,225,114,128, 0,166,115, + 2, 64, 21, 64, 29,244,242,239,235,101,128, 1,128,245,240,229, + 242,233,239,114,128,246,234,244,239,240,226,225,114,128, 1,131, + 117, 3, 64, 56, 64, 67, 64, 78,232,233,242,225,231,225,238, 97, + 128, 48,118,235,225,244,225,235,225,238, 97,128, 48,214,236,108, + 2, 64, 85, 64,115,229,116,130, 32, 34, 64, 94, 64,104,233,238, + 246,229,242,243,101,128, 37,216,239,240,229,242,225,244,239,114, + 128, 34, 25,243,229,249,101,128, 37,206, 99,143, 0, 99, 64,156, + 65,105, 65,116, 65,180, 65,211, 66, 48, 67,215, 68,199, 69, 43, + 69, 92, 72, 84, 72, 92, 72,102, 72,114, 72,147, 97, 9, 64,176, + 64,187, 64,197, 64,204, 64,211, 64,236, 64,246, 65, 42, 65, 51, + 225,242,237,229,238,233,225,110,128, 5,110,226,229,238,231,225, + 236,105,128, 9,154,227,245,244,101,128, 1, 7,228,229,246, 97, + 128, 9, 26,231,117, 2, 64,218, 64,227,234,225,242,225,244,105, + 128, 10,154,242,237,245,235,232,105,128, 10, 26,236,243,241,245, + 225,242,101,128, 51,136,238,228,242,225,226,233,238,228,117, 4, + 65, 8, 65, 18, 65, 24, 65, 31,226,229,238,231,225,236,105,128, + 9,129,227,237, 98,128, 3, 16,228,229,246, 97,128, 9, 1,231, + 245,234,225,242,225,244,105,128, 10,129,240,243,236,239,227,107, + 128, 33,234,114, 3, 65, 59, 65, 65, 65, 91,229,239,102,128, 33, + 5,239,110,130, 2,199, 65, 74, 65, 85,226,229,236,239,247,227, + 237, 98,128, 3, 44,227,237, 98,128, 3, 12,242,233,225,231,229, + 242,229,244,245,242,110,128, 33,181,226,239,240,239,237,239,230, + 111,128, 49, 24, 99, 4, 65,126, 65,133, 65,152, 65,174,225,242, + 239,110,128, 1, 13,229,228,233,236,236, 97,129, 0,231, 65,144, + 225,227,245,244,101,128, 30, 9,233,242, 99, 2, 65,160, 65,165, + 236,101,128, 36,210,245,237,230,236,229,120,128, 1, 9,245,242, + 108,128, 2, 85,100, 2, 65,186, 65,202,239,116,129, 1, 11, 65, + 193,225,227,227,229,238,116,128, 1, 11,243,241,245,225,242,101, + 128, 51,197,101, 2, 65,217, 65,233,228,233,236,236, 97,129, 0, + 184, 65,227,227,237, 98,128, 3, 39,238,116,132, 0,162, 65,246, + 66, 14, 66, 26, 66, 37,105, 2, 65,252, 66, 4,231,242,225,228, + 101,128, 33, 3,238,230,229,242,233,239,114,128,246,223,237,239, + 238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249, + 236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224, + 104, 5, 66, 60, 66,123, 66,134, 67, 62, 67,154, 97, 4, 66, 70, + 66, 81, 66, 91, 66, 98,225,242,237,229,238,233,225,110,128, 5, + 121,226,229,238,231,225,236,105,128, 9,155,228,229,246, 97,128, + 9, 27,231,117, 2, 66,105, 66,114,234,225,242,225,244,105,128, + 10,155,242,237,245,235,232,105,128, 10, 27,226,239,240,239,237, + 239,230,111,128, 49, 20,101, 6, 66,148, 66,168, 66,192, 67, 4, + 67, 16, 67, 37,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,189, 99, 2, 66,174, 66,182,235,237, + 225,242,107,128, 39, 19,249,242,233,236,236,233, 99,128, 4, 71, + 100, 2, 66,198, 66,242,229,243,227,229,238,228,229,114, 2, 66, + 211, 66,231,225,226,235,232,225,243,233,225,238,227,249,242,233, + 236,236,233, 99,128, 4,191,227,249,242,233,236,236,233, 99,128, + 4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,245,232,225,242,237,229,238,233,225,110,128, 5,115, + 235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,204,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,185,105,129, + 3,199, 67, 68,229,245,227,104, 4, 67, 81, 67,116, 67,131, 67, + 140, 97, 2, 67, 87, 67,102,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,119,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 23,227,233,242,227,236,229,235,239,242,229,225,110, + 128, 50,105,235,239,242,229,225,110,128, 49, 74,240,225,242,229, + 238,235,239,242,229,225,110,128, 50, 9,111, 2, 67,160, 67,210, + 227,104, 3, 67,169, 67,191, 67,201,225,110, 2, 67,176, 67,184, + 231,244,232,225,105,128, 14, 10,244,232,225,105,128, 14, 8,233, + 238,231,244,232,225,105,128, 14, 9,239,229,244,232,225,105,128, + 14, 12,239,107,128, 1,136,105, 2, 67,221, 68, 67,229,245, 99, + 5, 67,235, 68, 14, 68, 29, 68, 38, 68, 52, 97, 2, 67,241, 68, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,118, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 22,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,104,235,239,242, + 229,225,110,128, 49, 72,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 8,245,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 28,242, 99, 2, 68, 74, 68,169,236,101,132, 37,203, 68, + 87, 68, 98, 68,103, 68,127,237,245,236,244,233,240,236,121,128, + 34,151,239,116,128, 34,153,112, 2, 68,109, 68,115,236,245,115, + 128, 34,149,239,243,244,225,236,237,225,242,107,128, 48, 54,247, + 233,244,104, 2, 68,136, 68,152,236,229,230,244,232,225,236,230, + 226,236,225,227,107,128, 37,208,242,233,231,232,244,232,225,236, + 230,226,236,225,227,107,128, 37,209,245,237,230,236,229,120,130, + 2,198, 68,182, 68,193,226,229,236,239,247,227,237, 98,128, 3, + 45,227,237, 98,128, 3, 2,108, 3, 68,207, 68,213, 69, 11,229, + 225,114,128, 35, 39,233,227,107, 4, 68,225, 68,236, 68,245, 68, + 255,225,236,246,229,239,236,225,114,128, 1,194,228,229,238,244, + 225,108,128, 1,192,236,225,244,229,242,225,108,128, 1,193,242, + 229,244,242,239,230,236,229,120,128, 1,195,245, 98,129, 38, 99, + 69, 18,243,245,233,116, 2, 69, 27, 69, 35,226,236,225,227,107, + 128, 38, 99,247,232,233,244,101,128, 38,103,109, 3, 69, 51, 69, + 65, 69, 76,227,245,226,229,228,243,241,245,225,242,101,128, 51, + 164,239,238,239,243,240,225,227,101,128,255, 67,243,241,245,225, + 242,229,228,243,241,245,225,242,101,128, 51,160,111, 8, 69,110, + 69,121, 69,208, 70,150, 71,179, 71,210, 72, 61, 72, 70,225,242, + 237,229,238,233,225,110,128, 5,129,236,239,110,131, 0, 58, 69, + 133, 69,158, 69,177,237,239,110, 2, 69,141, 69,149,229,244,225, + 242,121,128, 32,161,239,243,240,225,227,101,128,255, 26,115, 2, + 69,164, 69,170,233,231,110,128, 32,161,237,225,236,108,128,254, + 85,244,242,233,225,238,231,245,236,225,114, 2, 69,192, 69,202, + 232,225,236,230,237,239,100,128, 2,209,237,239,100,128, 2,208, + 109, 2, 69,214, 70,143,237, 97,134, 0, 44, 69,231, 70, 39, 70, + 50, 70, 62, 70, 92, 70,115, 97, 3, 69,239, 70, 9, 70, 17,226, + 239,246,101, 2, 69,248, 69,254,227,237, 98,128, 3, 19,242,233, + 231,232,244,227,237, 98,128, 3, 21,227,227,229,238,116,128,246, + 195,114, 2, 70, 23, 70, 30,225,226,233, 99,128, 6, 12,237,229, + 238,233,225,110,128, 5, 93,233,238,230,229,242,233,239,114,128, + 246,225,237,239,238,239,243,240,225,227,101,128,255, 12,242,229, + 246,229,242,243,229,100, 2, 70, 75, 70, 86,225,226,239,246,229, + 227,237, 98,128, 3, 20,237,239,100,128, 2,189,115, 2, 70, 98, + 70,105,237,225,236,108,128,254, 80,245,240,229,242,233,239,114, + 128,246,226,244,245,242,238,229,100, 2, 70,126, 70,137,225,226, + 239,246,229,227,237, 98,128, 3, 18,237,239,100,128, 2,187,240, + 225,243,115,128, 38, 60,110, 2, 70,156, 70,165,231,242,245,229, + 238,116,128, 34, 69,116, 2, 70,171, 70,185,239,245,242,233,238, + 244,229,231,242,225,108,128, 34, 46,242,239,108,142, 35, 3, 70, + 219, 70,225, 70,240, 70,255, 71, 43, 71, 88, 71,102, 71,107, 71, + 112, 71,117, 71,123, 71,128, 71,169, 71,174,193,195, 75,128, 0, + 6, 66, 2, 70,231, 70,236,197, 76,128, 0, 7, 83,128, 0, 8, + 67, 2, 70,246, 70,251,193, 78,128, 0, 24, 82,128, 0, 13, 68, + 3, 71, 7, 71, 33, 71, 38, 67, 4, 71, 17, 71, 21, 71, 25, 71, + 29, 49,128, 0, 17, 50,128, 0, 18, 51,128, 0, 19, 52,128, 0, + 20,197, 76,128, 0,127,204, 69,128, 0, 16, 69, 5, 71, 55, 71, + 59, 71, 64, 71, 69, 71, 74, 77,128, 0, 25,206, 81,128, 0, 5, + 207, 84,128, 0, 4,211, 67,128, 0, 27, 84, 2, 71, 80, 71, 84, + 66,128, 0, 23, 88,128, 0, 3, 70, 2, 71, 94, 71, 98, 70,128, + 0, 12, 83,128, 0, 28,199, 83,128, 0, 29,200, 84,128, 0, 9, + 204, 70,128, 0, 10,206,193, 75,128, 0, 21,210, 83,128, 0, 30, + 83, 5, 71,140, 71,144, 71,154, 71,159, 71,164, 73,128, 0, 15, + 79,129, 0, 14, 71,150, 84,128, 0, 2,212, 88,128, 0, 1,213, + 66,128, 0, 26,217, 78,128, 0, 22,213, 83,128, 0, 31,214, 84, + 128, 0, 11,240,249,242,233,231,232,116,129, 0,169, 71,191,115, + 2, 71,197, 71,203,225,238,115,128,248,233,229,242,233,102,128, + 246,217,114, 2, 71,216, 72, 44,238,229,242,226,242,225,227,235, + 229,116, 2, 71,231, 72, 9,236,229,230,116,130, 48, 12, 71,242, + 71,254,232,225,236,230,247,233,228,244,104,128,255, 98,246,229, + 242,244,233,227,225,108,128,254, 65,242,233,231,232,116,130, 48, + 13, 72, 21, 72, 33,232,225,236,230,247,233,228,244,104,128,255, + 99,246,229,242,244,233,227,225,108,128,254, 66,240,239,242,225, + 244,233,239,238,243,241,245,225,242,101,128, 51,127,243,241,245, + 225,242,101,128, 51,199,246,229,242,235,231,243,241,245,225,242, + 101,128, 51,198,240,225,242,229,110,128, 36,158,242,245,250,229, + 233,242,111,128, 32,162,243,244,242,229,244,227,232,229,100,128, + 2,151,245,114, 2, 72,121, 72,139,236,121, 2, 72,128, 72,134, + 225,238,100,128, 34,207,239,114,128, 34,206,242,229,238,227,121, + 128, 0,164,249,114, 4, 72,158, 72,166, 72,173, 72,181,194,242, + 229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229, + 246,101,128,246,212,230,236,229,120,128,246,213,100,146, 0,100, + 72,228, 74,110, 75,134, 75,194, 76,114, 77, 68, 77,130, 78, 59, + 78, 72, 78, 81, 78,107, 78,132, 78,141, 79,208, 79,216, 79,227, + 79,247, 80, 19, 97, 11, 72,252, 73, 7, 73, 17, 73, 89, 73,152, + 73,163, 73,174, 73,243, 74, 49, 74, 55, 74, 85,225,242,237,229, + 238,233,225,110,128, 5,100,226,229,238,231,225,236,105,128, 9, + 166,100, 5, 73, 29, 73, 38, 73, 44, 73, 58, 73, 74,225,242,225, + 226,233, 99,128, 6, 54,229,246, 97,128, 9, 38,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,190,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,191,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,192,103, 3, 73, 97, 73,114, 73, + 128,229,243,104,129, 5,188, 73,105,232,229,226,242,229,119,128, + 5,188,231,229,114,129, 32, 32, 73,122,228,226,108,128, 32, 33, + 117, 2, 73,134, 73,143,234,225,242,225,244,105,128, 10,166,242, + 237,245,235,232,105,128, 10, 38,232,233,242,225,231,225,238, 97, + 128, 48, 96,235,225,244,225,235,225,238, 97,128, 48,192,108, 3, + 73,182, 73,191, 73,229,225,242,225,226,233, 99,128, 6, 47,229, + 116,130, 5,211, 73,200, 73,220,228,225,231,229,243,104,129,251, + 51, 73,211,232,229,226,242,229,119,128,251, 51,232,229,226,242, + 229,119,128, 5,211,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,170,237,237, 97, 3, 73,253, 74, 6, 74, 18,225,242,225, + 226,233, 99,128, 6, 79,236,239,247,225,242,225,226,233, 99,128, + 6, 79,244,225,238, 97, 2, 74, 27, 74, 41,236,244,239,238,229, + 225,242,225,226,233, 99,128, 6, 76,242,225,226,233, 99,128, 6, + 76,238,228, 97,128, 9,100,242,231, 97, 2, 74, 63, 74, 72,232, + 229,226,242,229,119,128, 5,167,236,229,230,244,232,229,226,242, + 229,119,128, 5,167,243,233,225,240,238,229,245,237,225,244,225, + 227,249,242,233,236,236,233,227,227,237, 98,128, 4,133, 98, 3, + 74,118, 75,115, 75,125,108, 9, 74,138, 74,146, 75, 3, 75, 11, + 75, 27, 75, 38, 75, 56, 75, 70, 75, 81,199,242,225,246,101,128, + 246,211, 97, 2, 74,152, 74,209,238,231,236,229,226,242,225,227, + 235,229,116, 2, 74,168, 74,188,236,229,230,116,129, 48, 10, 74, + 177,246,229,242,244,233,227,225,108,128,254, 61,242,233,231,232, + 116,129, 48, 11, 74,198,246,229,242,244,233,227,225,108,128,254, + 62,114, 2, 74,215, 74,236,227,232,233,238,246,229,242,244,229, + 228,226,229,236,239,247,227,237, 98,128, 3, 43,242,239,119, 2, + 74,244, 74,251,236,229,230,116,128, 33,212,242,233,231,232,116, + 128, 33,210,228,225,238,228, 97,128, 9,101,231,242,225,246,101, + 129,246,214, 75, 21,227,237, 98,128, 3, 15,233,238,244,229,231, + 242,225,108,128, 34, 44,236,239,247,236,233,238,101,129, 32, 23, + 75, 50,227,237, 98,128, 3, 51,239,246,229,242,236,233,238,229, + 227,237, 98,128, 3, 63,240,242,233,237,229,237,239,100,128, 2, + 186,246,229,242,244,233,227,225,108, 2, 75, 94, 75,100,226,225, + 114,128, 32, 22,236,233,238,229,225,226,239,246,229,227,237, 98, + 128, 3, 14,239,240,239,237,239,230,111,128, 49, 9,243,241,245, + 225,242,101,128, 51,200, 99, 4, 75,144, 75,151, 75,160, 75,187, + 225,242,239,110,128, 1, 15,229,228,233,236,236, 97,128, 30, 17, + 233,242, 99, 2, 75,168, 75,173,236,101,128, 36,211,245,237,230, + 236,229,248,226,229,236,239,119,128, 30, 19,242,239,225,116,128, + 1, 17,100, 4, 75,204, 76, 29, 76, 39, 76, 90, 97, 4, 75,214, + 75,224, 75,231, 76, 0,226,229,238,231,225,236,105,128, 9,161, + 228,229,246, 97,128, 9, 33,231,117, 2, 75,238, 75,247,234,225, + 242,225,244,105,128, 10,161,242,237,245,235,232,105,128, 10, 33, + 108, 2, 76, 6, 76, 15,225,242,225,226,233, 99,128, 6,136,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,137,228,232,225, + 228,229,246, 97,128, 9, 92,232, 97, 3, 76, 48, 76, 58, 76, 65, + 226,229,238,231,225,236,105,128, 9,162,228,229,246, 97,128, 9, + 34,231,117, 2, 76, 72, 76, 81,234,225,242,225,244,105,128, 10, + 162,242,237,245,235,232,105,128, 10, 34,239,116, 2, 76, 97, 76, + 106,225,227,227,229,238,116,128, 30, 11,226,229,236,239,119,128, + 30, 13,101, 8, 76,132, 76,185, 76,192, 76,217, 76,227, 76,238, + 77, 27, 77, 63, 99, 2, 76,138, 76,175,233,237,225,236,243,229, + 240,225,242,225,244,239,114, 2, 76,156, 76,165,225,242,225,226, + 233, 99,128, 6,107,240,229,242,243,233,225,110,128, 6,107,249, + 242,233,236,236,233, 99,128, 4, 52,231,242,229,101,128, 0,176, + 232,105, 2, 76,199, 76,208,232,229,226,242,229,119,128, 5,173, + 242,225,231,225,238, 97,128, 48,103,233,227,239,240,244,233, 99, + 128, 3,239,235,225,244,225,235,225,238, 97,128, 48,199,108, 2, + 76,244, 77, 11,229,244,101, 2, 76,252, 77, 3,236,229,230,116, + 128, 35, 43,242,233,231,232,116,128, 35, 38,244, 97,129, 3,180, + 77, 18,244,245,242,238,229,100,128, 1,141,238,239,237,233,238, + 225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229, + 242,225,244,239,242,226,229,238,231,225,236,105,128, 9,248,250, + 104,128, 2,164,104, 2, 77, 74, 77,124, 97, 3, 77, 82, 77, 92, + 77, 99,226,229,238,231,225,236,105,128, 9,167,228,229,246, 97, + 128, 9, 39,231,117, 2, 77,106, 77,115,234,225,242,225,244,105, + 128, 10,167,242,237,245,235,232,105,128, 10, 39,239,239,107,128, + 2, 87,105, 6, 77,144, 77,193, 77,253, 78, 8, 78, 19, 78, 29, + 97, 2, 77,150, 77,172,236,249,244,233,235,225,244,239,238,239, + 115,129, 3,133, 77,166,227,237, 98,128, 3, 68,237,239,238,100, + 129, 38,102, 77,181,243,245,233,244,247,232,233,244,101,128, 38, + 98,229,242,229,243,233,115,133, 0,168, 77,212, 77,220, 77,231, + 77,237, 77,245,225,227,245,244,101,128,246,215,226,229,236,239, + 247,227,237, 98,128, 3, 36,227,237, 98,128, 3, 8,231,242,225, + 246,101,128,246,216,244,239,238,239,115,128, 3,133,232,233,242, + 225,231,225,238, 97,128, 48, 98,235,225,244,225,235,225,238, 97, + 128, 48,194,244,244,239,237,225,242,107,128, 48, 3,246,105, 2, + 78, 36, 78, 47,228,101,129, 0,247, 78, 43,115,128, 34, 35,243, + 233,239,238,243,236,225,243,104,128, 34, 21,234,229,227,249,242, + 233,236,236,233, 99,128, 4, 82,235,243,232,225,228,101,128, 37, + 147,108, 2, 78, 87, 78, 98,233,238,229,226,229,236,239,119,128, + 30, 15,243,241,245,225,242,101,128, 51,151,109, 2, 78,113, 78, + 121,225,227,242,239,110,128, 1, 17,239,238,239,243,240,225,227, + 101,128,255, 68,238,226,236,239,227,107,128, 37,132,111, 10, 78, + 163, 78,175, 78,185, 78,196, 78,207, 79, 23, 79, 28, 79, 39, 79, + 154, 79,180,227,232,225,228,225,244,232,225,105,128, 14, 14,228, + 229,235,244,232,225,105,128, 14, 20,232,233,242,225,231,225,238, + 97,128, 48,105,235,225,244,225,235,225,238, 97,128, 48,201,236, + 236,225,114,132, 0, 36, 78,222, 78,233, 78,245, 79, 0,233,238, + 230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225, + 227,101,128,255, 4,239,236,228,243,244,249,236,101,128,247, 36, + 115, 2, 79, 6, 79, 13,237,225,236,108,128,254,105,245,240,229, + 242,233,239,114,128,246,228,238,103,128, 32,171,242,245,243,241, + 245,225,242,101,128, 51, 38,116, 6, 79, 53, 79, 70, 79, 92, 79, + 103, 79,135, 79,142,225,227,227,229,238,116,129, 2,217, 79, 64, + 227,237, 98,128, 3, 7,226,229,236,239,247, 99, 2, 79, 81, 79, + 86,237, 98,128, 3, 35,239,237, 98,128, 3, 35,235,225,244,225, + 235,225,238, 97,128, 48,251,236,229,243,115, 2, 79,112, 79,116, + 105,128, 1, 49,106,129,246,190, 79,122,243,244,242,239,235,229, + 232,239,239,107,128, 2,132,237,225,244,104,128, 34,197,244,229, + 228,227,233,242,227,236,101,128, 37,204,245,226,236,229,249,239, + 228,240,225,244,225,104,129,251, 31, 79,171,232,229,226,242,229, + 119,128,251, 31,247,238,244,225,227,107, 2, 79,191, 79,202,226, + 229,236,239,247,227,237, 98,128, 3, 30,237,239,100,128, 2,213, + 240,225,242,229,110,128, 36,159,243,245,240,229,242,233,239,114, + 128,246,235,116, 2, 79,233, 79,239,225,233,108,128, 2, 86,239, + 240,226,225,114,128, 1,140,117, 2, 79,253, 80, 8,232,233,242, + 225,231,225,238, 97,128, 48,101,235,225,244,225,235,225,238, 97, + 128, 48,197,122,132, 1,243, 80, 31, 80, 40, 80, 59, 80, 96,225, + 236,244,239,238,101,128, 2,163, 99, 2, 80, 46, 80, 53,225,242, + 239,110,128, 1,198,245,242,108,128, 2,165,101, 2, 80, 65, 80, + 85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,225,227,249,242,233,236,236,233, 99,128, 4, 85, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 95,101,151, 0, + 101, 80,159, 80,178, 80,212, 81,186, 81,248, 82, 25, 82, 37, 82, + 60, 82,113, 83,225, 84, 27, 84,129, 84,245, 85,124, 85,199, 85, + 230, 86, 36, 86, 89, 87, 24, 87,157, 87,177, 87,221, 88, 56, 97, + 2, 80,165, 80,172,227,245,244,101,128, 0,233,242,244,104,128, + 38, 65, 98, 3, 80,186, 80,195, 80,205,229,238,231,225,236,105, + 128, 9,143,239,240,239,237,239,230,111,128, 49, 28,242,229,246, + 101,128, 1, 21, 99, 5, 80,224, 81, 41, 81, 55, 81, 87, 81,176, + 97, 2, 80,230, 81, 35,238,228,242, 97, 3, 80,241, 80,248, 81, + 3,228,229,246, 97,128, 9, 13,231,245,234,225,242,225,244,105, + 128, 10,141,246,239,247,229,236,243,233,231,110, 2, 81, 17, 81, + 24,228,229,246, 97,128, 9, 69,231,245,234,225,242,225,244,105, + 128, 10,197,242,239,110,128, 1, 27,229,228,233,236,236,225,226, + 242,229,246,101,128, 30, 29,104, 2, 81, 61, 81, 72,225,242,237, + 229,238,233,225,110,128, 5,101,249,233,247,238,225,242,237,229, + 238,233,225,110,128, 5,135,233,242, 99, 2, 81, 95, 81,100,236, + 101,128, 36,212,245,237,230,236,229,120,134, 0,234, 81,121, 81, + 129, 81,137, 81,148, 81,156, 81,168,225,227,245,244,101,128, 30, + 191,226,229,236,239,119,128, 30, 25,228,239,244,226,229,236,239, + 119,128, 30,199,231,242,225,246,101,128, 30,193,232,239,239,235, + 225,226,239,246,101,128, 30,195,244,233,236,228,101,128, 30,197, + 249,242,233,236,236,233, 99,128, 4, 84,100, 4, 81,196, 81,206, + 81,212, 81,222,226,236,231,242,225,246,101,128, 2, 5,229,246, + 97,128, 9, 15,233,229,242,229,243,233,115,128, 0,235,239,116, + 130, 1, 23, 81,231, 81,240,225,227,227,229,238,116,128, 1, 23, + 226,229,236,239,119,128, 30,185,101, 2, 81,254, 82, 9,231,245, + 242,237,245,235,232,105,128, 10, 15,237,225,244,242,225,231,245, + 242,237,245,235,232,105,128, 10, 71,230,227,249,242,233,236,236, + 233, 99,128, 4, 68,103, 2, 82, 43, 82, 50,242,225,246,101,128, + 0,232,245,234,225,242,225,244,105,128, 10,143,104, 4, 82, 70, + 82, 81, 82, 92, 82,102,225,242,237,229,238,233,225,110,128, 5, + 103,226,239,240,239,237,239,230,111,128, 49, 29,233,242,225,231, + 225,238, 97,128, 48, 72,239,239,235,225,226,239,246,101,128, 30, + 187,105, 4, 82,123, 82,134, 83,192, 83,207,226,239,240,239,237, + 239,230,111,128, 49, 31,231,232,116,142, 0, 56, 82,168, 82,177, + 82,187, 82,217, 82,224, 83, 6, 83, 31, 83, 76, 83,110, 83,122, + 83,133, 83,166, 83,174, 83,185,225,242,225,226,233, 99,128, 6, + 104,226,229,238,231,225,236,105,128, 9,238,227,233,242,227,236, + 101,129, 36,103, 82,198,233,238,246,229,242,243,229,243,225,238, + 243,243,229,242,233,102,128, 39,145,228,229,246, 97,128, 9,110, + 229,229,110, 2, 82,232, 82,241,227,233,242,227,236,101,128, 36, + 113,112, 2, 82,247, 82,254,225,242,229,110,128, 36,133,229,242, + 233,239,100,128, 36,153,231,117, 2, 83, 13, 83, 22,234,225,242, + 225,244,105,128, 10,238,242,237,245,235,232,105,128, 10,110,104, + 2, 83, 37, 83, 63, 97, 2, 83, 43, 83, 54,227,235,225,242,225, + 226,233, 99,128, 6,104,238,231,250,232,239,117,128, 48, 40,238, + 239,244,229,226,229,225,237,229,100,128, 38,107,105, 2, 83, 82, + 83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 39,238,230,229,242,233,239,114,128, 32,136,237,239, + 238,239,243,240,225,227,101,128,255, 24,239,236,228,243,244,249, + 236,101,128,247, 56,112, 2, 83,139, 83,146,225,242,229,110,128, + 36,123,229,114, 2, 83,153, 83,159,233,239,100,128, 36,143,243, + 233,225,110,128, 6,248,242,239,237,225,110,128, 33,119,243,245, + 240,229,242,233,239,114,128, 32,120,244,232,225,105,128, 14, 88, + 238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 7,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 101,107, 2, 83,231, 83,255,225,244,225,235,225,238, 97,129, 48, + 168, 83,243,232,225,236,230,247,233,228,244,104,128,255,116,111, + 2, 84, 5, 84, 20,238,235,225,242,231,245,242,237,245,235,232, + 105,128, 10,116,242,229,225,110,128, 49, 84,108, 3, 84, 35, 84, + 46, 84,107,227,249,242,233,236,236,233, 99,128, 4, 59,101, 2, + 84, 52, 84, 59,237,229,238,116,128, 34, 8,246,229,110, 3, 84, + 69, 84, 78, 84, 99,227,233,242,227,236,101,128, 36,106,112, 2, + 84, 84, 84, 91,225,242,229,110,128, 36,126,229,242,233,239,100, + 128, 36,146,242,239,237,225,110,128, 33,122,236,233,240,243,233, + 115,129, 32, 38, 84,118,246,229,242,244,233,227,225,108,128, 34, + 238,109, 5, 84,141, 84,169, 84,180, 84,200, 84,211,225,227,242, + 239,110,130, 1, 19, 84,153, 84,161,225,227,245,244,101,128, 30, + 23,231,242,225,246,101,128, 30, 21,227,249,242,233,236,236,233, + 99,128, 4, 60,228,225,243,104,129, 32, 20, 84,189,246,229,242, + 244,233,227,225,108,128,254, 49,239,238,239,243,240,225,227,101, + 128,255, 69,112, 2, 84,217, 84,237,232,225,243,233,243,237,225, + 242,235,225,242,237,229,238,233,225,110,128, 5, 91,244,249,243, + 229,116,128, 34, 5,110, 6, 85, 3, 85, 14, 85, 25, 85, 69, 85, + 101, 85,116,226,239,240,239,237,239,230,111,128, 49, 35,227,249, + 242,233,236,236,233, 99,128, 4, 61,100, 2, 85, 31, 85, 50,225, + 243,104,129, 32, 19, 85, 39,246,229,242,244,233,227,225,108,128, + 254, 50,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,163,103,130, 1, 75, 85, 77, 85, 88,226,239,240, + 239,237,239,230,111,128, 49, 37,232,229,227,249,242,233,236,236, + 233, 99,128, 4,165,232,239,239,235,227,249,242,233,236,236,233, + 99,128, 4,200,243,240,225,227,101,128, 32, 2,111, 3, 85,132, + 85,140, 85,149,231,239,238,229,107,128, 1, 25,235,239,242,229, + 225,110,128, 49, 83,240,229,110,130, 2, 91, 85,159, 85,168,227, + 236,239,243,229,100,128, 2,154,242,229,246,229,242,243,229,100, + 130, 2, 92, 85,183, 85,192,227,236,239,243,229,100,128, 2, 94, + 232,239,239,107,128, 2, 93,112, 2, 85,205, 85,212,225,242,229, + 110,128, 36,160,243,233,236,239,110,129, 3,181, 85,222,244,239, + 238,239,115,128, 3,173,241,117, 2, 85,237, 86, 25,225,108,130, + 0, 61, 85,246, 86, 2,237,239,238,239,243,240,225,227,101,128, + 255, 29,115, 2, 86, 8, 86, 15,237,225,236,108,128,254,102,245, + 240,229,242,233,239,114,128, 32,124,233,246,225,236,229,238,227, + 101,128, 34, 97,114, 3, 86, 44, 86, 55, 86, 66,226,239,240,239, + 237,239,230,111,128, 49, 38,227,249,242,233,236,236,233, 99,128, + 4, 64,229,246,229,242,243,229,100,129, 2, 88, 86, 78,227,249, + 242,233,236,236,233, 99,128, 4, 77,115, 6, 86,103, 86,114, 86, + 134, 86,215, 87, 4, 87, 14,227,249,242,233,236,236,233, 99,128, + 4, 65,228,229,243,227,229,238,228,229,242,227,249,242,233,236, + 236,233, 99,128, 4,171,104,132, 2,131, 86,146, 86,153, 86,184, + 86,199,227,245,242,108,128, 2,134,239,242,116, 2, 86,161, 86, + 168,228,229,246, 97,128, 9, 14,246,239,247,229,236,243,233,231, + 238,228,229,246, 97,128, 9, 70,242,229,246,229,242,243,229,228, + 236,239,239,112,128, 1,170,243,241,245,225,244,242,229,246,229, + 242,243,229,100,128, 2,133,237,225,236,108, 2, 86,224, 86,235, + 232,233,242,225,231,225,238, 97,128, 48, 71,235,225,244,225,235, + 225,238, 97,129, 48,167, 86,248,232,225,236,230,247,233,228,244, + 104,128,255,106,244,233,237,225,244,229,100,128, 33, 46,245,240, + 229,242,233,239,114,128,246,236,116, 5, 87, 36, 87, 62, 87, 66, + 87, 83, 87,149, 97,130, 3,183, 87, 44, 87, 54,242,237,229,238, + 233,225,110,128, 5,104,244,239,238,239,115,128, 3,174,104,128, + 0,240,233,236,228,101,129, 30,189, 87, 75,226,229,236,239,119, + 128, 30, 27,238,225,232,244, 97, 3, 87, 95, 87,127, 87,136,230, + 239,245,235,104, 2, 87,105, 87,114,232,229,226,242,229,119,128, + 5,145,236,229,230,244,232,229,226,242,229,119,128, 5,145,232, + 229,226,242,229,119,128, 5,145,236,229,230,244,232,229,226,242, + 229,119,128, 5,145,245,242,238,229,100,128, 1,221,117, 2, 87, + 163, 87,172,235,239,242,229,225,110,128, 49, 97,242,111,128, 32, + 172,246,239,247,229,236,243,233,231,110, 3, 87,193, 87,203, 87, + 210,226,229,238,231,225,236,105,128, 9,199,228,229,246, 97,128, + 9, 71,231,245,234,225,242,225,244,105,128, 10,199,120, 2, 87, + 227, 88, 44,227,236,225,109,132, 0, 33, 87,242, 87,253, 88, 24, + 88, 36,225,242,237,229,238,233,225,110,128, 5, 92,100, 2, 88, + 3, 88, 8,226,108,128, 32, 60,239,247,110,129, 0,161, 88, 16, + 243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227, + 101,128,255, 1,243,237,225,236,108,128,247, 33,233,243,244,229, + 238,244,233,225,108,128, 34, 3,250,104,131, 2,146, 88, 67, 88, + 86, 88, 97, 99, 2, 88, 73, 88, 80,225,242,239,110,128, 1,239, + 245,242,108,128, 2,147,242,229,246,229,242,243,229,100,128, 1, + 185,244,225,233,108,128, 1,186,102,140, 0,102, 88,132, 88,214, + 88,225, 88,234, 88,246, 89, 93, 89,109, 91,117, 91,130, 91,156, + 93, 33, 93, 41, 97, 4, 88,142, 88,149, 88,160, 88,171,228,229, + 246, 97,128, 9, 94,231,245,242,237,245,235,232,105,128, 10, 94, + 232,242,229,238,232,229,233,116,128, 33, 9,244,232, 97, 3, 88, + 181, 88,190, 88,202,225,242,225,226,233, 99,128, 6, 78,236,239, + 247,225,242,225,226,233, 99,128, 6, 78,244,225,238,225,242,225, + 226,233, 99,128, 6, 75,226,239,240,239,237,239,230,111,128, 49, + 8,227,233,242,227,236,101,128, 36,213,228,239,244,225,227,227, + 229,238,116,128, 30, 31,101, 3, 88,254, 89, 76, 89, 86,104, 4, + 89, 8, 89, 31, 89, 45, 89, 61,225,114, 2, 89, 15, 89, 22,225, + 226,233, 99,128, 6, 65,237,229,238,233,225,110,128, 5,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,210,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,211,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,254,212,233,227,239,240, + 244,233, 99,128, 3,229,237,225,236,101,128, 38, 64,102,130,251, + 0, 89,101, 89,105,105,128,251, 3,108,128,251, 4,105,136,251, + 1, 89,129, 89,169, 89,180, 89,202, 90, 68, 90, 85, 90, 93, 90, + 106,230,244,229,229,110, 2, 89,139, 89,148,227,233,242,227,236, + 101,128, 36,110,112, 2, 89,154, 89,161,225,242,229,110,128, 36, + 130,229,242,233,239,100,128, 36,150,231,245,242,229,228,225,243, + 104,128, 32, 18,236,236,229,100, 2, 89,189, 89,195,226,239,120, + 128, 37,160,242,229,227,116,128, 37,172,238,225,108, 5, 89,216, + 89,255, 90, 16, 90, 33, 90, 49,235,225,102,130, 5,218, 89,226, + 89,246,228,225,231,229,243,104,129,251, 58, 89,237,232,229,226, + 242,229,119,128,251, 58,232,229,226,242,229,119,128, 5,218,237, + 229,109,129, 5,221, 90, 7,232,229,226,242,229,119,128, 5,221, + 238,245,110,129, 5,223, 90, 24,232,229,226,242,229,119,128, 5, + 223,240,101,129, 5,227, 90, 40,232,229,226,242,229,119,128, 5, + 227,244,243,225,228,105,129, 5,229, 90, 59,232,229,226,242,229, + 119,128, 5,229,242,243,244,244,239,238,229,227,232,233,238,229, + 243,101,128, 2,201,243,232,229,249,101,128, 37,201,244,225,227, + 249,242,233,236,236,233, 99,128, 4,115,246,101,142, 0, 53, 90, + 139, 90,148, 90,158, 90,188, 90,195, 90,205, 90,230, 91, 1, 91, + 35, 91, 47, 91, 58, 91, 91, 91, 99, 91,110,225,242,225,226,233, + 99,128, 6,101,226,229,238,231,225,236,105,128, 9,235,227,233, + 242,227,236,101,129, 36,100, 90,169,233,238,246,229,242,243,229, + 243,225,238,243,243,229,242,233,102,128, 39,142,228,229,246, 97, + 128, 9,107,229,233,231,232,244,232,115,128, 33, 93,231,117, 2, + 90,212, 90,221,234,225,242,225,244,105,128, 10,235,242,237,245, + 235,232,105,128, 10,107,232, 97, 2, 90,237, 90,248,227,235,225, + 242,225,226,233, 99,128, 6,101,238,231,250,232,239,117,128, 48, + 37,105, 2, 91, 7, 91, 25,228,229,239,231,242,225,240,232,233, + 227,240,225,242,229,110,128, 50, 36,238,230,229,242,233,239,114, + 128, 32,133,237,239,238,239,243,240,225,227,101,128,255, 21,239, + 236,228,243,244,249,236,101,128,247, 53,112, 2, 91, 64, 91, 71, + 225,242,229,110,128, 36,120,229,114, 2, 91, 78, 91, 84,233,239, + 100,128, 36,140,243,233,225,110,128, 6,245,242,239,237,225,110, + 128, 33,116,243,245,240,229,242,233,239,114,128, 32,117,244,232, + 225,105,128, 14, 85,108,129,251, 2, 91,123,239,242,233,110,128, + 1,146,109, 2, 91,136, 91,147,239,238,239,243,240,225,227,101, + 128,255, 70,243,241,245,225,242,101,128, 51,153,111, 4, 91,166, + 91,188, 91,200, 91,207,230, 97, 2, 91,173, 91,181,238,244,232, + 225,105,128, 14, 31,244,232,225,105,128, 14, 29,238,231,237,225, + 238,244,232,225,105,128, 14, 79,242,225,236,108,128, 34, 0,245, + 114,142, 0, 52, 91,240, 91,249, 92, 3, 92, 33, 92, 40, 92, 65, + 92, 92, 92,126, 92,138, 92,157, 92,168, 92,201, 92,209, 92,220, + 225,242,225,226,233, 99,128, 6,100,226,229,238,231,225,236,105, + 128, 9,234,227,233,242,227,236,101,129, 36, 99, 92, 14,233,238, + 246,229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39, + 141,228,229,246, 97,128, 9,106,231,117, 2, 92, 47, 92, 56,234, + 225,242,225,244,105,128, 10,234,242,237,245,235,232,105,128, 10, + 106,232, 97, 2, 92, 72, 92, 83,227,235,225,242,225,226,233, 99, + 128, 6,100,238,231,250,232,239,117,128, 48, 36,105, 2, 92, 98, + 92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 35,238,230,229,242,233,239,114,128, 32,132,237,239, + 238,239,243,240,225,227,101,128,255, 20,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,247,239,236,228, + 243,244,249,236,101,128,247, 52,112, 2, 92,174, 92,181,225,242, + 229,110,128, 36,119,229,114, 2, 92,188, 92,194,233,239,100,128, + 36,139,243,233,225,110,128, 6,244,242,239,237,225,110,128, 33, + 115,243,245,240,229,242,233,239,114,128, 32,116,116, 2, 92,226, + 93, 8,229,229,110, 2, 92,234, 92,243,227,233,242,227,236,101, + 128, 36,109,112, 2, 92,249, 93, 0,225,242,229,110,128, 36,129, + 229,242,233,239,100,128, 36,149,104, 2, 93, 14, 93, 19,225,105, + 128, 14, 84,244,239,238,229,227,232,233,238,229,243,101,128, 2, + 203,240,225,242,229,110,128, 36,161,242, 97, 2, 93, 48, 93, 56, + 227,244,233,239,110,128, 32, 68,238, 99,128, 32,163,103,144, 0, + 103, 93, 97, 94, 43, 94, 66, 94,127, 94,144, 95, 65, 96, 58, 96, + 143, 96,156, 97, 14, 97, 39, 97, 67, 97, 89, 98, 34, 98, 56, 98, + 158, 97, 9, 93,117, 93,127, 93,134, 93,141, 93,205, 93,230, 93, + 241, 93,252, 94, 30,226,229,238,231,225,236,105,128, 9,151,227, + 245,244,101,128, 1,245,228,229,246, 97,128, 9, 23,102, 4, 93, + 151, 93,160, 93,174, 93,190,225,242,225,226,233, 99,128, 6,175, + 230,233,238,225,236,225,242,225,226,233, 99,128,251,147,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251,148,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,251,149,231,117, 2, + 93,212, 93,221,234,225,242,225,244,105,128, 10,151,242,237,245, + 235,232,105,128, 10, 23,232,233,242,225,231,225,238, 97,128, 48, + 76,235,225,244,225,235,225,238, 97,128, 48,172,237,237, 97,130, + 3,179, 94, 6, 94, 19,236,225,244,233,238,243,237,225,236,108, + 128, 2, 99,243,245,240,229,242,233,239,114,128, 2,224,238,231, + 233,225,227,239,240,244,233, 99,128, 3,235, 98, 2, 94, 49, 94, + 59,239,240,239,237,239,230,111,128, 49, 13,242,229,246,101,128, + 1, 31, 99, 4, 94, 76, 94, 83, 94, 92, 94,114,225,242,239,110, + 128, 1,231,229,228,233,236,236, 97,128, 1, 35,233,242, 99, 2, + 94,100, 94,105,236,101,128, 36,214,245,237,230,236,229,120,128, + 1, 29,239,237,237,225,225,227,227,229,238,116,128, 1, 35,228, + 239,116,129, 1, 33, 94,135,225,227,227,229,238,116,128, 1, 33, + 101, 6, 94,158, 94,169, 94,180, 94,191, 94,210, 95, 56,227,249, + 242,233,236,236,233, 99,128, 4, 51,232,233,242,225,231,225,238, + 97,128, 48, 82,235,225,244,225,235,225,238, 97,128, 48,178,239, + 237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128, + 34, 81,114, 3, 94,218, 95, 11, 95, 21,229,243,104, 3, 94,228, + 94,243, 94,252,225,227,227,229,238,244,232,229,226,242,229,119, + 128, 5,156,232,229,226,242,229,119,128, 5,243,237,245,241,228, + 225,237,232,229,226,242,229,119,128, 5,157,237,225,238,228,226, + 236,115,128, 0,223,243,232,225,249,233,109, 2, 95, 32, 95, 47, + 225,227,227,229,238,244,232,229,226,242,229,119,128, 5,158,232, + 229,226,242,229,119,128, 5,244,244,225,237,225,242,107,128, 48, + 19,104, 5, 95, 77, 95,210, 96, 17, 96, 42, 96, 48, 97, 4, 95, + 87, 95, 97, 95,120, 95,145,226,229,238,231,225,236,105,128, 9, + 152,100, 2, 95,103, 95,114,225,242,237,229,238,233,225,110,128, + 5,114,229,246, 97,128, 9, 24,231,117, 2, 95,127, 95,136,234, + 225,242,225,244,105,128, 10,152,242,237,245,235,232,105,128, 10, + 24,233,110, 4, 95,156, 95,165, 95,179, 95,195,225,242,225,226, + 233, 99,128, 6, 58,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,206,233,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,207,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,208,101, 3, 95,218, 95,239, 96, 0,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,149,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,147, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 145,232, 97, 2, 96, 24, 96, 31,228,229,246, 97,128, 9, 90,231, + 245,242,237,245,235,232,105,128, 10, 90,239,239,107,128, 2, 96, + 250,243,241,245,225,242,101,128, 51,147,105, 3, 96, 66, 96, 77, + 96, 88,232,233,242,225,231,225,238, 97,128, 48, 78,235,225,244, + 225,235,225,238, 97,128, 48,174,109, 2, 96, 94, 96,105,225,242, + 237,229,238,233,225,110,128, 5, 99,229,108,130, 5,210, 96,114, + 96,134,228,225,231,229,243,104,129,251, 50, 96,125,232,229,226, + 242,229,119,128,251, 50,232,229,226,242,229,119,128, 5,210,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 83,236,239,244,244, + 225,108, 2, 96,167, 96,184,233,238,246,229,242,244,229,228,243, + 244,242,239,235,101,128, 1,190,243,244,239,112,132, 2,148, 96, + 199, 96,210, 96,216, 96,248,233,238,246,229,242,244,229,100,128, + 2,150,237,239,100,128, 2,192,242,229,246,229,242,243,229,100, + 130, 2,149, 96,231, 96,237,237,239,100,128, 2,193,243,245,240, + 229,242,233,239,114,128, 2,228,243,244,242,239,235,101,129, 2, + 161, 97, 3,242,229,246,229,242,243,229,100,128, 2,162,109, 2, + 97, 20, 97, 28,225,227,242,239,110,128, 30, 33,239,238,239,243, + 240,225,227,101,128,255, 71,111, 2, 97, 45, 97, 56,232,233,242, + 225,231,225,238, 97,128, 48, 84,235,225,244,225,235,225,238, 97, + 128, 48,180,240, 97, 2, 97, 74, 97, 80,242,229,110,128, 36,162, + 243,241,245,225,242,101,128, 51,172,114, 2, 97, 95, 97,192, 97, + 2, 97,101, 97,109,228,233,229,238,116,128, 34, 7,246,101,134, + 0, 96, 97,126, 97,137, 97,154, 97,161, 97,170, 97,182,226,229, + 236,239,247,227,237, 98,128, 3, 22, 99, 2, 97,143, 97,148,237, + 98,128, 3, 0,239,237, 98,128, 3, 0,228,229,246, 97,128, 9, + 83,236,239,247,237,239,100,128, 2,206,237,239,238,239,243,240, + 225,227,101,128,255, 64,244,239,238,229,227,237, 98,128, 3, 64, + 229,225,244,229,114,132, 0, 62, 97,208, 97,227, 97,239, 98, 26, + 229,241,245,225,108,129, 34,101, 97,218,239,242,236,229,243,115, + 128, 34,219,237,239,238,239,243,240,225,227,101,128,255, 30,111, + 2, 97,245, 98, 15,114, 2, 97,251, 98, 8,229,241,245,233,246, + 225,236,229,238,116,128, 34,115,236,229,243,115,128, 34,119,246, + 229,242,229,241,245,225,108,128, 34,103,243,237,225,236,108,128, + 254,101,115, 2, 98, 40, 98, 48,227,242,233,240,116,128, 2, 97, + 244,242,239,235,101,128, 1,229,117, 4, 98, 66, 98, 77, 98,134, + 98,145,232,233,242,225,231,225,238, 97,128, 48, 80,233,108, 2, + 98, 84, 98,109,236,229,237,239,116, 2, 98, 94, 98,101,236,229, + 230,116,128, 0,171,242,233,231,232,116,128, 0,187,243,233,238, + 231,108, 2, 98,119, 98,126,236,229,230,116,128, 32, 57,242,233, + 231,232,116,128, 32, 58,235,225,244,225,235,225,238, 97,128, 48, + 176,242,225,237,245,243,241,245,225,242,101,128, 51, 24,249,243, + 241,245,225,242,101,128, 51,201,104,144, 0,104, 98,204,101, 90, + 101,125,101,162,101,202,103, 90,103,110,104, 75,104, 87,104, 99, + 105,167,105,175,105,186,105,195,106, 19,106, 23, 97, 13, 98,232, + 99, 15, 99, 25, 99, 55, 99, 80, 99,158, 99,170, 99,195, 99,210, + 99,239, 99,252,100, 54,100, 63, 97, 2, 98,238, 99, 1,226,235, + 232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, 4, + 169,236,244,239,238,229,225,242,225,226,233, 99,128, 6,193,226, + 229,238,231,225,236,105,128, 9,185,228,101, 2, 99, 32, 99, 50, + 243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, + 4,179,246, 97,128, 9, 57,231,117, 2, 99, 62, 99, 71,234,225, + 242,225,244,105,128, 10,185,242,237,245,235,232,105,128, 10, 57, + 104, 4, 99, 90, 99, 99, 99,113, 99,143,225,242,225,226,233, 99, + 128, 6, 45,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 162,105, 2, 99,119, 99,134,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,163,242,225,231,225,238, 97,128, 48,111,237, + 229,228,233,225,236,225,242,225,226,233, 99,128,254,164,233,244, + 245,243,241,245,225,242,101,128, 51, 42,235,225,244,225,235,225, + 238, 97,129, 48,207, 99,183,232,225,236,230,247,233,228,244,104, + 128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128, + 10, 77,237,250, 97, 2, 99,218, 99,227,225,242,225,226,233, 99, + 128, 6, 33,236,239,247,225,242,225,226,233, 99,128, 6, 33,238, + 231,245,236,230,233,236,236,229,114,128, 49,100,114, 2,100, 2, + 100, 18,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, + 4, 74,240,239,239,110, 2,100, 27,100, 40,236,229,230,244,226, + 225,242,226,245,112,128, 33,188,242,233,231,232,244,226,225,242, + 226,245,112,128, 33,192,243,241,245,225,242,101,128, 51,202,244, + 225,102, 3,100, 73,100,165,101, 0,240,225,244,225,104,134, 5, + 178,100, 93,100, 98,100,112,100,121,100,136,100,152,177, 54,128, + 5,178, 50, 2,100,104,100,108, 51,128, 5,178,102,128, 5,178, + 232,229,226,242,229,119,128, 5,178,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,178,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,178,247,233,228,229,232,229,226,242, + 229,119,128, 5,178,241,225,237,225,244,115,135, 5,179,100,188, + 100,193,100,198,100,203,100,212,100,227,100,243,177, 98,128, 5, + 179,178, 56,128, 5,179,179, 52,128, 5,179,232,229,226,242,229, + 119,128, 5,179,238,225,242,242,239,247,232,229,226,242,229,119, + 128, 5,179,241,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,179,247,233,228,229,232,229,226,242,229,119,128, 5,179, + 243,229,231,239,108,135, 5,177,101, 22,101, 27,101, 32,101, 37, + 101, 46,101, 61,101, 77,177, 55,128, 5,177,178, 52,128, 5,177, + 179, 48,128, 5,177,232,229,226,242,229,119,128, 5,177,238,225, + 242,242,239,247,232,229,226,242,229,119,128, 5,177,241,245,225, + 242,244,229,242,232,229,226,242,229,119,128, 5,177,247,233,228, + 229,232,229,226,242,229,119,128, 5,177, 98, 3,101, 98,101,103, + 101,113,225,114,128, 1, 39,239,240,239,237,239,230,111,128, 49, + 15,242,229,246,229,226,229,236,239,119,128, 30, 43, 99, 2,101, + 131,101,140,229,228,233,236,236, 97,128, 30, 41,233,242, 99, 2, + 101,148,101,153,236,101,128, 36,215,245,237,230,236,229,120,128, + 1, 37,100, 2,101,168,101,178,233,229,242,229,243,233,115,128, + 30, 39,239,116, 2,101,185,101,194,225,227,227,229,238,116,128, + 30, 35,226,229,236,239,119,128, 30, 37,101,136, 5,212,101,222, + 101,255,102, 19,102,248,103, 8,103, 53,103, 62,103, 75,225,242, + 116,129, 38,101,101,230,243,245,233,116, 2,101,239,101,247,226, + 236,225,227,107,128, 38,101,247,232,233,244,101,128, 38, 97,228, + 225,231,229,243,104,129,251, 52,102, 10,232,229,226,242,229,119, + 128,251, 52,104, 6,102, 33,102, 61,102, 69,102,119,102,165,102, + 214, 97, 2,102, 39,102, 53,236,244,239,238,229,225,242,225,226, + 233, 99,128, 6,193,242,225,226,233, 99,128, 6, 71,229,226,242, + 229,119,128, 5,212,230,233,238,225,236, 97, 2,102, 80,102,111, + 236,116, 2,102, 87,102, 99,239,238,229,225,242,225,226,233, 99, + 128,251,167,244,247,239,225,242,225,226,233, 99,128,254,234,242, + 225,226,233, 99,128,254,234,232,225,237,250,225,225,226,239,246, + 101, 2,102,134,102,148,230,233,238,225,236,225,242,225,226,233, + 99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,251,164,105, 2,102,171,102,205,238,233,244,233,225, + 236, 97, 2,102,183,102,197,236,244,239,238,229,225,242,225,226, + 233, 99,128,251,168,242,225,226,233, 99,128,254,235,242,225,231, + 225,238, 97,128, 48,120,237,229,228,233,225,236, 97, 2,102,226, + 102,240,236,244,239,238,229,225,242,225,226,233, 99,128,251,169, + 242,225,226,233, 99,128,254,236,233,243,229,233,229,242,225,243, + 241,245,225,242,101,128, 51,123,107, 2,103, 14,103, 38,225,244, + 225,235,225,238, 97,129, 48,216,103, 26,232,225,236,230,247,233, + 228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225, + 242,101,128, 51, 54,238,231,232,239,239,107,128, 2,103,242,245, + 244,245,243,241,245,225,242,101,128, 51, 57,116,129, 5,215,103, + 81,232,229,226,242,229,119,128, 5,215,232,239,239,107,129, 2, + 102,103, 99,243,245,240,229,242,233,239,114,128, 2,177,105, 4, + 103,120,103,205,103,216,103,241,229,245,104, 4,103,132,103,167, + 103,182,103,191, 97, 2,103,138,103,153,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,123,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 27,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,109,235,239,242,229,225,110,128, 49, 78,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 13,232,233,242, + 225,231,225,238, 97,128, 48,114,235,225,244,225,235,225,238, 97, + 129, 48,210,103,229,232,225,236,230,247,233,228,244,104,128,255, + 139,242,233,113,134, 5,180,104, 3,104, 8,104, 22,104, 31,104, + 46,104, 62,177, 52,128, 5,180, 50, 2,104, 14,104, 18, 49,128, + 5,180,100,128, 5,180,232,229,226,242,229,119,128, 5,180,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,180,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,180,247,233, + 228,229,232,229,226,242,229,119,128, 5,180,236,233,238,229,226, + 229,236,239,119,128, 30,150,237,239,238,239,243,240,225,227,101, + 128,255, 72,111, 9,104,119,104,130,104,154,104,179,105, 11,105, + 24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128, + 5,112,232,105, 2,104,137,104,145,240,244,232,225,105,128, 14, + 43,242,225,231,225,238, 97,128, 48,123,235,225,244,225,235,225, + 238, 97,129, 48,219,104,167,232,225,236,230,247,233,228,244,104, + 128,255,142,236,225,109,135, 5,185,104,199,104,204,104,209,104, + 214,104,223,104,238,104,254,177, 57,128, 5,185,178, 54,128, 5, + 185,179, 50,128, 5,185,232,229,226,242,229,119,128, 5,185,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,185,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,185,247,233, + 228,229,232,229,226,242,229,119,128, 5,185,238,239,235,232,245, + 235,244,232,225,105,128, 14, 46,111, 2,105, 30,105,100,107, 4, + 105, 40,105, 52,105, 58,105, 80,225,226,239,246,229,227,239,237, + 98,128, 3, 9,227,237, 98,128, 3, 9,240,225,236,225,244,225, + 236,233,250,229,228,226,229,236,239,247,227,237, 98,128, 3, 33, + 242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237, + 98,128, 3, 34,238,243,241,245,225,242,101,128, 51, 66,114, 2, + 105,116,105,143,105, 2,105,122,105,131,227,239,240,244,233, 99, + 128, 3,233,250,239,238,244,225,236,226,225,114,128, 32, 21,238, + 227,237, 98,128, 3, 27,244,243,240,242,233,238,231,115,128, 38, + 104,245,243,101,128, 35, 2,240,225,242,229,110,128, 36,163,243, + 245,240,229,242,233,239,114,128, 2,176,244,245,242,238,229,100, + 128, 2,101,117, 4,105,205,105,216,105,229,105,254,232,233,242, + 225,231,225,238, 97,128, 48,117,233,233,244,239,243,241,245,225, + 242,101,128, 51, 51,235,225,244,225,235,225,238, 97,129, 48,213, + 105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231, + 225,242,245,237,236,225,245,116,129, 2,221,106, 13,227,237, 98, + 128, 3, 11,118,128, 1,149,249,240,232,229,110,132, 0, 45,106, + 39,106, 50,106, 62,106, 85,233,238,230,229,242,233,239,114,128, + 246,229,237,239,238,239,243,240,225,227,101,128,255, 13,115, 2, + 106, 68,106, 75,237,225,236,108,128,254, 99,245,240,229,242,233, + 239,114,128,246,230,244,247,111,128, 32, 16,105,149, 0,105,106, + 137,106,160,106,194,106,241,110,123,110,243,111, 24,111, 51,111, + 213,111,217,111,255,112, 21,112,105,113, 14,113, 89,113, 97,113, + 110,113,197,113,254,114, 26,114, 70,225, 99, 2,106,144,106,150, + 245,244,101,128, 0,237,249,242,233,236,236,233, 99,128, 4, 79, + 98, 3,106,168,106,177,106,187,229,238,231,225,236,105,128, 9, + 135,239,240,239,237,239,230,111,128, 49, 39,242,229,246,101,128, + 1, 45, 99, 3,106,202,106,209,106,231,225,242,239,110,128, 1, + 208,233,242, 99, 2,106,217,106,222,236,101,128, 36,216,245,237, + 230,236,229,120,128, 0,238,249,242,233,236,236,233, 99,128, 4, + 86,100, 4,106,251,107, 5,110, 80,110,113,226,236,231,242,225, + 246,101,128, 2, 9,101, 2,107, 11,110, 75,239,231,242,225,240, + 104, 7,107, 32,107, 46,107, 59,109,244,110, 19,110, 32,110, 44, + 229,225,242,244,232,227,233,242,227,236,101,128, 50,143,230,233, + 242,229,227,233,242,227,236,101,128, 50,139,233, 99, 14,107, 90, + 107,106,107,205,108, 3,108, 69,108, 98,108,114,108,171,108,220, + 108,232,109, 3,109, 70,109,208,109,237,225,236,236,233,225,238, + 227,229,240,225,242,229,110,128, 50, 63, 99, 4,107,116,107,127, + 107,141,107,148,225,236,236,240,225,242,229,110,128, 50, 58,229, + 238,244,242,229,227,233,242,227,236,101,128, 50,165,236,239,243, + 101,128, 48, 6,111, 3,107,156,107,171,107,191,237,237, 97,129, + 48, 1,107,164,236,229,230,116,128,255,100,238,231,242,225,244, + 245,236,225,244,233,239,238,240,225,242,229,110,128, 50, 55,242, + 242,229,227,244,227,233,242,227,236,101,128, 50,163,101, 3,107, + 213,107,225,107,242,225,242,244,232,240,225,242,229,110,128, 50, + 47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128, + 50, 61,248,227,229,236,236,229,238,244,227,233,242,227,236,101, + 128, 50,157,102, 2,108, 9,108, 24,229,243,244,233,246,225,236, + 240,225,242,229,110,128, 50, 64,105, 2,108, 30,108, 59,238,225, + 238,227,233,225,108, 2,108, 42,108, 51,227,233,242,227,236,101, + 128, 50,150,240,225,242,229,110,128, 50, 54,242,229,240,225,242, + 229,110,128, 50, 43,104, 2,108, 75,108, 86,225,246,229,240,225, + 242,229,110,128, 50, 50,233,231,232,227,233,242,227,236,101,128, + 50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128, + 48, 5,108, 3,108,122,108,148,108,160,225,226,239,114, 2,108, + 131,108,140,227,233,242,227,236,101,128, 50,152,240,225,242,229, + 110,128, 50, 56,229,230,244,227,233,242,227,236,101,128, 50,167, + 239,247,227,233,242,227,236,101,128, 50,166,109, 2,108,177,108, + 209,101, 2,108,183,108,198,228,233,227,233,238,229,227,233,242, + 227,236,101,128, 50,169,244,225,236,240,225,242,229,110,128, 50, + 46,239,239,238,240,225,242,229,110,128, 50, 42,238,225,237,229, + 240,225,242,229,110,128, 50, 52,112, 2,108,238,108,246,229,242, + 233,239,100,128, 48, 2,242,233,238,244,227,233,242,227,236,101, + 128, 50,158,114, 2,109, 9,109, 57,101, 3,109, 17,109, 28,109, + 43,225,227,232,240,225,242,229,110,128, 50, 67,240,242,229,243, + 229,238,244,240,225,242,229,110,128, 50, 57,243,239,245,242,227, + 229,240,225,242,229,110,128, 50, 62,233,231,232,244,227,233,242, + 227,236,101,128, 50,168,115, 5,109, 82,109,111,109,125,109,150, + 109,178,101, 2,109, 88,109,101,227,242,229,244,227,233,242,227, + 236,101,128, 50,153,236,230,240,225,242,229,110,128, 50, 66,239, + 227,233,229,244,249,240,225,242,229,110,128, 50, 51,112, 2,109, + 131,109,137,225,227,101,128, 48, 0,229,227,233,225,236,240,225, + 242,229,110,128, 50, 53,116, 2,109,156,109,167,239,227,235,240, + 225,242,229,110,128, 50, 49,245,228,249,240,225,242,229,110,128, + 50, 59,117, 2,109,184,109,193,238,240,225,242,229,110,128, 50, + 48,240,229,242,246,233,243,229,240,225,242,229,110,128, 50, 60, + 119, 2,109,214,109,226,225,244,229,242,240,225,242,229,110,128, + 50, 44,239,239,228,240,225,242,229,110,128, 50, 45,250,229,242, + 111,128, 48, 7,109, 2,109,250,110, 7,229,244,225,236,227,233, + 242,227,236,101,128, 50,142,239,239,238,227,233,242,227,236,101, + 128, 50,138,238,225,237,229,227,233,242,227,236,101,128, 50,148, + 243,245,238,227,233,242,227,236,101,128, 50,144,119, 2,110, 50, + 110, 63,225,244,229,242,227,233,242,227,236,101,128, 50,140,239, + 239,228,227,233,242,227,236,101,128, 50,141,246, 97,128, 9, 7, + 233,229,242,229,243,233,115,130, 0,239,110, 94,110,102,225,227, + 245,244,101,128, 30, 47,227,249,242,233,236,236,233, 99,128, 4, + 229,239,244,226,229,236,239,119,128, 30,203,101, 3,110,131,110, + 147,110,158,226,242,229,246,229,227,249,242,233,236,236,233, 99, + 128, 4,215,227,249,242,233,236,236,233, 99,128, 4, 53,245,238, + 103, 4,110,170,110,205,110,220,110,229, 97, 2,110,176,110,191, + 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,117,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 21,227,233,242, + 227,236,229,235,239,242,229,225,110,128, 50,103,235,239,242,229, + 225,110,128, 49, 71,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 7,103, 2,110,249,111, 0,242,225,246,101,128, 0,236, + 117, 2,111, 6,111, 15,234,225,242,225,244,105,128, 10,135,242, + 237,245,235,232,105,128, 10, 7,104, 2,111, 30,111, 40,233,242, + 225,231,225,238, 97,128, 48, 68,239,239,235,225,226,239,246,101, + 128, 30,201,105, 8,111, 69,111, 79,111, 90,111, 97,111,122,111, + 138,111,153,111,169,226,229,238,231,225,236,105,128, 9,136,227, + 249,242,233,236,236,233, 99,128, 4, 56,228,229,246, 97,128, 9, + 8,231,117, 2,111,104,111,113,234,225,242,225,244,105,128, 10, + 136,242,237,245,235,232,105,128, 10, 8,237,225,244,242,225,231, + 245,242,237,245,235,232,105,128, 10, 64,238,246,229,242,244,229, + 228,226,242,229,246,101,128, 2, 11,243,232,239,242,244,227,249, + 242,233,236,236,233, 99,128, 4, 57,246,239,247,229,236,243,233, + 231,110, 3,111,185,111,195,111,202,226,229,238,231,225,236,105, + 128, 9,192,228,229,246, 97,128, 9, 64,231,245,234,225,242,225, + 244,105,128, 10,192,106,128, 1, 51,107, 2,111,223,111,247,225, + 244,225,235,225,238, 97,129, 48,164,111,235,232,225,236,230,247, + 233,228,244,104,128,255,114,239,242,229,225,110,128, 49, 99,108, + 2,112, 5,112, 10,228,101,128, 2,220,245,249,232,229,226,242, + 229,119,128, 5,172,109, 2,112, 27,112, 94, 97, 3,112, 35,112, + 55,112, 80,227,242,239,110,129, 1, 43,112, 44,227,249,242,233, + 236,236,233, 99,128, 4,227,231,229,239,242,225,240,240,242,239, + 248,233,237,225,244,229,236,249,229,241,245,225,108,128, 34, 83, + 244,242,225,231,245,242,237,245,235,232,105,128, 10, 63,239,238, + 239,243,240,225,227,101,128,255, 73,110, 5,112,117,112,127,112, + 136,112,148,112,232,227,242,229,237,229,238,116,128, 34, 6,230, + 233,238,233,244,121,128, 34, 30,233,225,242,237,229,238,233,225, + 110,128, 5,107,116, 2,112,154,112,222,101, 2,112,160,112,211, + 231,242,225,108,131, 34, 43,112,173,112,191,112,196, 98, 2,112, + 179,112,187,239,244,244,239,109,128, 35, 33,116,128, 35, 33,229, + 120,128,248,245,116, 2,112,202,112,207,239,112,128, 35, 32,112, + 128, 35, 32,242,243,229,227,244,233,239,110,128, 34, 41,233,243, + 241,245,225,242,101,128, 51, 5,118, 3,112,240,112,249,113, 2, + 226,245,236,236,229,116,128, 37,216,227,233,242,227,236,101,128, + 37,217,243,237,233,236,229,230,225,227,101,128, 38, 59,111, 3, + 113, 22,113, 33,113, 41,227,249,242,233,236,236,233, 99,128, 4, + 81,231,239,238,229,107,128, 1, 47,244, 97,131, 3,185,113, 52, + 113, 73,113, 81,228,233,229,242,229,243,233,115,129, 3,202,113, + 65,244,239,238,239,115,128, 3,144,236,225,244,233,110,128, 2, + 105,244,239,238,239,115,128, 3,175,240,225,242,229,110,128, 36, + 164,242,233,231,245,242,237,245,235,232,105,128, 10,114,115, 4, + 113,120,113,165,113,179,113,187,237,225,236,108, 2,113,129,113, + 140,232,233,242,225,231,225,238, 97,128, 48, 67,235,225,244,225, + 235,225,238, 97,129, 48,163,113,153,232,225,236,230,247,233,228, + 244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105, + 128, 9,250,244,242,239,235,101,128, 2,104,245,240,229,242,233, + 239,114,128,246,237,116, 2,113,203,113,237,229,242,225,244,233, + 239,110, 2,113,215,113,226,232,233,242,225,231,225,238, 97,128, + 48,157,235,225,244,225,235,225,238, 97,128, 48,253,233,236,228, + 101,129, 1, 41,113,246,226,229,236,239,119,128, 30, 45,117, 2, + 114, 4,114, 15,226,239,240,239,237,239,230,111,128, 49, 41,227, + 249,242,233,236,236,233, 99,128, 4, 78,246,239,247,229,236,243, + 233,231,110, 3,114, 42,114, 52,114, 59,226,229,238,231,225,236, + 105,128, 9,191,228,229,246, 97,128, 9, 63,231,245,234,225,242, + 225,244,105,128, 10,191,250,232,233,244,243, 97, 2,114, 81,114, + 92,227,249,242,233,236,236,233, 99,128, 4,117,228,226,236,231, + 242,225,246,229,227,249,242,233,236,236,233, 99,128, 4,119,106, + 138, 0,106,114,135,114,198,114,209,115, 3,115, 19,115,132,115, + 201,115,206,115,218,115,226, 97, 4,114,145,114,156,114,166,114, + 173,225,242,237,229,238,233,225,110,128, 5,113,226,229,238,231, + 225,236,105,128, 9,156,228,229,246, 97,128, 9, 28,231,117, 2, + 114,180,114,189,234,225,242,225,244,105,128, 10,156,242,237,245, + 235,232,105,128, 10, 28,226,239,240,239,237,239,230,111,128, 49, + 16, 99, 3,114,217,114,224,114,246,225,242,239,110,128, 1,240, + 233,242, 99, 2,114,232,114,237,236,101,128, 36,217,245,237,230, + 236,229,120,128, 1, 53,242,239,243,243,229,228,244,225,233,108, + 128, 2,157,228,239,244,236,229,243,243,243,244,242,239,235,101, + 128, 2, 95,101, 3,115, 27,115, 38,115,103,227,249,242,233,236, + 236,233, 99,128, 4, 88,229,109, 4,115, 49,115, 58,115, 72,115, + 88,225,242,225,226,233, 99,128, 6, 44,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,158,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,159,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,160,104, 2,115,109,115,118,225,242,225, + 226,233, 99,128, 6,152,230,233,238,225,236,225,242,225,226,233, + 99,128,251,139,104, 2,115,138,115,188, 97, 3,115,146,115,156, + 115,163,226,229,238,231,225,236,105,128, 9,157,228,229,246, 97, + 128, 9, 29,231,117, 2,115,170,115,179,234,225,242,225,244,105, + 128, 10,157,242,237,245,235,232,105,128, 10, 29,229,232,225,242, + 237,229,238,233,225,110,128, 5,123,233,115,128, 48, 4,237,239, + 238,239,243,240,225,227,101,128,255, 74,240,225,242,229,110,128, + 36,165,243,245,240,229,242,233,239,114,128, 2,178,107,146, 0, + 107,116, 21,118,110,118,121,118,183,118,194,119, 28,119, 42,120, + 150,121, 90,121,103,121,129,121,178,122, 60,122, 82,122, 95,122, + 118,122,160,122,170, 97, 12,116, 47,116, 79,116,101,116,131,116, + 245,117, 14,117, 44,117, 69,117,175,117,189,118, 56,118, 85, 98, + 2,116, 53,116, 70,225,243,232,235,233,242,227,249,242,233,236, + 236,233, 99,128, 4,161,229,238,231,225,236,105,128, 9,149, 99, + 2,116, 85,116, 91,245,244,101,128, 30, 49,249,242,233,236,236, + 233, 99,128, 4, 58,228,101, 2,116,108,116,126,243,227,229,238, + 228,229,242,227,249,242,233,236,236,233, 99,128, 4,155,246, 97, + 128, 9, 21,102,135, 5,219,116,149,116,158,116,178,116,192,116, + 201,116,217,116,232,225,242,225,226,233, 99,128, 6, 67,228,225, + 231,229,243,104,129,251, 59,116,169,232,229,226,242,229,119,128, + 251, 59,230,233,238,225,236,225,242,225,226,233, 99,128,254,218, + 232,229,226,242,229,119,128, 5,219,233,238,233,244,233,225,236, + 225,242,225,226,233, 99,128,254,219,237,229,228,233,225,236,225, + 242,225,226,233, 99,128,254,220,242,225,230,229,232,229,226,242, + 229,119,128,251, 77,231,117, 2,116,252,117, 5,234,225,242,225, + 244,105,128, 10,149,242,237,245,235,232,105,128, 10, 21,104, 2, + 117, 20,117, 30,233,242,225,231,225,238, 97,128, 48, 75,239,239, + 235,227,249,242,233,236,236,233, 99,128, 4,196,235,225,244,225, + 235,225,238, 97,129, 48,171,117, 57,232,225,236,230,247,233,228, + 244,104,128,255,118,112, 2,117, 75,117, 96,240, 97,129, 3,186, + 117, 82,243,249,237,226,239,236,231,242,229,229,107,128, 3,240, + 249,229,239,245,110, 3,117,108,117,122,117,156,237,233,229,245, + 237,235,239,242,229,225,110,128, 49,113,112, 2,117,128,117,143, + 232,233,229,245,240,232,235,239,242,229,225,110,128, 49,132,233, + 229,245,240,235,239,242,229,225,110,128, 49,120,243,243,225,238, + 231,240,233,229,245,240,235,239,242,229,225,110,128, 49,121,242, + 239,242,233,233,243,241,245,225,242,101,128, 51, 13,115, 5,117, + 201,117,245,118, 4,118, 12,118, 40,232,233,228,225,225,245,244, + 111, 2,117,214,117,223,225,242,225,226,233, 99,128, 6, 64,238, + 239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226, + 233, 99,128, 6, 64,237,225,236,236,235,225,244,225,235,225,238, + 97,128, 48,245,241,245,225,242,101,128, 51,132,242, 97, 2,118, + 19,118, 28,225,242,225,226,233, 99,128, 6, 80,244,225,238,225, + 242,225,226,233, 99,128, 6, 77,244,242,239,235,229,227,249,242, + 233,236,236,233, 99,128, 4,159,244,225,232,233,242,225,240,242, + 239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228, + 244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,157,226,239, + 240,239,237,239,230,111,128, 49, 14, 99, 4,118,131,118,153,118, + 162,118,170, 97, 2,118,137,118,147,236,243,241,245,225,242,101, + 128, 51,137,242,239,110,128, 1,233,229,228,233,236,236, 97,128, + 1, 55,233,242,227,236,101,128, 36,218,239,237,237,225,225,227, + 227,229,238,116,128, 1, 55,228,239,244,226,229,236,239,119,128, + 30, 51,101, 4,118,204,118,231,119, 0,119, 12,104, 2,118,210, + 118,221,225,242,237,229,238,233,225,110,128, 5,132,233,242,225, + 231,225,238, 97,128, 48, 81,235,225,244,225,235,225,238, 97,129, + 48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121, + 238,225,242,237,229,238,233,225,110,128, 5,111,243,237,225,236, + 236,235,225,244,225,235,225,238, 97,128, 48,246,231,242,229,229, + 238,236,225,238,228,233, 99,128, 1, 56,104, 6,119, 56,119,185, + 119,196,119,221,120, 52,120,140, 97, 5,119, 68,119, 78,119, 89, + 119, 96,119,121,226,229,238,231,225,236,105,128, 9,150,227,249, + 242,233,236,236,233, 99,128, 4, 69,228,229,246, 97,128, 9, 22, + 231,117, 2,119,103,119,112,234,225,242,225,244,105,128, 10,150, + 242,237,245,235,232,105,128, 10, 22,104, 4,119,131,119,140,119, + 154,119,170,225,242,225,226,233, 99,128, 6, 46,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,166,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,167,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,168,229,233,227,239,240,244,233, + 99,128, 3,231,232, 97, 2,119,203,119,210,228,229,246, 97,128, + 9, 89,231,245,242,237,245,235,232,105,128, 10, 89,233,229,245, + 235,104, 4,119,235,120, 14,120, 29,120, 38, 97, 2,119,241,120, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,120, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 24,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,106,235,239,242, + 229,225,110,128, 49, 75,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 10,111, 4,120, 62,120,111,120,121,120,126,235,104, + 4,120, 73,120, 82,120, 91,120,101,225,233,244,232,225,105,128, + 14, 2,239,238,244,232,225,105,128, 14, 5,245,225,244,244,232, + 225,105,128, 14, 3,247,225,233,244,232,225,105,128, 14, 4,237, + 245,244,244,232,225,105,128, 14, 91,239,107,128, 1,153,242,225, + 235,232,225,238,231,244,232,225,105,128, 14, 6,250,243,241,245, + 225,242,101,128, 51,145,105, 4,120,160,120,171,120,196,120,245, + 232,233,242,225,231,225,238, 97,128, 48, 77,235,225,244,225,235, + 225,238, 97,129, 48,173,120,184,232,225,236,230,247,233,228,244, + 104,128,255,119,242,111, 3,120,205,120,220,120,236,231,245,242, + 225,237,245,243,241,245,225,242,101,128, 51, 21,237,229,229,244, + 239,242,245,243,241,245,225,242,101,128, 51, 22,243,241,245,225, + 242,101,128, 51, 20,249,229,239,107, 5,121, 4,121, 39,121, 54, + 121, 63,121, 77, 97, 2,121, 10,121, 25,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,110,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 14,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50, 96,235,239,242,229,225,110,128, 49, 49,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 0,243,233,239, + 243,235,239,242,229,225,110,128, 49, 51,234,229,227,249,242,233, + 236,236,233, 99,128, 4, 92,108, 2,121,109,121,120,233,238,229, + 226,229,236,239,119,128, 30, 53,243,241,245,225,242,101,128, 51, + 152,109, 3,121,137,121,151,121,162,227,245,226,229,228,243,241, + 245,225,242,101,128, 51,166,239,238,239,243,240,225,227,101,128, + 255, 75,243,241,245,225,242,229,228,243,241,245,225,242,101,128, + 51,162,111, 5,121,190,121,216,121,254,122, 10,122, 24,104, 2, + 121,196,121,206,233,242,225,231,225,238, 97,128, 48, 83,237,243, + 241,245,225,242,101,128, 51,192,235, 97, 2,121,223,121,231,233, + 244,232,225,105,128, 14, 1,244,225,235,225,238, 97,129, 48,179, + 121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240, + 239,243,241,245,225,242,101,128, 51, 30,240,240,225,227,249,242, + 233,236,236,233, 99,128, 4,129,114, 2,122, 30,122, 50,229,225, + 238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128, + 50,127,239,238,233,243,227,237, 98,128, 3, 67,240, 97, 2,122, + 67,122, 73,242,229,110,128, 36,166,243,241,245,225,242,101,128, + 51,170,243,233,227,249,242,233,236,236,233, 99,128, 4,111,116, + 2,122,101,122,110,243,241,245,225,242,101,128, 51,207,245,242, + 238,229,100,128, 2,158,117, 2,122,124,122,135,232,233,242,225, + 231,225,238, 97,128, 48, 79,235,225,244,225,235,225,238, 97,129, + 48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120, + 246,243,241,245,225,242,101,128, 51,184,247,243,241,245,225,242, + 101,128, 51,190,108,146, 0,108,122,220,124,247,125, 20,125, 86, + 125,124,126, 20,126, 29,126, 45,126, 69,126, 87,126,205,126,246, + 127,125,127,133,127,166,127,175,127,183,127,245, 97, 7,122,236, + 122,246,122,253,123, 4,123, 29,123, 45,124,235,226,229,238,231, + 225,236,105,128, 9,178,227,245,244,101,128, 1, 58,228,229,246, + 97,128, 9, 50,231,117, 2,123, 11,123, 20,234,225,242,225,244, + 105,128, 10,178,242,237,245,235,232,105,128, 10, 50,235,235,232, + 225,238,231,249,225,239,244,232,225,105,128, 14, 69,109, 10,123, + 67,124, 6,124, 23,124, 61,124, 75,124, 94,124,110,124,130,124, + 150,124,173, 97, 2,123, 73,123,254,236,229,102, 4,123, 85,123, + 99,123,191,123,208,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,252,232,225,237,250, 97, 2,123,109,123,150,225,226,239, + 246,101, 2,123,119,123,133,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,248,233,243,239,236,225,244,229,228,225,242,225, + 226,233, 99,128,254,247,226,229,236,239,119, 2,123,160,123,174, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,250,233,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,254,249,233, + 243,239,236,225,244,229,228,225,242,225,226,233, 99,128,254,251, + 237,225,228,228,225,225,226,239,246,101, 2,123,223,123,237,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,246,233,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,254,245,242,225, + 226,233, 99,128, 6, 68,226,228, 97,129, 3,187,124, 14,243,244, + 242,239,235,101,128, 1,155,229,100,130, 5,220,124, 32,124, 52, + 228,225,231,229,243,104,129,251, 60,124, 43,232,229,226,242,229, + 119,128,251, 60,232,229,226,242,229,119,128, 5,220,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,222,232,225,232,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,202,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,223,234,229, + 229,237,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,252,203,236,225,237,232,229,232,233,243,239,236, + 225,244,229,228,225,242,225,226,233, 99,128,253,242,237,101, 2, + 124,180,124,193,228,233,225,236,225,242,225,226,233, 99,128,254, + 224,229,109, 2,124,200,124,219,232,225,232,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,253,136,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,252,204,242,231,229,227,233, + 242,227,236,101,128, 37,239, 98, 3,124,255,125, 4,125, 10,225, + 114,128, 1,154,229,236,116,128, 2,108,239,240,239,237,239,230, + 111,128, 49, 12, 99, 4,125, 30,125, 37,125, 46,125, 73,225,242, + 239,110,128, 1, 62,229,228,233,236,236, 97,128, 1, 60,233,242, + 99, 2,125, 54,125, 59,236,101,128, 36,219,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 61,239,237,237,225,225,227,227, + 229,238,116,128, 1, 60,228,239,116,130, 1, 64,125, 96,125,105, + 225,227,227,229,238,116,128, 1, 64,226,229,236,239,119,129, 30, + 55,125,115,237,225,227,242,239,110,128, 30, 57,101, 3,125,132, + 125,170,126, 15,230,116, 2,125,139,125,155,225,238,231,236,229, + 225,226,239,246,229,227,237, 98,128, 3, 26,244,225,227,235,226, + 229,236,239,247,227,237, 98,128, 3, 24,243,115,132, 0, 60,125, + 183,125,205,125,217,126, 7,229,241,245,225,108,129, 34,100,125, + 193,239,242,231,242,229,225,244,229,114,128, 34,218,237,239,238, + 239,243,240,225,227,101,128,255, 28,111, 2,125,223,125,252,114, + 2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128, + 34,114,231,242,229,225,244,229,114,128, 34,118,246,229,242,229, + 241,245,225,108,128, 34,102,243,237,225,236,108,128,254,100,250, + 104,128, 2,110,230,226,236,239,227,107,128, 37,140,232,239,239, + 235,242,229,244,242,239,230,236,229,120,128, 2,109,105, 2,126, + 51,126, 56,242, 97,128, 32,164,247,238,225,242,237,229,238,233, + 225,110,128, 5,108,106,129, 1,201,126, 75,229,227,249,242,233, + 236,236,233, 99,128, 4, 89,108,132,246,192,126, 99,126,123,126, + 134,126,143, 97, 2,126,105,126,112,228,229,246, 97,128, 9, 51, + 231,245,234,225,242,225,244,105,128, 10,179,233,238,229,226,229, + 236,239,119,128, 30, 59,236,225,228,229,246, 97,128, 9, 52,246, + 239,227,225,236,233, 99, 3,126,157,126,167,126,174,226,229,238, + 231,225,236,105,128, 9,225,228,229,246, 97,128, 9, 97,246,239, + 247,229,236,243,233,231,110, 2,126,188,126,198,226,229,238,231, + 225,236,105,128, 9,227,228,229,246, 97,128, 9, 99,109, 3,126, + 213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128, + 2,107,239,238,239,243,240,225,227,101,128,255, 76,243,241,245, + 225,242,101,128, 51,208,111, 6,127, 4,127, 16,127, 58,127, 69, + 127, 75,127,117,227,232,245,236,225,244,232,225,105,128, 14, 44, + 231,233,227,225,108, 3,127, 28,127, 34,127, 53,225,238,100,128, + 34, 39,238,239,116,129, 0,172,127, 42,242,229,246,229,242,243, + 229,100,128, 35, 16,239,114,128, 34, 40,236,233,238,231,244,232, + 225,105,128, 14, 37,238,231,115,128, 1,127,247,236,233,238,101, + 2,127, 85,127,108, 99, 2,127, 91,127,103,229,238,244,229,242, + 236,233,238,101,128,254, 78,237, 98,128, 3, 50,228,225,243,232, + 229,100,128,254, 77,250,229,238,231,101,128, 37,202,240,225,242, + 229,110,128, 36,167,115, 3,127,141,127,148,127,156,236,225,243, + 104,128, 1, 66,241,245,225,242,101,128, 33, 19,245,240,229,242, + 233,239,114,128,246,238,244,243,232,225,228,101,128, 37,145,245, + 244,232,225,105,128, 14, 38,246,239,227,225,236,233, 99, 3,127, + 197,127,207,127,214,226,229,238,231,225,236,105,128, 9,140,228, + 229,246, 97,128, 9, 12,246,239,247,229,236,243,233,231,110, 2, + 127,228,127,238,226,229,238,231,225,236,105,128, 9,226,228,229, + 246, 97,128, 9, 98,248,243,241,245,225,242,101,128, 51,211,109, + 144, 0,109,128, 35,130,144,130,169,130,196,130,221,132, 18,132, + 40,133, 95,133,125,133,174,134, 25,134, 47,134, 72,134, 81,135, + 108,135,136, 97, 12,128, 61,128, 71,128,135,128,142,128,167,128, + 215,130, 51,130, 76,130, 81,130, 95,130,107,130,112,226,229,238, + 231,225,236,105,128, 9,174, 99, 2,128, 77,128,129,242,239,110, + 132, 0,175,128, 91,128,102,128,108,128,117,226,229,236,239,247, + 227,237, 98,128, 3, 49,227,237, 98,128, 3, 4,236,239,247,237, + 239,100,128, 2,205,237,239,238,239,243,240,225,227,101,128,255, + 227,245,244,101,128, 30, 63,228,229,246, 97,128, 9, 46,231,117, + 2,128,149,128,158,234,225,242,225,244,105,128, 10,174,242,237, + 245,235,232,105,128, 10, 46,104, 2,128,173,128,205,225,240,225, + 235,104, 2,128,183,128,192,232,229,226,242,229,119,128, 5,164, + 236,229,230,244,232,229,226,242,229,119,128, 5,164,233,242,225, + 231,225,238, 97,128, 48,126,105, 5,128,227,129, 40,129,103,129, + 133,130, 39,227,232,225,244,244,225,247, 97, 3,128,242,129, 17, + 129, 24,236,239,119, 2,128,250,129, 5,236,229,230,244,244,232, + 225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248, + 148,244,232,225,105,128, 14, 75,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,147,229,107, 3,129, 49,129, 80,129, + 87,236,239,119, 2,129, 57,129, 68,236,229,230,244,244,232,225, + 105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139, + 244,232,225,105,128, 14, 72,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,138,232,225,238,225,235,225,116, 2,129, + 115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232, + 225,105,128, 14, 49,116, 3,129,141,129,169,129,232,225,233,235, + 232,117, 2,129,151,129,162,236,229,230,244,244,232,225,105,128, + 248,137,244,232,225,105,128, 14, 71,232,111, 3,129,178,129,209, + 129,216,236,239,119, 2,129,186,129,197,236,229,230,244,244,232, + 225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248, + 142,244,232,225,105,128, 14, 73,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,141,242,105, 3,129,241,130, 16,130, + 23,236,239,119, 2,129,249,130, 4,236,229,230,244,244,232,225, + 105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145, + 244,232,225,105,128, 14, 74,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105, + 128, 14, 70,235,225,244,225,235,225,238, 97,129, 48,222,130, 64, + 232,225,236,230,247,233,228,244,104,128,255,143,236,101,128, 38, + 66,238,243,249,239,238,243,241,245,225,242,101,128, 51, 71,241, + 225,230,232,229,226,242,229,119,128, 5,190,242,115,128, 38, 66, + 115, 2,130,118,130,136,239,242,225,227,233,242,227,236,229,232, + 229,226,242,229,119,128, 5,175,241,245,225,242,101,128, 51,131, + 98, 2,130,150,130,160,239,240,239,237,239,230,111,128, 49, 7, + 243,241,245,225,242,101,128, 51,212, 99, 2,130,175,130,183,233, + 242,227,236,101,128, 36,220,245,226,229,228,243,241,245,225,242, + 101,128, 51,165,228,239,116, 2,130,204,130,213,225,227,227,229, + 238,116,128, 30, 65,226,229,236,239,119,128, 30, 67,101, 7,130, + 237,131,108,131,119,131,134,131,159,131,196,131,208,101, 2,130, + 243,131, 95,109, 4,130,253,131, 6,131, 20,131, 36,225,242,225, + 226,233, 99,128, 6, 69,230,233,238,225,236,225,242,225,226,233, + 99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,227,237,101, 2,131, 43,131, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,228,229,237,105, 2,131, 64,131, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,209,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 72,244, + 239,242,245,243,241,245,225,242,101,128, 51, 77,232,233,242,225, + 231,225,238, 97,128, 48,129,233,250,233,229,242,225,243,241,245, + 225,242,101,128, 51,126,235,225,244,225,235,225,238, 97,129, 48, + 225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109, + 130, 5,222,131,167,131,187,228,225,231,229,243,104,129,251, 62, + 131,178,232,229,226,242,229,119,128,251, 62,232,229,226,242,229, + 119,128, 5,222,238,225,242,237,229,238,233,225,110,128, 5,116, + 242,235,232, 97, 3,131,219,131,228,132, 5,232,229,226,242,229, + 119,128, 5,165,235,229,230,245,236, 97, 2,131,239,131,248,232, + 229,226,242,229,119,128, 5,166,236,229,230,244,232,229,226,242, + 229,119,128, 5,166,236,229,230,244,232,229,226,242,229,119,128, + 5,165,104, 2,132, 24,132, 30,239,239,107,128, 2,113,250,243, + 241,245,225,242,101,128, 51,146,105, 6,132, 54,132, 91,132,228, + 132,239,133, 8,133, 65,228,100, 2,132, 61,132, 86,236,229,228, + 239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233, + 228,244,104,128,255,101,239,116,128, 0,183,229,245,109, 5,132, + 105,132,140,132,155,132,164,132,215, 97, 2,132,111,132,126,227, + 233,242,227,236,229,235,239,242,229,225,110,128, 50,114,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 18,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,100,235,239,242,229,225, + 110,128, 49, 65,112, 2,132,170,132,202, 97, 2,132,176,132,190, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,112,242,229, + 238,235,239,242,229,225,110,128, 50, 4,233,229,245,240,235,239, + 242,229,225,110,128, 49,110,243,233,239,243,235,239,242,229,225, + 110,128, 49,111,232,233,242,225,231,225,238, 97,128, 48,127,235, + 225,244,225,235,225,238, 97,129, 48,223,132,252,232,225,236,230, + 247,233,228,244,104,128,255,144,238,117, 2,133, 15,133, 60,115, + 132, 34, 18,133, 27,133, 38,133, 47,133, 53,226,229,236,239,247, + 227,237, 98,128, 3, 32,227,233,242,227,236,101,128, 34,150,237, + 239,100,128, 2,215,240,236,245,115,128, 34, 19,244,101,128, 32, + 50,242,105, 2,133, 72,133, 86,226,225,225,242,245,243,241,245, + 225,242,101,128, 51, 74,243,241,245,225,242,101,128, 51, 73,108, + 2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229, + 100,128, 2,112,243,241,245,225,242,101,128, 51,150,109, 3,133, + 133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101, + 128, 51,163,239,238,239,243,240,225,227,101,128,255, 77,243,241, + 245,225,242,229,228,243,241,245,225,242,101,128, 51,159,111, 5, + 133,186,133,212,133,237,133,247,134, 0,104, 2,133,192,133,202, + 233,242,225,231,225,238, 97,128, 48,130,237,243,241,245,225,242, + 101,128, 51,193,235,225,244,225,235,225,238, 97,129, 48,226,133, + 225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241, + 245,225,242,101,128, 51,214,237,225,244,232,225,105,128, 14, 33, + 246,229,242,243,243,241,245,225,242,101,129, 51,167,134, 15,228, + 243,241,245,225,242,101,128, 51,168,240, 97, 2,134, 32,134, 38, + 242,229,110,128, 36,168,243,241,245,225,242,101,128, 51,171,115, + 2,134, 53,134, 62,243,241,245,225,242,101,128, 51,179,245,240, + 229,242,233,239,114,128,246,239,244,245,242,238,229,100,128, 2, + 111,117,141, 0,181,134,111,134,115,134,125,134,149,134,159,134, + 181,134,192,134,217,134,240,134,250,135, 24,135, 88,135, 98, 49, + 128, 0,181,225,243,241,245,225,242,101,128, 51,130,227,104, 2, + 134,132,134,142,231,242,229,225,244,229,114,128, 34,107,236,229, + 243,115,128, 34,106,230,243,241,245,225,242,101,128, 51,140,103, + 2,134,165,134,172,242,229,229,107,128, 3,188,243,241,245,225, + 242,101,128, 51,141,232,233,242,225,231,225,238, 97,128, 48,128, + 235,225,244,225,235,225,238, 97,129, 48,224,134,205,232,225,236, + 230,247,233,228,244,104,128,255,145,108, 2,134,223,134,232,243, + 241,245,225,242,101,128, 51,149,244,233,240,236,121,128, 0,215, + 237,243,241,245,225,242,101,128, 51,155,238,225,104, 2,135, 2, + 135, 11,232,229,226,242,229,119,128, 5,163,236,229,230,244,232, + 229,226,242,229,119,128, 5,163,115, 2,135, 30,135, 79,233, 99, + 3,135, 39,135, 56,135, 67,225,236,238,239,244,101,129, 38,106, + 135, 50,228,226,108,128, 38,107,230,236,225,244,243,233,231,110, + 128, 38,109,243,232,225,242,240,243,233,231,110,128, 38,111,243, + 241,245,225,242,101,128, 51,178,246,243,241,245,225,242,101,128, + 51,182,247,243,241,245,225,242,101,128, 51,188,118, 2,135,114, + 135,127,237,229,231,225,243,241,245,225,242,101,128, 51,185,243, + 241,245,225,242,101,128, 51,183,119, 2,135,142,135,155,237,229, + 231,225,243,241,245,225,242,101,128, 51,191,243,241,245,225,242, + 101,128, 51,189,110,150, 0,110,135,212,136, 90,136,114,136,180, + 136,205,137, 7,137, 17,137, 84,137,127,139,161,139,179,139,204, + 139,235,140, 5,140, 70,142, 52,142, 60,142, 85,142, 93,143, 61, + 143, 71,143, 81, 97, 8,135,230,135,250,136, 1,136, 8,136, 33, + 136, 44,136, 69,136, 81, 98, 2,135,236,135,245,229,238,231,225, + 236,105,128, 9,168,236, 97,128, 34, 7,227,245,244,101,128, 1, + 68,228,229,246, 97,128, 9, 40,231,117, 2,136, 15,136, 24,234, + 225,242,225,244,105,128, 10,168,242,237,245,235,232,105,128, 10, + 40,232,233,242,225,231,225,238, 97,128, 48,106,235,225,244,225, + 235,225,238, 97,129, 48,202,136, 57,232,225,236,230,247,233,228, + 244,104,128,255,133,240,239,243,244,242,239,240,232,101,128, 1, + 73,243,241,245,225,242,101,128, 51,129, 98, 2,136, 96,136,106, + 239,240,239,237,239,230,111,128, 49, 11,243,240,225,227,101,128, + 0,160, 99, 4,136,124,136,131,136,140,136,167,225,242,239,110, + 128, 1, 72,229,228,233,236,236, 97,128, 1, 70,233,242, 99, 2, + 136,148,136,153,236,101,128, 36,221,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 75,239,237,237,225,225,227,227,229,238, + 116,128, 1, 70,228,239,116, 2,136,188,136,197,225,227,227,229, + 238,116,128, 30, 69,226,229,236,239,119,128, 30, 71,101, 3,136, + 213,136,224,136,249,232,233,242,225,231,225,238, 97,128, 48,109, + 235,225,244,225,235,225,238, 97,129, 48,205,136,237,232,225,236, + 230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236, + 243,233,231,110,128, 32,170,230,243,241,245,225,242,101,128, 51, + 139,103, 2,137, 23,137, 73, 97, 3,137, 31,137, 41,137, 48,226, + 229,238,231,225,236,105,128, 9,153,228,229,246, 97,128, 9, 25, + 231,117, 2,137, 55,137, 64,234,225,242,225,244,105,128, 10,153, + 242,237,245,235,232,105,128, 10, 25,239,238,231,245,244,232,225, + 105,128, 14, 7,104, 2,137, 90,137,100,233,242,225,231,225,238, + 97,128, 48,147,239,239,107, 2,137,108,137,115,236,229,230,116, + 128, 2,114,242,229,244,242,239,230,236,229,120,128, 2,115,105, + 4,137,137,138, 50,138, 61,138,119,229,245,110, 7,137,155,137, + 190,137,222,137,236,137,245,138, 22,138, 35, 97, 2,137,161,137, + 176,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,111, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 15,227,105, + 2,137,197,137,209,229,245,227,235,239,242,229,225,110,128, 49, + 53,242,227,236,229,235,239,242,229,225,110,128, 50, 97,232,233, + 229,245,232,235,239,242,229,225,110,128, 49, 54,235,239,242,229, + 225,110,128, 49, 52,240, 97, 2,137,252,138, 10,238,243,233,239, + 243,235,239,242,229,225,110,128, 49,104,242,229,238,235,239,242, + 229,225,110,128, 50, 1,243,233,239,243,235,239,242,229,225,110, + 128, 49,103,244,233,235,229,245,244,235,239,242,229,225,110,128, + 49,102,232,233,242,225,231,225,238, 97,128, 48,107,107, 2,138, + 67,138, 91,225,244,225,235,225,238, 97,129, 48,203,138, 79,232, + 225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116, + 2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153, + 244,232,225,105,128, 14, 77,238,101,141, 0, 57,138,150,138,159, + 138,169,138,199,138,206,138,231,139, 2,139, 36,139, 48,139, 59, + 139, 92,139,100,139,111,225,242,225,226,233, 99,128, 6,105,226, + 229,238,231,225,236,105,128, 9,239,227,233,242,227,236,101,129, + 36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243, + 229,242,233,102,128, 39,146,228,229,246, 97,128, 9,111,231,117, + 2,138,213,138,222,234,225,242,225,244,105,128, 10,239,242,237, + 245,235,232,105,128, 10,111,232, 97, 2,138,238,138,249,227,235, + 225,242,225,226,233, 99,128, 6,105,238,231,250,232,239,117,128, + 48, 41,105, 2,139, 8,139, 26,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 40,238,230,229,242,233,239, + 114,128, 32,137,237,239,238,239,243,240,225,227,101,128,255, 25, + 239,236,228,243,244,249,236,101,128,247, 57,112, 2,139, 65,139, + 72,225,242,229,110,128, 36,124,229,114, 2,139, 79,139, 85,233, + 239,100,128, 36,144,243,233,225,110,128, 6,249,242,239,237,225, + 110,128, 33,120,243,245,240,229,242,233,239,114,128, 32,121,116, + 2,139,117,139,155,229,229,110, 2,139,125,139,134,227,233,242, + 227,236,101,128, 36,114,112, 2,139,140,139,147,225,242,229,110, + 128, 36,134,229,242,233,239,100,128, 36,154,232,225,105,128, 14, + 89,106,129, 1,204,139,167,229,227,249,242,233,236,236,233, 99, + 128, 4, 90,235,225,244,225,235,225,238, 97,129, 48,243,139,192, + 232,225,236,230,247,233,228,244,104,128,255,157,108, 2,139,210, + 139,224,229,231,242,233,231,232,244,236,239,238,103,128, 1,158, + 233,238,229,226,229,236,239,119,128, 30, 73,109, 2,139,241,139, + 252,239,238,239,243,240,225,227,101,128,255, 78,243,241,245,225, + 242,101,128, 51,154,110, 2,140, 11,140, 61, 97, 3,140, 19,140, + 29,140, 36,226,229,238,231,225,236,105,128, 9,163,228,229,246, + 97,128, 9, 35,231,117, 2,140, 43,140, 52,234,225,242,225,244, + 105,128, 10,163,242,237,245,235,232,105,128, 10, 35,238,225,228, + 229,246, 97,128, 9, 41,111, 6,140, 84,140, 95,140,120,140,161, + 141,113,142, 40,232,233,242,225,231,225,238, 97,128, 48,110,235, + 225,244,225,235,225,238, 97,129, 48,206,140,108,232,225,236,230, + 247,233,228,244,104,128,255,137,110, 3,140,128,140,144,140,153, + 226,242,229,225,235,233,238,231,243,240,225,227,101,128, 0,160, + 229,238,244,232,225,105,128, 14, 19,245,244,232,225,105,128, 14, + 25,239,110, 7,140,178,140,187,140,201,140,235,140,251,141, 36, + 141, 95,225,242,225,226,233, 99,128, 6, 70,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,230,231,232,245,238,238, 97, 2, + 140,212,140,221,225,242,225,226,233, 99,128, 6,186,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,159,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,231,234,229,229,237,105, + 2,141, 5,141, 20,238,233,244,233,225,236,225,242,225,226,233, + 99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233, + 99,128,252, 75,237,101, 2,141, 43,141, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,232,229,237,105, 2,141, 64,141, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,213,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 78,238, + 239,239,238,230,233,238,225,236,225,242,225,226,233, 99,128,252, + 141,116, 7,141,129,141,140,141,169,141,204,141,216,141,236,142, + 6,227,239,238,244,225,233,238,115,128, 34, 12,101, 2,141,146, + 141,162,236,229,237,229,238,116,129, 34, 9,141,157,239,102,128, + 34, 9,241,245,225,108,128, 34, 96,231,242,229,225,244,229,114, + 129, 34,111,141,181,238,239,114, 2,141,189,141,197,229,241,245, + 225,108,128, 34,113,236,229,243,115,128, 34,121,233,228,229,238, + 244,233,227,225,108,128, 34, 98,236,229,243,115,129, 34,110,141, + 225,238,239,242,229,241,245,225,108,128, 34,112,112, 2,141,242, + 141,252,225,242,225,236,236,229,108,128, 34, 38,242,229,227,229, + 228,229,115,128, 34,128,243,117, 3,142, 15,142, 22,142, 31,226, + 243,229,116,128, 34,132,227,227,229,229,228,115,128, 34,129,240, + 229,242,243,229,116,128, 34,133,247,225,242,237,229,238,233,225, + 110,128, 5,118,240,225,242,229,110,128, 36,169,115, 2,142, 66, + 142, 75,243,241,245,225,242,101,128, 51,177,245,240,229,242,233, + 239,114,128, 32,127,244,233,236,228,101,128, 0,241,117,132, 3, + 189,142,105,142,116,142,197,143, 24,232,233,242,225,231,225,238, + 97,128, 48,108,107, 2,142,122,142,146,225,244,225,235,225,238, + 97,129, 48,204,142,134,232,225,236,230,247,233,228,244,104,128, + 255,135,244, 97, 3,142,155,142,165,142,172,226,229,238,231,225, + 236,105,128, 9,188,228,229,246, 97,128, 9, 60,231,117, 2,142, + 179,142,188,234,225,242,225,244,105,128, 10,188,242,237,245,235, + 232,105,128, 10, 60,109, 2,142,203,142,237,226,229,242,243,233, + 231,110,130, 0, 35,142,217,142,229,237,239,238,239,243,240,225, + 227,101,128,255, 3,243,237,225,236,108,128,254, 95,229,114, 2, + 142,244,143, 20,225,236,243,233,231,110, 2,142,255,143, 7,231, + 242,229,229,107,128, 3,116,236,239,247,229,242,231,242,229,229, + 107,128, 3,117,111,128, 33, 22,110,130, 5,224,143, 32,143, 52, + 228,225,231,229,243,104,129,251, 64,143, 43,232,229,226,242,229, + 119,128,251, 64,232,229,226,242,229,119,128, 5,224,246,243,241, + 245,225,242,101,128, 51,181,247,243,241,245,225,242,101,128, 51, + 187,249, 97, 3,143, 90,143,100,143,107,226,229,238,231,225,236, + 105,128, 9,158,228,229,246, 97,128, 9, 30,231,117, 2,143,114, + 143,123,234,225,242,225,244,105,128, 10,158,242,237,245,235,232, + 105,128, 10, 30,111,147, 0,111,143,174,143,196,144, 18,144,188, + 145, 4,145, 19,145, 59,145,182,145,203,145,241,145,252,146,174, + 148, 8,148, 72,148,105,148,151,149, 24,149, 71,149, 83, 97, 2, + 143,180,143,187,227,245,244,101,128, 0,243,238,231,244,232,225, + 105,128, 14, 45, 98, 4,143,206,143,248,144, 1,144, 11,225,242, + 242,229,100,130, 2,117,143,218,143,229,227,249,242,233,236,236, + 233, 99,128, 4,233,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,235,229,238,231,225,236,105,128, 9, + 147,239,240,239,237,239,230,111,128, 49, 27,242,229,246,101,128, + 1, 79, 99, 3,144, 26,144, 99,144,178, 97, 2,144, 32,144, 93, + 238,228,242, 97, 3,144, 43,144, 50,144, 61,228,229,246, 97,128, + 9, 17,231,245,234,225,242,225,244,105,128, 10,145,246,239,247, + 229,236,243,233,231,110, 2,144, 75,144, 82,228,229,246, 97,128, + 9, 73,231,245,234,225,242,225,244,105,128, 10,201,242,239,110, + 128, 1,210,233,242, 99, 2,144,107,144,112,236,101,128, 36,222, + 245,237,230,236,229,120,133, 0,244,144,131,144,139,144,150,144, + 158,144,170,225,227,245,244,101,128, 30,209,228,239,244,226,229, + 236,239,119,128, 30,217,231,242,225,246,101,128, 30,211,232,239, + 239,235,225,226,239,246,101,128, 30,213,244,233,236,228,101,128, + 30,215,249,242,233,236,236,233, 99,128, 4, 62,100, 4,144,198, + 144,221,144,227,144,250,226,108, 2,144,205,144,213,225,227,245, + 244,101,128, 1, 81,231,242,225,246,101,128, 2, 13,229,246, 97, + 128, 9, 19,233,229,242,229,243,233,115,129, 0,246,144,239,227, + 249,242,233,236,236,233, 99,128, 4,231,239,244,226,229,236,239, + 119,128, 30,205,101,129, 1, 83,145, 10,235,239,242,229,225,110, + 128, 49, 90,103, 3,145, 27,145, 42,145, 49,239,238,229,107,129, + 2,219,145, 36,227,237, 98,128, 3, 40,242,225,246,101,128, 0, + 242,245,234,225,242,225,244,105,128, 10,147,104, 4,145, 69,145, + 80,145, 90,145,168,225,242,237,229,238,233,225,110,128, 5,133, + 233,242,225,231,225,238, 97,128, 48, 74,111, 2,145, 96,145,106, + 239,235,225,226,239,246,101,128, 30,207,242,110,133, 1,161,145, + 121,145,129,145,140,145,148,145,160,225,227,245,244,101,128, 30, + 219,228,239,244,226,229,236,239,119,128, 30,227,231,242,225,246, + 101,128, 30,221,232,239,239,235,225,226,239,246,101,128, 30,223, + 244,233,236,228,101,128, 30,225,245,238,231,225,242,245,237,236, + 225,245,116,128, 1, 81,105,129, 1,163,145,188,238,246,229,242, + 244,229,228,226,242,229,246,101,128, 2, 15,107, 2,145,209,145, + 233,225,244,225,235,225,238, 97,129, 48,170,145,221,232,225,236, + 230,247,233,228,244,104,128,255,117,239,242,229,225,110,128, 49, + 87,236,229,232,229,226,242,229,119,128, 5,171,109, 6,146, 10, + 146, 38,146, 45,146,134,146,145,146,163,225,227,242,239,110,130, + 1, 77,146, 22,146, 30,225,227,245,244,101,128, 30, 83,231,242, + 225,246,101,128, 30, 81,228,229,246, 97,128, 9, 80,229,231, 97, + 133, 3,201,146, 61,146, 65,146, 76,146, 90,146,106, 49,128, 3, + 214,227,249,242,233,236,236,233, 99,128, 4, 97,236,225,244,233, + 238,227,236,239,243,229,100,128, 2,119,242,239,245,238,228,227, + 249,242,233,236,236,233, 99,128, 4,123,116, 2,146,112,146,127, + 233,244,236,239,227,249,242,233,236,236,233, 99,128, 4,125,239, + 238,239,115,128, 3,206,231,245,234,225,242,225,244,105,128, 10, + 208,233,227,242,239,110,129, 3,191,146,155,244,239,238,239,115, + 128, 3,204,239,238,239,243,240,225,227,101,128,255, 79,238,101, + 145, 0, 49,146,213,146,222,146,232,147, 6,147, 31,147, 40,147, + 49,147, 74,147,108,147,142,147,154,147,173,147,184,147,217,147, + 227,147,235,147,246,225,242,225,226,233, 99,128, 6, 97,226,229, + 238,231,225,236,105,128, 9,231,227,233,242,227,236,101,129, 36, + 96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229, + 242,233,102,128, 39,138,100, 2,147, 12,147, 18,229,246, 97,128, + 9,103,239,244,229,238,236,229,225,228,229,114,128, 32, 36,229, + 233,231,232,244,104,128, 33, 91,230,233,244,244,229,100,128,246, + 220,231,117, 2,147, 56,147, 65,234,225,242,225,244,105,128, 10, + 231,242,237,245,235,232,105,128, 10,103,232, 97, 3,147, 83,147, + 94,147, 99,227,235,225,242,225,226,233, 99,128, 6, 97,236,102, + 128, 0,189,238,231,250,232,239,117,128, 48, 33,105, 2,147,114, + 147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 32,238,230,229,242,233,239,114,128, 32,129,237,239, + 238,239,243,240,225,227,101,128,255, 17,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,244,239,236,228, + 243,244,249,236,101,128,247, 49,112, 2,147,190,147,197,225,242, + 229,110,128, 36,116,229,114, 2,147,204,147,210,233,239,100,128, + 36,136,243,233,225,110,128, 6,241,241,245,225,242,244,229,114, + 128, 0,188,242,239,237,225,110,128, 33,112,243,245,240,229,242, + 233,239,114,128, 0,185,244,104, 2,147,253,148, 2,225,105,128, + 14, 81,233,242,100,128, 33, 83,111, 3,148, 16,148, 50,148, 66, + 103, 2,148, 22,148, 40,239,238,229,107,129, 1,235,148, 31,237, + 225,227,242,239,110,128, 1,237,245,242,237,245,235,232,105,128, + 10, 19,237,225,244,242,225,231,245,242,237,245,235,232,105,128, + 10, 75,240,229,110,128, 2, 84,112, 3,148, 80,148, 87,148, 98, + 225,242,229,110,128, 36,170,229,238,226,245,236,236,229,116,128, + 37,230,244,233,239,110,128, 35, 37,114, 2,148,111,148,140,100, + 2,148,117,148,128,230,229,237,233,238,233,238,101,128, 0,170, + 237,225,243,227,245,236,233,238,101,128, 0,186,244,232,239,231, + 239,238,225,108,128, 34, 31,115, 5,148,163,148,195,148,212,149, + 1,149, 14,232,239,242,116, 2,148,172,148,179,228,229,246, 97, + 128, 9, 18,246,239,247,229,236,243,233,231,238,228,229,246, 97, + 128, 9, 74,236,225,243,104,129, 0,248,148,204,225,227,245,244, + 101,128, 1,255,237,225,236,108, 2,148,221,148,232,232,233,242, + 225,231,225,238, 97,128, 48, 73,235,225,244,225,235,225,238, 97, + 129, 48,169,148,245,232,225,236,230,247,233,228,244,104,128,255, + 107,244,242,239,235,229,225,227,245,244,101,128, 1,255,245,240, + 229,242,233,239,114,128,246,240,116, 2,149, 30,149, 41,227,249, + 242,233,236,236,233, 99,128, 4,127,233,236,228,101,130, 0,245, + 149, 52,149, 60,225,227,245,244,101,128, 30, 77,228,233,229,242, + 229,243,233,115,128, 30, 79,245,226,239,240,239,237,239,230,111, + 128, 49, 33,118, 2,149, 89,149,170,229,114, 2,149, 96,149,162, + 236,233,238,101,131, 32, 62,149,109,149,132,149,155, 99, 2,149, + 115,149,127,229,238,244,229,242,236,233,238,101,128,254, 74,237, + 98,128, 3, 5,100, 2,149,138,149,146,225,243,232,229,100,128, + 254, 73,226,236,247,225,246,121,128,254, 76,247,225,246,121,128, + 254, 75,243,227,239,242,101,128, 0,175,239,247,229,236,243,233, + 231,110, 3,149,185,149,195,149,202,226,229,238,231,225,236,105, + 128, 9,203,228,229,246, 97,128, 9, 75,231,245,234,225,242,225, + 244,105,128, 10,203,112,145, 0,112,149,251,152,123,152,134,152, + 143,152,155,154, 80,154, 90,155, 82,156,101,156,191,156,217,157, + 92,157,100,158, 2,158, 60,158, 88,158, 98, 97, 14,150, 25,150, + 57,150, 67,150, 74,150, 81,150,129,150,140,150,154,150,165,150, + 212,150,226,151,238,152, 21,152,111, 97, 2,150, 31,150, 43,237, + 240,243,243,241,245,225,242,101,128, 51,128,243,229,238,244,239, + 243,241,245,225,242,101,128, 51, 43,226,229,238,231,225,236,105, + 128, 9,170,227,245,244,101,128, 30, 85,228,229,246, 97,128, 9, + 42,103, 2,150, 87,150,105,101, 2,150, 93,150,100,228,239,247, + 110,128, 33,223,245,112,128, 33,222,117, 2,150,111,150,120,234, + 225,242,225,244,105,128, 10,170,242,237,245,235,232,105,128, 10, + 42,232,233,242,225,231,225,238, 97,128, 48,113,233,249,225,238, + 238,239,233,244,232,225,105,128, 14, 47,235,225,244,225,235,225, + 238, 97,128, 48,209,108, 2,150,171,150,196,225,244,225,236,233, + 250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,132,239,227,232,235,225,227,249,242,233,236,236,233, + 99,128, 4,192,238,243,233,239,243,235,239,242,229,225,110,128, + 49,127,114, 3,150,234,150,255,151,227, 97, 2,150,240,150,248, + 231,242,225,240,104,128, 0,182,236,236,229,108,128, 34, 37,229, + 110, 2,151, 6,151,116,236,229,230,116,136, 0, 40,151, 29,151, + 44,151, 49,151, 54,151, 65,151, 77,151,100,151,105,225,236,244, + 239,238,229,225,242,225,226,233, 99,128,253, 62,226,116,128,248, + 237,229,120,128,248,236,233,238,230,229,242,233,239,114,128, 32, + 141,237,239,238,239,243,240,225,227,101,128,255, 8,115, 2,151, + 83,151, 90,237,225,236,108,128,254, 89,245,240,229,242,233,239, + 114,128, 32,125,244,112,128,248,235,246,229,242,244,233,227,225, + 108,128,254, 53,242,233,231,232,116,136, 0, 41,151,140,151,155, + 151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239, + 238,229,225,242,225,226,233, 99,128,253, 63,226,116,128,248,248, + 229,120,128,248,247,233,238,230,229,242,233,239,114,128, 32,142, + 237,239,238,239,243,240,225,227,101,128,255, 9,115, 2,151,194, + 151,201,237,225,236,108,128,254, 90,245,240,229,242,233,239,114, + 128, 32,126,244,112,128,248,246,246,229,242,244,233,227,225,108, + 128,254, 54,244,233,225,236,228,233,230,102,128, 34, 2,115, 3, + 151,246,152, 1,152, 13,229,241,232,229,226,242,229,119,128, 5, + 192,232,244,225,232,229,226,242,229,119,128, 5,153,241,245,225, + 242,101,128, 51,169,244,225,104,134, 5,183,152, 39,152, 53,152, + 58,152, 67,152, 82,152, 98, 49, 2,152, 45,152, 49, 49,128, 5, + 183,100,128, 5,183,178, 97,128, 5,183,232,229,226,242,229,119, + 128, 5,183,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,183,247,233,228,229,232,229,226,242,229,119,128, 5,183,250, + 229,242,232,229,226,242,229,119,128, 5,161,226,239,240,239,237, + 239,230,111,128, 49, 6,227,233,242,227,236,101,128, 36,223,228, + 239,244,225,227,227,229,238,116,128, 30, 87,101,137, 5,228,152, + 177,152,188,152,208,152,220,152,240,153, 86,153, 97,153,118,154, + 73,227,249,242,233,236,236,233, 99,128, 4, 63,228,225,231,229, + 243,104,129,251, 68,152,199,232,229,226,242,229,119,128,251, 68, + 229,250,233,243,241,245,225,242,101,128, 51, 59,230,233,238,225, + 236,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 67, + 104, 5,152,252,153, 19,153, 27,153, 41,153, 71,225,114, 2,153, + 3,153, 10,225,226,233, 99,128, 6,126,237,229,238,233,225,110, + 128, 5,122,229,226,242,229,119,128, 5,228,230,233,238,225,236, + 225,242,225,226,233, 99,128,251, 87,105, 2,153, 47,153, 62,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251, 88,242,225, + 231,225,238, 97,128, 48,122,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,251, 89,235,225,244,225,235,225,238, 97,128, 48, + 218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236, + 236,233, 99,128, 4,167,114, 5,153,130,153,142,153,184,154, 49, + 154, 62,225,230,229,232,229,226,242,229,119,128,251, 78,227,229, + 238,116,131, 0, 37,153,155,153,164,153,176,225,242,225,226,233, + 99,128, 6,106,237,239,238,239,243,240,225,227,101,128,255, 5, + 243,237,225,236,108,128,254,106,105, 2,153,190,154, 31,239,100, + 134, 0, 46,153,207,153,218,153,229,153,241,153,252,154, 8,225, + 242,237,229,238,233,225,110,128, 5,137,227,229,238,244,229,242, + 229,100,128, 0,183,232,225,236,230,247,233,228,244,104,128,255, + 97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239, + 243,240,225,227,101,128,255, 14,115, 2,154, 14,154, 21,237,225, + 236,108,128,254, 82,245,240,229,242,233,239,114,128,246,232,243, + 240,239,237,229,238,233,231,242,229,229,235,227,237, 98,128, 3, + 66,240,229,238,228,233,227,245,236,225,114,128, 34,165,244,232, + 239,245,243,225,238,100,128, 32, 48,243,229,244, 97,128, 32,167, + 230,243,241,245,225,242,101,128, 51,138,104, 3,154, 98,154,148, + 155, 29, 97, 3,154,106,154,116,154,123,226,229,238,231,225,236, + 105,128, 9,171,228,229,246, 97,128, 9, 43,231,117, 2,154,130, + 154,139,234,225,242,225,244,105,128, 10,171,242,237,245,235,232, + 105,128, 10, 43,105,133, 3,198,154,162,154,166,154,252,155, 4, + 155, 15, 49,128, 3,213,229,245,240,104, 4,154,179,154,214,154, + 229,154,238, 97, 2,154,185,154,200,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50,122,240,225,242,229,238,235,239,242, + 229,225,110,128, 50, 26,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,108,235,239,242,229,225,110,128, 49, 77,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 12,236,225,244,233, + 110,128, 2,120,238,244,232,245,244,232,225,105,128, 14, 58,243, + 249,237,226,239,236,231,242,229,229,107,128, 3,213,111, 3,155, + 37,155, 42,155, 68,239,107,128, 1,165,240,104, 2,155, 49,155, + 58,225,238,244,232,225,105,128, 14, 30,245,238,231,244,232,225, + 105,128, 14, 28,243,225,237,240,232,225,239,244,232,225,105,128, + 14, 32,105,133, 3,192,155, 96,156, 52,156, 63,156, 74,156, 88, + 229,245,112, 6,155,112,155,147,155,179,155,207,155,221,156, 17, + 97, 2,155,118,155,133,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,115,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 19,227,105, 2,155,154,155,166,229,245,227,235,239,242, + 229,225,110,128, 49,118,242,227,236,229,235,239,242,229,225,110, + 128, 50,101,107, 2,155,185,155,199,233,249,229,239,235,235,239, + 242,229,225,110,128, 49,114,239,242,229,225,110,128, 49, 66,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 5,243,233,239, + 115, 2,155,230,156, 2,107, 2,155,236,155,250,233,249,229,239, + 235,235,239,242,229,225,110,128, 49,116,239,242,229,225,110,128, + 49, 68,244,233,235,229,245,244,235,239,242,229,225,110,128, 49, + 117,116, 2,156, 23,156, 38,232,233,229,245,244,232,235,239,242, + 229,225,110,128, 49,119,233,235,229,245,244,235,239,242,229,225, + 110,128, 49,115,232,233,242,225,231,225,238, 97,128, 48,116,235, + 225,244,225,235,225,238, 97,128, 48,212,243,249,237,226,239,236, + 231,242,229,229,107,128, 3,214,247,242,225,242,237,229,238,233, + 225,110,128, 5,131,236,245,115,132, 0, 43,156,115,156,126,156, + 135,156,168,226,229,236,239,247,227,237, 98,128, 3, 31,227,233, + 242,227,236,101,128, 34,149,109, 2,156,141,156,148,233,238,245, + 115,128, 0,177,111, 2,156,154,156,158,100,128, 2,214,238,239, + 243,240,225,227,101,128,255, 11,115, 2,156,174,156,181,237,225, + 236,108,128,254, 98,245,240,229,242,233,239,114,128, 32,122,109, + 2,156,197,156,208,239,238,239,243,240,225,227,101,128,255, 80, + 243,241,245,225,242,101,128, 51,216,111, 5,156,229,156,240,157, + 51,157, 62,157, 72,232,233,242,225,231,225,238, 97,128, 48,125, + 233,238,244,233,238,231,233,238,228,229,120, 4,157, 4,157, 16, + 157, 28,157, 41,228,239,247,238,247,232,233,244,101,128, 38, 31, + 236,229,230,244,247,232,233,244,101,128, 38, 28,242,233,231,232, + 244,247,232,233,244,101,128, 38, 30,245,240,247,232,233,244,101, + 128, 38, 29,235,225,244,225,235,225,238, 97,128, 48,221,240,236, + 225,244,232,225,105,128, 14, 27,243,244,225,236,237,225,242,107, + 129, 48, 18,157, 85,230,225,227,101,128, 48, 32,240,225,242,229, + 110,128, 36,171,114, 3,157,108,157,134,157,159,101, 2,157,114, + 157,122,227,229,228,229,115,128, 34,122,243,227,242,233,240,244, + 233,239,110,128, 33, 30,233,237,101, 2,157,142,157,148,237,239, + 100,128, 2,185,242,229,246,229,242,243,229,100,128, 32, 53,111, + 4,157,169,157,176,157,186,157,199,228,245,227,116,128, 34, 15, + 234,229,227,244,233,246,101,128, 35, 5,236,239,238,231,229,228, + 235,225,238, 97,128, 48,252,112, 2,157,205,157,242,101, 2,157, + 211,157,218,236,236,239,114,128, 35, 24,242,243,117, 2,157,226, + 157,233,226,243,229,116,128, 34,130,240,229,242,243,229,116,128, + 34,131,239,242,244,233,239,110,129, 34, 55,157,253,225,108,128, + 34, 29,115, 2,158, 8,158, 51,105,130, 3,200,158, 16,158, 27, + 227,249,242,233,236,236,233, 99,128, 4,113,236,233,240,238,229, + 245,237,225,244,225,227,249,242,233,236,236,233,227,227,237, 98, + 128, 4,134,243,241,245,225,242,101,128, 51,176,117, 2,158, 66, + 158, 77,232,233,242,225,231,225,238, 97,128, 48,119,235,225,244, + 225,235,225,238, 97,128, 48,215,246,243,241,245,225,242,101,128, + 51,180,247,243,241,245,225,242,101,128, 51,186,113,136, 0,113, + 158,128,159,177,159,188,159,197,159,204,159,216,159,254,160, 6, + 97, 4,158,138,158,161,158,225,159,160,100, 2,158,144,158,150, + 229,246, 97,128, 9, 88,237,225,232,229,226,242,229,119,128, 5, + 168,102, 4,158,171,158,180,158,194,158,210,225,242,225,226,233, + 99,128, 6, 66,230,233,238,225,236,225,242,225,226,233, 99,128, + 254,214,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,215,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, + 216,237,225,244,115,136, 5,184,158,248,159, 12,159, 26,159, 31, + 159, 36,159, 45,159, 60,159,147, 49, 3,159, 0,159, 4,159, 8, + 48,128, 5,184, 97,128, 5,184, 99,128, 5,184, 50, 2,159, 18, + 159, 22, 55,128, 5,184, 57,128, 5,184,179, 51,128, 5,184,228, + 101,128, 5,184,232,229,226,242,229,119,128, 5,184,238,225,242, + 242,239,247,232,229,226,242,229,119,128, 5,184,113, 2,159, 66, + 159,132,225,244,225,110, 4,159, 79,159, 88,159,103,159,119,232, + 229,226,242,229,119,128, 5,184,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,184,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,184,247,233,228,229,232,229,226,242,229, + 119,128, 5,184,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,184,247,233,228,229,232,229,226,242,229,119,128, 5,184, + 242,238,229,249,240,225,242,225,232,229,226,242,229,119,128, 5, + 159,226,239,240,239,237,239,230,111,128, 49, 17,227,233,242,227, + 236,101,128, 36,224,232,239,239,107,128, 2,160,237,239,238,239, + 243,240,225,227,101,128,255, 81,239,102,130, 5,231,159,225,159, + 245,228,225,231,229,243,104,129,251, 71,159,236,232,229,226,242, + 229,119,128,251, 71,232,229,226,242,229,119,128, 5,231,240,225, + 242,229,110,128, 36,172,117, 4,160, 16,160, 28,160,117,160,204, + 225,242,244,229,242,238,239,244,101,128, 38,105,226,245,244,115, + 135, 5,187,160, 49,160, 54,160, 59,160, 64,160, 73,160, 88,160, + 104,177, 56,128, 5,187,178, 53,128, 5,187,179, 49,128, 5,187, + 232,229,226,242,229,119,128, 5,187,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,187,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,187,247,233,228,229,232,229,226,242, + 229,119,128, 5,187,229,243,244,233,239,110,133, 0, 63,160,136, + 160,159,160,176,160,184,160,196,225,114, 2,160,143,160,150,225, + 226,233, 99,128, 6, 31,237,229,238,233,225,110,128, 5, 94,228, + 239,247,110,129, 0,191,160,168,243,237,225,236,108,128,247,191, + 231,242,229,229,107,128, 3,126,237,239,238,239,243,240,225,227, + 101,128,255, 31,243,237,225,236,108,128,247, 63,239,244,101, 4, + 160,216,161, 31,161, 51,161, 80,228,226,108,133, 0, 34,160,232, + 160,239,160,246,161, 2,161, 23,226,225,243,101,128, 32, 30,236, + 229,230,116,128, 32, 28,237,239,238,239,243,240,225,227,101,128, + 255, 2,240,242,233,237,101,129, 48, 30,161, 12,242,229,246,229, + 242,243,229,100,128, 48, 29,242,233,231,232,116,128, 32, 29,236, + 229,230,116,129, 32, 24,161, 40,242,229,246,229,242,243,229,100, + 128, 32, 27,114, 2,161, 57,161, 67,229,246,229,242,243,229,100, + 128, 32, 27,233,231,232,116,129, 32, 25,161, 76,110,128, 1, 73, + 243,233,238,231,108, 2,161, 90,161, 97,226,225,243,101,128, 32, + 26,101,129, 0, 39,161,103,237,239,238,239,243,240,225,227,101, + 128,255, 7,114,145, 0,114,161,153,162,157,162,168,162,215,163, + 10,164, 27,164, 51,164,146,166,180,166,217,166,229,167, 27,167, + 35,167,197,167,208,167,243,168, 87, 97, 11,161,177,161,188,161, + 198,161,205,162, 14,162, 30,162, 55,162, 66,162, 91,162,114,162, + 151,225,242,237,229,238,233,225,110,128, 5,124,226,229,238,231, + 225,236,105,128, 9,176,227,245,244,101,128, 1, 85,100, 4,161, + 215,161,221,161,235,162, 5,229,246, 97,128, 9, 48,233,227,225, + 108,129, 34, 26,161,230,229,120,128,248,229,239,246,229,242,243, + 243,241,245,225,242,101,129, 51,174,161,251,228,243,241,245,225, + 242,101,128, 51,175,243,241,245,225,242,101,128, 51,173,230,101, + 129, 5,191,162, 21,232,229,226,242,229,119,128, 5,191,231,117, + 2,162, 37,162, 46,234,225,242,225,244,105,128, 10,176,242,237, + 245,235,232,105,128, 10, 48,232,233,242,225,231,225,238, 97,128, + 48,137,235,225,244,225,235,225,238, 97,129, 48,233,162, 79,232, + 225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242, + 228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128, + 9,241,109, 2,162,120,162,143,233,228,228,236,229,228,233,225, + 231,239,238,225,236,226,229,238,231,225,236,105,128, 9,240,243, + 232,239,242,110,128, 2,100,244,233,111,128, 34, 54,226,239,240, + 239,237,239,230,111,128, 49, 22, 99, 4,162,178,162,185,162,194, + 162,202,225,242,239,110,128, 1, 89,229,228,233,236,236, 97,128, + 1, 87,233,242,227,236,101,128, 36,225,239,237,237,225,225,227, + 227,229,238,116,128, 1, 87,100, 2,162,221,162,231,226,236,231, + 242,225,246,101,128, 2, 17,239,116, 2,162,238,162,247,225,227, + 227,229,238,116,128, 30, 89,226,229,236,239,119,129, 30, 91,163, + 1,237,225,227,242,239,110,128, 30, 93,101, 6,163, 24,163, 69, + 163,104,163,159,163,184,163,217,102, 2,163, 30,163, 43,229,242, + 229,238,227,229,237,225,242,107,128, 32, 59,236,229,248,243,117, + 2,163, 53,163, 60,226,243,229,116,128, 34,134,240,229,242,243, + 229,116,128, 34,135,231,233,243,244,229,114, 2,163, 80,163, 85, + 229,100,128, 0,174,115, 2,163, 91,163, 97,225,238,115,128,248, + 232,229,242,233,102,128,246,218,104, 3,163,112,163,135,163,149, + 225,114, 2,163,119,163,126,225,226,233, 99,128, 6, 49,237,229, + 238,233,225,110,128, 5,128,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,174,233,242,225,231,225,238, 97,128, 48,140,235, + 225,244,225,235,225,238, 97,129, 48,236,163,172,232,225,236,230, + 247,233,228,244,104,128,255,154,243,104,130, 5,232,163,193,163, + 208,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 72, + 232,229,226,242,229,119,128, 5,232,118, 3,163,225,163,238,164, + 14,229,242,243,229,228,244,233,236,228,101,128, 34, 61,233, 97, + 2,163,245,163,254,232,229,226,242,229,119,128, 5,151,237,245, + 231,242,225,243,232,232,229,226,242,229,119,128, 5,151,236,239, + 231,233,227,225,236,238,239,116,128, 35, 16,230,233,243,232,232, + 239,239,107,129, 2,126,164, 40,242,229,246,229,242,243,229,100, + 128, 2,127,104, 2,164, 57,164, 80, 97, 2,164, 63,164, 73,226, + 229,238,231,225,236,105,128, 9,221,228,229,246, 97,128, 9, 93, + 111,131, 3,193,164, 90,164,119,164,133,239,107,129, 2,125,164, + 97,244,245,242,238,229,100,129, 2,123,164,108,243,245,240,229, + 242,233,239,114,128, 2,181,243,249,237,226,239,236,231,242,229, + 229,107,128, 3,241,244,233,227,232,239,239,235,237,239,100,128, + 2,222,105, 6,164,160,165,204,165,250,166, 5,166, 30,166,166, + 229,245,108, 9,164,182,164,217,164,232,164,246,165, 36,165, 50, + 165,136,165,149,165,184, 97, 2,164,188,164,203,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,113,240,225,242,229,238, + 235,239,242,229,225,110,128, 50, 17,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50, 99,232,233,229,245,232,235,239,242, + 229,225,110,128, 49, 64,107, 2,164,252,165, 28,233,249,229,239, + 107, 2,165, 6,165, 15,235,239,242,229,225,110,128, 49, 58,243, + 233,239,243,235,239,242,229,225,110,128, 49,105,239,242,229,225, + 110,128, 49, 57,237,233,229,245,237,235,239,242,229,225,110,128, + 49, 59,112, 3,165, 58,165, 90,165,105, 97, 2,165, 64,165, 78, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,108,242,229, + 238,235,239,242,229,225,110,128, 50, 3,232,233,229,245,240,232, + 235,239,242,229,225,110,128, 49, 63,233,229,245,112, 2,165,114, + 165,123,235,239,242,229,225,110,128, 49, 60,243,233,239,243,235, + 239,242,229,225,110,128, 49,107,243,233,239,243,235,239,242,229, + 225,110,128, 49, 61,116, 2,165,155,165,170,232,233,229,245,244, + 232,235,239,242,229,225,110,128, 49, 62,233,235,229,245,244,235, + 239,242,229,225,110,128, 49,106,249,229,239,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,109,231,232,116, 2, + 165,212,165,220,225,238,231,236,101,128, 34, 31,116, 2,165,226, + 165,240,225,227,235,226,229,236,239,247,227,237, 98,128, 3, 25, + 242,233,225,238,231,236,101,128, 34,191,232,233,242,225,231,225, + 238, 97,128, 48,138,235,225,244,225,235,225,238, 97,129, 48,234, + 166, 18,232,225,236,230,247,233,228,244,104,128,255,152,110, 2, + 166, 36,166,152,103,131, 2,218,166, 46,166, 57,166, 63,226,229, + 236,239,247,227,237, 98,128, 3, 37,227,237, 98,128, 3, 10,232, + 225,236,102, 2,166, 72,166,118,236,229,230,116,131, 2,191,166, + 85,166, 96,166,107,225,242,237,229,238,233,225,110,128, 5, 89, + 226,229,236,239,247,227,237, 98,128, 3, 28,227,229,238,244,229, + 242,229,100,128, 2,211,242,233,231,232,116,130, 2,190,166,130, + 166,141,226,229,236,239,247,227,237, 98,128, 3, 57,227,229,238, + 244,229,242,229,100,128, 2,210,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 19,244,244,239,242,245,243,241,245,225,242, + 101,128, 51, 81,108, 2,166,186,166,197,233,238,229,226,229,236, + 239,119,128, 30, 95,239,238,231,236,229,103,129, 2,124,166,208, + 244,245,242,238,229,100,128, 2,122,237,239,238,239,243,240,225, + 227,101,128,255, 82,111, 3,166,237,166,248,167, 17,232,233,242, + 225,231,225,238, 97,128, 48,141,235,225,244,225,235,225,238, 97, + 129, 48,237,167, 5,232,225,236,230,247,233,228,244,104,128,255, + 155,242,245,225,244,232,225,105,128, 14, 35,240,225,242,229,110, + 128, 36,173,114, 3,167, 43,167, 79,167,109, 97, 3,167, 51,167, + 61,167, 68,226,229,238,231,225,236,105,128, 9,220,228,229,246, + 97,128, 9, 49,231,245,242,237,245,235,232,105,128, 10, 92,229, + 104, 2,167, 86,167, 95,225,242,225,226,233, 99,128, 6,145,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,141,246,239,227, + 225,236,233, 99, 4,167,125,167,135,167,142,167,153,226,229,238, + 231,225,236,105,128, 9,224,228,229,246, 97,128, 9, 96,231,245, + 234,225,242,225,244,105,128, 10,224,246,239,247,229,236,243,233, + 231,110, 3,167,169,167,179,167,186,226,229,238,231,225,236,105, + 128, 9,196,228,229,246, 97,128, 9, 68,231,245,234,225,242,225, + 244,105,128, 10,196,243,245,240,229,242,233,239,114,128,246,241, + 116, 2,167,214,167,222,226,236,239,227,107,128, 37,144,245,242, + 238,229,100,129, 2,121,167,232,243,245,240,229,242,233,239,114, + 128, 2,180,117, 4,167,253,168, 8,168, 33,168, 80,232,233,242, + 225,231,225,238, 97,128, 48,139,235,225,244,225,235,225,238, 97, + 129, 48,235,168, 21,232,225,236,230,247,233,228,244,104,128,255, + 153,112, 2,168, 39,168, 74,229,101, 2,168, 46,168, 60,237,225, + 242,235,226,229,238,231,225,236,105,128, 9,242,243,233,231,238, + 226,229,238,231,225,236,105,128, 9,243,233,225,104,128,246,221, + 244,232,225,105,128, 14, 36,246,239,227,225,236,233, 99, 4,168, + 103,168,113,168,120,168,131,226,229,238,231,225,236,105,128, 9, + 139,228,229,246, 97,128, 9, 11,231,245,234,225,242,225,244,105, + 128, 10,139,246,239,247,229,236,243,233,231,110, 3,168,147,168, + 157,168,164,226,229,238,231,225,236,105,128, 9,195,228,229,246, + 97,128, 9, 67,231,245,234,225,242,225,244,105,128, 10,195,115, + 147, 0,115,168,217,170,187,170,198,171, 68,171,107,174, 49,174, + 60,176,203,179, 85,179,131,179,158,180, 93,180,160,181,193,181, + 203,182,133,182,206,183,120,183,130, 97, 9,168,237,168,247,169, + 12,169, 84,169,109,169,120,169,145,169,177,169,217,226,229,238, + 231,225,236,105,128, 9,184,227,245,244,101,129, 1, 91,169, 0, + 228,239,244,225,227,227,229,238,116,128, 30,101,100, 5,169, 24, + 169, 33,169, 39,169, 53,169, 69,225,242,225,226,233, 99,128, 6, + 53,229,246, 97,128, 9, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,186,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,254,187,237,229,228,233,225,236,225,242,225,226,233, + 99,128,254,188,231,117, 2,169, 91,169,100,234,225,242,225,244, + 105,128, 10,184,242,237,245,235,232,105,128, 10, 56,232,233,242, + 225,231,225,238, 97,128, 48, 85,235,225,244,225,235,225,238, 97, + 129, 48,181,169,133,232,225,236,230,247,233,228,244,104,128,255, + 123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229, + 247,225,243,225,236,236,225,237,225,242,225,226,233, 99,128,253, + 250,237,229,235,104,130, 5,225,169,188,169,208,228,225,231,229, + 243,104,129,251, 65,169,199,232,229,226,242,229,119,128,251, 65, + 232,229,226,242,229,119,128, 5,225,242, 97, 5,169,230,170, 48, + 170, 56,170,106,170,114, 97, 5,169,242,169,250,170, 2,170, 33, + 170, 41,225,244,232,225,105,128, 14, 50,229,244,232,225,105,128, + 14, 65,233,237,225,233,109, 2,170, 12,170, 23,225,236,225,233, + 244,232,225,105,128, 14, 68,245,225,238,244,232,225,105,128, 14, + 67,237,244,232,225,105,128, 14, 51,244,232,225,105,128, 14, 48, + 229,244,232,225,105,128, 14, 64,105, 3,170, 64,170, 88,170, 99, + 105, 2,170, 70,170, 81,236,229,230,244,244,232,225,105,128,248, + 134,244,232,225,105,128, 14, 53,236,229,230,244,244,232,225,105, + 128,248,133,244,232,225,105,128, 14, 52,239,244,232,225,105,128, + 14, 66,117, 3,170,122,170,172,170,179,101, 3,170,130,170,154, + 170,165,101, 2,170,136,170,147,236,229,230,244,244,232,225,105, + 128,248,136,244,232,225,105,128, 14, 55,236,229,230,244,244,232, + 225,105,128,248,135,244,232,225,105,128, 14, 54,244,232,225,105, + 128, 14, 56,245,244,232,225,105,128, 14, 57,226,239,240,239,237, + 239,230,111,128, 49, 25, 99, 5,170,210,170,231,170,240,171, 33, + 171, 55,225,242,239,110,129, 1, 97,170,219,228,239,244,225,227, + 227,229,238,116,128, 30,103,229,228,233,236,236, 97,128, 1, 95, + 232,247, 97,131, 2, 89,170,252,171, 7,171, 26,227,249,242,233, + 236,236,233, 99,128, 4,217,228,233,229,242,229,243,233,243,227, + 249,242,233,236,236,233, 99,128, 4,219,232,239,239,107,128, 2, + 90,233,242, 99, 2,171, 41,171, 46,236,101,128, 36,226,245,237, + 230,236,229,120,128, 1, 93,239,237,237,225,225,227,227,229,238, + 116,128, 2, 25,228,239,116, 2,171, 76,171, 85,225,227,227,229, + 238,116,128, 30, 97,226,229,236,239,119,129, 30, 99,171, 95,228, + 239,244,225,227,227,229,238,116,128, 30,105,101, 9,171,127,171, + 143,171,178,171,243,172, 90,172,117,172,142,172,223,172,250,225, + 231,245,236,236,226,229,236,239,247,227,237, 98,128, 3, 60, 99, + 2,171,149,171,171,239,238,100,129, 32, 51,171,157,244,239,238, + 229,227,232,233,238,229,243,101,128, 2,202,244,233,239,110,128, + 0,167,229,110, 4,171,189,171,198,171,212,171,228,225,242,225, + 226,233, 99,128, 6, 51,230,233,238,225,236,225,242,225,226,233, + 99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,179,237,229,228,233,225,236,225,242,225,226,233, 99, + 128,254,180,231,239,108,135, 5,182,172, 7,172, 21,172, 26,172, + 35,172, 50,172, 66,172, 77, 49, 2,172, 13,172, 17, 51,128, 5, + 182,102,128, 5,182,178, 99,128, 5,182,232,229,226,242,229,119, + 128, 5,182,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,182,244,225,232,229,226,242,229,119,128, 5,146,247,233,228, + 229,232,229,226,242,229,119,128, 5,182,104, 2,172, 96,172,107, + 225,242,237,229,238,233,225,110,128, 5,125,233,242,225,231,225, + 238, 97,128, 48, 91,235,225,244,225,235,225,238, 97,129, 48,187, + 172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105, + 2,172,149,172,192,227,239,236,239,110,131, 0, 59,172,163,172, + 172,172,184,225,242,225,226,233, 99,128, 6, 27,237,239,238,239, + 243,240,225,227,101,128,255, 27,243,237,225,236,108,128,254, 84, + 246,239,233,227,229,228,237,225,242,235,235,225,238, 97,129, 48, + 156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238, + 116, 2,172,230,172,240,233,243,241,245,225,242,101,128, 51, 34, + 239,243,241,245,225,242,101,128, 51, 35,246,229,110,142, 0, 55, + 173, 28,173, 37,173, 47,173, 77,173, 84,173, 94,173,119,173,146, + 173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226, + 233, 99,128, 6,103,226,229,238,231,225,236,105,128, 9,237,227, + 233,242,227,236,101,129, 36,102,173, 58,233,238,246,229,242,243, + 229,243,225,238,243,243,229,242,233,102,128, 39,144,228,229,246, + 97,128, 9,109,229,233,231,232,244,232,115,128, 33, 94,231,117, + 2,173,101,173,110,234,225,242,225,244,105,128, 10,237,242,237, + 245,235,232,105,128, 10,109,232, 97, 2,173,126,173,137,227,235, + 225,242,225,226,233, 99,128, 6,103,238,231,250,232,239,117,128, + 48, 39,105, 2,173,152,173,170,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 38,238,230,229,242,233,239, + 114,128, 32,135,237,239,238,239,243,240,225,227,101,128,255, 23, + 239,236,228,243,244,249,236,101,128,247, 55,112, 2,173,209,173, + 216,225,242,229,110,128, 36,122,229,114, 2,173,223,173,229,233, + 239,100,128, 36,142,243,233,225,110,128, 6,247,242,239,237,225, + 110,128, 33,118,243,245,240,229,242,233,239,114,128, 32,119,116, + 2,174, 5,174, 43,229,229,110, 2,174, 13,174, 22,227,233,242, + 227,236,101,128, 36,112,112, 2,174, 28,174, 35,225,242,229,110, + 128, 36,132,229,242,233,239,100,128, 36,152,232,225,105,128, 14, + 87,230,244,232,249,240,232,229,110,128, 0,173,104, 7,174, 76, + 175, 50,175, 61,175, 75,176, 20,176, 33,176,197, 97, 6,174, 90, + 174,101,174,111,174,122,175, 9,175, 34,225,242,237,229,238,233, + 225,110,128, 5,119,226,229,238,231,225,236,105,128, 9,182,227, + 249,242,233,236,236,233, 99,128, 4, 72,100, 2,174,128,174,224, + 228, 97, 4,174,139,174,148,174,179,174,193,225,242,225,226,233, + 99,128, 6, 81,228,225,237,237, 97, 2,174,158,174,167,225,242, + 225,226,233, 99,128,252, 97,244,225,238,225,242,225,226,233, 99, + 128,252, 94,230,225,244,232,225,225,242,225,226,233, 99,128,252, + 96,235,225,243,242, 97, 2,174,203,174,212,225,242,225,226,233, + 99,128,252, 98,244,225,238,225,242,225,226,233, 99,128,252, 95, + 101,132, 37,146,174,236,174,243,174,251,175, 4,228,225,242,107, + 128, 37,147,236,233,231,232,116,128, 37,145,237,229,228,233,245, + 109,128, 37,146,246, 97,128, 9, 54,231,117, 2,175, 16,175, 25, + 234,225,242,225,244,105,128, 10,182,242,237,245,235,232,105,128, + 10, 54,236,243,232,229,236,229,244,232,229,226,242,229,119,128, + 5,147,226,239,240,239,237,239,230,111,128, 49, 21,227,232,225, + 227,249,242,233,236,236,233, 99,128, 4, 73,101, 4,175, 85,175, + 150,175,160,175,177,229,110, 4,175, 96,175,105,175,119,175,135, + 225,242,225,226,233, 99,128, 6, 52,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,182,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,254,183,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,254,184,233,227,239,240,244,233, 99,128, 3,227, + 241,229,108,129, 32,170,175,168,232,229,226,242,229,119,128, 32, + 170,246, 97,134, 5,176,175,194,175,209,175,223,175,232,175,247, + 176, 7, 49, 2,175,200,175,205,177, 53,128, 5,176, 53,128, 5, + 176, 50, 2,175,215,175,219, 50,128, 5,176,101,128, 5,176,232, + 229,226,242,229,119,128, 5,176,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,176,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,176,247,233,228,229,232,229,226,242,229, + 119,128, 5,176,232,225,227,249,242,233,236,236,233, 99,128, 4, + 187,105, 2,176, 39,176, 50,237,225,227,239,240,244,233, 99,128, + 3,237,110,131, 5,233,176, 60,176,143,176,152,100, 2,176, 66, + 176,132,225,231,229,243,104,130,251, 73,176, 78,176, 87,232,229, + 226,242,229,119,128,251, 73,115, 2,176, 93,176,113,232,233,238, + 228,239,116,129,251, 44,176,104,232,229,226,242,229,119,128,251, + 44,233,238,228,239,116,129,251, 45,176,123,232,229,226,242,229, + 119,128,251, 45,239,244,232,229,226,242,229,119,128, 5,193,232, + 229,226,242,229,119,128, 5,233,115, 2,176,158,176,178,232,233, + 238,228,239,116,129,251, 42,176,169,232,229,226,242,229,119,128, + 251, 42,233,238,228,239,116,129,251, 43,176,188,232,229,226,242, + 229,119,128,251, 43,239,239,107,128, 2,130,105, 8,176,221,177, + 9,177, 20,177, 45,177, 75,177, 83,177, 96,178, 11,231,237, 97, + 131, 3,195,176,233,176,237,176,245, 49,128, 3,194,230,233,238, + 225,108,128, 3,194,236,245,238,225,244,229,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,242,232,233,242,225,231,225,238, + 97,128, 48, 87,235,225,244,225,235,225,238, 97,129, 48,183,177, + 33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113, + 2,177, 53,177, 62,232,229,226,242,229,119,128, 5,189,236,229, + 230,244,232,229,226,242,229,119,128, 5,189,237,233,236,225,114, + 128, 34, 60,238,228,239,244,232,229,226,242,229,119,128, 5,194, + 239,115, 6,177,111,177,146,177,178,177,206,177,220,177,252, 97, + 2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,116,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 20,227,105, 2,177,153,177,165,229,245,227,235,239,242,229, + 225,110,128, 49,126,242,227,236,229,235,239,242,229,225,110,128, + 50,102,107, 2,177,184,177,198,233,249,229,239,235,235,239,242, + 229,225,110,128, 49,122,239,242,229,225,110,128, 49, 69,238,233, + 229,245,238,235,239,242,229,225,110,128, 49,123,112, 2,177,226, + 177,239,225,242,229,238,235,239,242,229,225,110,128, 50, 6,233, + 229,245,240,235,239,242,229,225,110,128, 49,125,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49,124,120,141, 0, 54,178, + 41,178, 50,178, 60,178, 90,178, 97,178,122,178,149,178,183,178, + 195,178,206,178,239,178,247,179, 2,225,242,225,226,233, 99,128, + 6,102,226,229,238,231,225,236,105,128, 9,236,227,233,242,227, + 236,101,129, 36,101,178, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,143,228,229,246, 97,128, 9, + 108,231,117, 2,178,104,178,113,234,225,242,225,244,105,128, 10, + 236,242,237,245,235,232,105,128, 10,108,232, 97, 2,178,129,178, + 140,227,235,225,242,225,226,233, 99,128, 6,102,238,231,250,232, + 239,117,128, 48, 38,105, 2,178,155,178,173,228,229,239,231,242, + 225,240,232,233,227,240,225,242,229,110,128, 50, 37,238,230,229, + 242,233,239,114,128, 32,134,237,239,238,239,243,240,225,227,101, + 128,255, 22,239,236,228,243,244,249,236,101,128,247, 54,112, 2, + 178,212,178,219,225,242,229,110,128, 36,121,229,114, 2,178,226, + 178,232,233,239,100,128, 36,141,243,233,225,110,128, 6,246,242, + 239,237,225,110,128, 33,117,243,245,240,229,242,233,239,114,128, + 32,118,116, 2,179, 8,179, 79,229,229,110, 2,179, 16,179, 58, + 99, 2,179, 22,179, 30,233,242,227,236,101,128, 36,111,245,242, + 242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242, + 226,229,238,231,225,236,105,128, 9,249,112, 2,179, 64,179, 71, + 225,242,229,110,128, 36,131,229,242,233,239,100,128, 36,151,232, + 225,105,128, 14, 86,108, 2,179, 91,179,111,225,243,104,129, 0, + 47,179, 99,237,239,238,239,243,240,225,227,101,128,255, 15,239, + 238,103,129, 1,127,179,119,228,239,244,225,227,227,229,238,116, + 128, 30,155,109, 2,179,137,179,147,233,236,229,230,225,227,101, + 128, 38, 58,239,238,239,243,240,225,227,101,128,255, 83,111, 6, + 179,172,179,222,179,233,180, 2,180, 47,180, 58,102, 2,179,178, + 179,192,240,225,243,245,241,232,229,226,242,229,119,128, 5,195, + 116, 2,179,198,179,207,232,249,240,232,229,110,128, 0,173,243, + 233,231,238,227,249,242,233,236,236,233, 99,128, 4, 76,232,233, + 242,225,231,225,238, 97,128, 48, 93,235,225,244,225,235,225,238, + 97,129, 48,189,179,246,232,225,236,230,247,233,228,244,104,128, + 255,127,236,233,228,245,115, 2,180, 12,180, 29,236,239,238,231, + 239,246,229,242,236,225,249,227,237, 98,128, 3, 56,243,232,239, + 242,244,239,246,229,242,236,225,249,227,237, 98,128, 3, 55,242, + 245,243,233,244,232,225,105,128, 14, 41,115, 3,180, 66,180, 76, + 180, 84,225,236,225,244,232,225,105,128, 14, 40,239,244,232,225, + 105,128, 14, 11,245,225,244,232,225,105,128, 14, 42,240, 97, 3, + 180,102,180,122,180,154,227,101,129, 0, 32,180,109,232,225,227, + 235,225,242,225,226,233, 99,128, 0, 32,228,101,129, 38, 96,180, + 129,243,245,233,116, 2,180,138,180,146,226,236,225,227,107,128, + 38, 96,247,232,233,244,101,128, 38,100,242,229,110,128, 36,174, + 241,245,225,242,101, 11,180,188,180,199,180,213,180,238,180,255, + 181, 25,181, 40,181, 73,181,100,181,156,181,171,226,229,236,239, + 247,227,237, 98,128, 3, 59, 99, 2,180,205,180,209, 99,128, 51, + 196,109,128, 51,157,228,233,225,231,239,238,225,236,227,242,239, + 243,243,232,225,244,227,232,230,233,236,108,128, 37,169,232,239, + 242,233,250,239,238,244,225,236,230,233,236,108,128, 37,164,107, + 2,181, 5,181, 9,103,128, 51,143,109,129, 51,158,181, 15,227, + 225,240,233,244,225,108,128, 51,206,108, 2,181, 31,181, 35,110, + 128, 51,209,239,103,128, 51,210,109, 4,181, 50,181, 54,181, 59, + 181, 63,103,128, 51,142,233,108,128, 51,213,109,128, 51,156,243, + 241,245,225,242,229,100,128, 51,161,239,242,244,232,239,231,239, + 238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236, + 108,128, 37,166,245,240,240,229,114, 2,181,110,181,133,236,229, + 230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233, + 236,108,128, 37,167,242,233,231,232,244,244,239,236,239,247,229, + 242,236,229,230,244,230,233,236,108,128, 37,168,246,229,242,244, + 233,227,225,236,230,233,236,108,128, 37,165,247,232,233,244,229, + 247,233,244,232,243,237,225,236,236,226,236,225,227,107,128, 37, + 163,242,243,241,245,225,242,101,128, 51,219,115, 2,181,209,182, + 123, 97, 4,181,219,181,229,181,236,181,247,226,229,238,231,225, + 236,105,128, 9,183,228,229,246, 97,128, 9, 55,231,245,234,225, + 242,225,244,105,128, 10,183,238,103, 8,182, 10,182, 24,182, 38, + 182, 52,182, 67,182, 81,182, 95,182,108,227,233,229,245,227,235, + 239,242,229,225,110,128, 49, 73,232,233,229,245,232,235,239,242, + 229,225,110,128, 49,133,233,229,245,238,231,235,239,242,229,225, + 110,128, 49,128,235,233,249,229,239,235,235,239,242,229,225,110, + 128, 49, 50,238,233,229,245,238,235,239,242,229,225,110,128, 49, + 101,240,233,229,245,240,235,239,242,229,225,110,128, 49, 67,243, + 233,239,243,235,239,242,229,225,110,128, 49, 70,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49, 56,245,240,229,242,233, + 239,114,128,246,242,116, 2,182,139,182,162,229,242,236,233,238, + 103,129, 0,163,182,150,237,239,238,239,243,240,225,227,101,128, + 255,225,242,239,235,101, 2,182,171,182,188,236,239,238,231,239, + 246,229,242,236,225,249,227,237, 98,128, 3, 54,243,232,239,242, + 244,239,246,229,242,236,225,249,227,237, 98,128, 3, 53,117, 7, + 182,222,182,254,183, 20,183, 31,183, 72,183, 82,183, 86,226,243, + 229,116,130, 34,130,182,233,182,244,238,239,244,229,241,245,225, + 108,128, 34,138,239,242,229,241,245,225,108,128, 34,134, 99, 2, + 183, 4,183, 12,227,229,229,228,115,128, 34,123,232,244,232,225, + 116,128, 34, 11,232,233,242,225,231,225,238, 97,128, 48, 89,107, + 2,183, 37,183, 61,225,244,225,235,225,238, 97,129, 48,185,183, + 49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225, + 242,225,226,233, 99,128, 6, 82,237,237,225,244,233,239,110,128, + 34, 17,110,128, 38, 60,240,229,242,243,229,116,130, 34,131,183, + 99,183,110,238,239,244,229,241,245,225,108,128, 34,139,239,242, + 229,241,245,225,108,128, 34,135,246,243,241,245,225,242,101,128, + 51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101, + 128, 51,124,116,144, 0,116,183,183,184,192,184,213,185,100,185, + 140,187,188,191, 70,192,145,192,157,192,169,193,202,193,227,194, + 57,194,237,195,165,195,255, 97, 10,183,205,183,215,183,236,183, + 243,184, 12,184, 90,184,107,184,132,184,146,184,150,226,229,238, + 231,225,236,105,128, 9,164,227,107, 2,183,222,183,229,228,239, + 247,110,128, 34,164,236,229,230,116,128, 34,163,228,229,246, 97, + 128, 9, 36,231,117, 2,183,250,184, 3,234,225,242,225,244,105, + 128, 10,164,242,237,245,235,232,105,128, 10, 36,104, 4,184, 22, + 184, 31,184, 45,184, 75,225,242,225,226,233, 99,128, 6, 55,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,194,105, 2,184, + 51,184, 66,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,195,242,225,231,225,238, 97,128, 48, 95,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,196,233,243,249,239,245,229, + 242,225,243,241,245,225,242,101,128, 51,125,235,225,244,225,235, + 225,238, 97,129, 48,191,184,120,232,225,236,230,247,233,228,244, + 104,128,255,128,244,247,229,229,236,225,242,225,226,233, 99,128, + 6, 64,117,128, 3,196,118,130, 5,234,184,158,184,183,228,225, + 231,229,115,129,251, 74,184,168,104,129,251, 74,184,174,232,229, + 226,242,229,119,128,251, 74,232,229,226,242,229,119,128, 5,234, + 98, 2,184,198,184,203,225,114,128, 1,103,239,240,239,237,239, + 230,111,128, 49, 10, 99, 6,184,227,184,234,184,241,184,250,185, + 60,185, 87,225,242,239,110,128, 1,101,227,245,242,108,128, 2, + 168,229,228,233,236,236, 97,128, 1, 99,232,229,104, 4,185, 6, + 185, 15,185, 29,185, 45,225,242,225,226,233, 99,128, 6,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,123,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,251,124,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,251,125,233,242, 99, 2, + 185, 68,185, 73,236,101,128, 36,227,245,237,230,236,229,248,226, + 229,236,239,119,128, 30,113,239,237,237,225,225,227,227,229,238, + 116,128, 1, 99,100, 2,185,106,185,116,233,229,242,229,243,233, + 115,128, 30,151,239,116, 2,185,123,185,132,225,227,227,229,238, + 116,128, 30,107,226,229,236,239,119,128, 30,109,101, 9,185,160, + 185,171,185,191,186,201,186,226,187, 34,187,101,187,106,187,158, + 227,249,242,233,236,236,233, 99,128, 4, 66,228,229,243,227,229, + 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,173,104, + 7,185,207,185,216,185,230,186, 14,186, 44,186, 85,186,183,225, + 242,225,226,233, 99,128, 6, 42,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,150,232,225,232,105, 2,185,239,185,254,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,162,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,252, 12,105, 2, + 186, 20,186, 35,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,151,242,225,231,225,238, 97,128, 48,102,234,229,229,237, + 105, 2,186, 54,186, 69,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,252,161,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,252, 11,109, 2,186, 91,186,125,225,242,226,245,244, + 97, 2,186,102,186,111,225,242,225,226,233, 99,128, 6, 41,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,148,101, 2,186, + 131,186,144,228,233,225,236,225,242,225,226,233, 99,128,254,152, + 229,237,105, 2,186,152,186,167,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,252,164,243,239,236,225,244,229,228,225,242, + 225,226,233, 99,128,252, 14,238,239,239,238,230,233,238,225,236, + 225,242,225,226,233, 99,128,252,115,235,225,244,225,235,225,238, + 97,129, 48,198,186,214,232,225,236,230,247,233,228,244,104,128, + 255,131,108, 2,186,232,186,251,229,240,232,239,238,101,129, 33, + 33,186,243,226,236,225,227,107,128, 38, 14,233,243,232, 97, 2, + 187, 4,187, 19,231,229,228,239,236,225,232,229,226,242,229,119, + 128, 5,160,241,229,244,225,238,225,232,229,226,242,229,119,128, + 5,169,110, 4,187, 44,187, 53,187, 72,187, 93,227,233,242,227, + 236,101,128, 36,105,233,228,229,239,231,242,225,240,232,233,227, + 240,225,242,229,110,128, 50, 41,112, 2,187, 78,187, 85,225,242, + 229,110,128, 36,125,229,242,233,239,100,128, 36,145,242,239,237, + 225,110,128, 33,121,243,104,128, 2,167,116,131, 5,216,187,116, + 187,136,187,145,228,225,231,229,243,104,129,251, 56,187,127,232, + 229,226,242,229,119,128,251, 56,232,229,226,242,229,119,128, 5, + 216,243,229,227,249,242,233,236,236,233, 99,128, 4,181,246,233, + 114, 2,187,166,187,175,232,229,226,242,229,119,128, 5,155,236, + 229,230,244,232,229,226,242,229,119,128, 5,155,104, 6,187,202, + 188, 98,188,220,189, 96,190, 3,191, 60, 97, 5,187,214,187,224, + 187,231,188, 0,188, 29,226,229,238,231,225,236,105,128, 9,165, + 228,229,246, 97,128, 9, 37,231,117, 2,187,238,187,247,234,225, + 242,225,244,105,128, 10,165,242,237,245,235,232,105,128, 10, 37, + 108, 2,188, 6,188, 15,225,242,225,226,233, 99,128, 6, 48,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,172,238,244,232, + 225,235,232,225,116, 3,188, 44,188, 75,188, 82,236,239,119, 2, + 188, 52,188, 63,236,229,230,244,244,232,225,105,128,248,152,242, + 233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128, + 14, 76,245,240,240,229,242,236,229,230,244,244,232,225,105,128, + 248,150,101, 3,188,106,188,170,188,193,104, 4,188,116,188,125, + 188,139,188,155,225,242,225,226,233, 99,128, 6, 43,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,154,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,155,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,156,242,101, 2,188,177,188, + 186,229,248,233,243,244,115,128, 34, 3,230,239,242,101,128, 34, + 52,244, 97,130, 3,184,188,202,188,206, 49,128, 3,209,243,249, + 237,226,239,236,231,242,229,229,107,128, 3,209,105, 2,188,226, + 189, 56,229,245,244,104, 4,188,239,189, 18,189, 33,189, 42, 97, + 2,188,245,189, 4,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,121,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 25,227,233,242,227,236,229,235,239,242,229,225,110,128, 50, + 107,235,239,242,229,225,110,128, 49, 76,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 11,242,244,229,229,110, 2,189, 66, + 189, 75,227,233,242,227,236,101,128, 36,108,112, 2,189, 81,189, + 88,225,242,229,110,128, 36,128,229,242,233,239,100,128, 36,148, + 111, 6,189,110,189,127,189,132,189,146,189,151,189,204,238,225, + 238,231,237,239,238,244,232,239,244,232,225,105,128, 14, 17,239, + 107,128, 1,173,240,232,245,244,232,225,239,244,232,225,105,128, + 14, 18,242,110,128, 0,254,244,104, 3,189,160,189,184,189,194, + 97, 2,189,166,189,176,232,225,238,244,232,225,105,128, 14, 23, + 238,244,232,225,105,128, 14, 16,239,238,231,244,232,225,105,128, + 14, 24,245,238,231,244,232,225,105,128, 14, 22,245,243,225,238, + 100, 2,189,214,189,225,227,249,242,233,236,236,233, 99,128, 4, + 130,243,243,229,240,225,242,225,244,239,114, 2,189,240,189,249, + 225,242,225,226,233, 99,128, 6,108,240,229,242,243,233,225,110, + 128, 6,108,242,229,101,144, 0, 51,190, 41,190, 50,190, 60,190, + 90,190, 97,190,107,190,132,190,159,190,193,190,205,190,224,190, + 235,191, 12,191, 34,191, 42,191, 53,225,242,225,226,233, 99,128, + 6, 99,226,229,238,231,225,236,105,128, 9,233,227,233,242,227, + 236,101,129, 36, 98,190, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,140,228,229,246, 97,128, 9, + 105,229,233,231,232,244,232,115,128, 33, 92,231,117, 2,190,114, + 190,123,234,225,242,225,244,105,128, 10,233,242,237,245,235,232, + 105,128, 10,105,232, 97, 2,190,139,190,150,227,235,225,242,225, + 226,233, 99,128, 6, 99,238,231,250,232,239,117,128, 48, 35,105, + 2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240, + 225,242,229,110,128, 50, 34,238,230,229,242,233,239,114,128, 32, + 131,237,239,238,239,243,240,225,227,101,128,255, 19,238,245,237, + 229,242,225,244,239,242,226,229,238,231,225,236,105,128, 9,246, + 239,236,228,243,244,249,236,101,128,247, 51,112, 2,190,241,190, + 248,225,242,229,110,128, 36,118,229,114, 2,190,255,191, 5,233, + 239,100,128, 36,138,243,233,225,110,128, 6,243,241,245,225,242, + 244,229,242,115,129, 0,190,191, 25,229,237,228,225,243,104,128, + 246,222,242,239,237,225,110,128, 33,114,243,245,240,229,242,233, + 239,114,128, 0,179,244,232,225,105,128, 14, 83,250,243,241,245, + 225,242,101,128, 51,148,105, 7,191, 86,191, 97,191,212,192, 54, + 192, 66,192,115,192,132,232,233,242,225,231,225,238, 97,128, 48, + 97,107, 2,191,103,191,127,225,244,225,235,225,238, 97,129, 48, + 193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229, + 245,116, 4,191,139,191,174,191,189,191,198, 97, 2,191,145,191, + 160,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,112, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 16,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50, 98,235,239,242, + 229,225,110,128, 49, 55,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 2,236,228,101,133, 2,220,191,228,191,239,192, 0, + 192, 12,192, 40,226,229,236,239,247,227,237, 98,128, 3, 48, 99, + 2,191,245,191,250,237, 98,128, 3, 3,239,237, 98,128, 3, 3, + 228,239,245,226,236,229,227,237, 98,128, 3, 96,111, 2,192, 18, + 192, 28,240,229,242,225,244,239,114,128, 34, 60,246,229,242,236, + 225,249,227,237, 98,128, 3, 52,246,229,242,244,233,227,225,236, + 227,237, 98,128, 3, 62,237,229,243,227,233,242,227,236,101,128, + 34,151,112, 2,192, 72,192,102,229,232, 97, 2,192, 80,192, 89, + 232,229,226,242,229,119,128, 5,150,236,229,230,244,232,229,226, + 242,229,119,128, 5,150,240,233,231,245,242,237,245,235,232,105, + 128, 10,112,244,236,239,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,131,247,238,225,242,237,229,238,233,225,110,128, 5, + 127,236,233,238,229,226,229,236,239,119,128, 30,111,237,239,238, + 239,243,240,225,227,101,128,255, 84,111, 7,192,185,192,196,192, + 207,192,232,193, 96,193,108,193,192,225,242,237,229,238,233,225, + 110,128, 5,105,232,233,242,225,231,225,238, 97,128, 48,104,235, + 225,244,225,235,225,238, 97,129, 48,200,192,220,232,225,236,230, + 247,233,228,244,104,128,255,132,110, 3,192,240,193, 82,193, 87, + 101, 4,192,250,193, 63,193, 70,193, 76,226,225,114, 4,193, 6, + 193, 35,193, 45,193, 54,229,248,244,242, 97, 2,193, 16,193, 26, + 232,233,231,232,237,239,100,128, 2,229,236,239,247,237,239,100, + 128, 2,233,232,233,231,232,237,239,100,128, 2,230,236,239,247, + 237,239,100,128, 2,232,237,233,228,237,239,100,128, 2,231,230, + 233,246,101,128, 1,189,243,233,120,128, 1,133,244,247,111,128, + 1,168,239,115,128, 3,132,243,241,245,225,242,101,128, 51, 39, + 240,225,244,225,235,244,232,225,105,128, 14, 15,242,244,239,233, + 243,229,243,232,229,236,236,226,242,225,227,235,229,116, 2,193, + 131,193,161,236,229,230,116,130, 48, 20,193,142,193,150,243,237, + 225,236,108,128,254, 93,246,229,242,244,233,227,225,108,128,254, + 57,242,233,231,232,116,130, 48, 21,193,173,193,181,243,237,225, + 236,108,128,254, 94,246,229,242,244,233,227,225,108,128,254, 58, + 244,225,239,244,232,225,105,128, 14, 21,240, 97, 2,193,209,193, + 221,236,225,244,225,236,232,239,239,107,128, 1,171,242,229,110, + 128, 36,175,114, 3,193,235,194, 10,194, 25,225,228,229,237,225, + 242,107,129, 33, 34,193,247,115, 2,193,253,194, 3,225,238,115, + 128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236, + 229,248,232,239,239,107,128, 2,136,233,225,103, 4,194, 37,194, + 42,194, 47,194, 52,228,110,128, 37,188,236,102,128, 37,196,242, + 116,128, 37,186,245,112,128, 37,178,115,132, 2,166,194, 69,194, + 108,194,214,194,227,225,228,105,130, 5,230,194, 79,194, 99,228, + 225,231,229,243,104,129,251, 70,194, 90,232,229,226,242,229,119, + 128,251, 70,232,229,226,242,229,119,128, 5,230,101, 2,194,114, + 194,125,227,249,242,233,236,236,233, 99,128, 4, 70,242,101,134, + 5,181,194,142,194,156,194,161,194,170,194,185,194,201, 49, 2, + 194,148,194,152, 50,128, 5,181,101,128, 5,181,178, 98,128, 5, + 181,232,229,226,242,229,119,128, 5,181,238,225,242,242,239,247, + 232,229,226,242,229,119,128, 5,181,241,245,225,242,244,229,242, + 232,229,226,242,229,119,128, 5,181,247,233,228,229,232,229,226, + 242,229,119,128, 5,181,232,229,227,249,242,233,236,236,233, 99, + 128, 4, 91,245,240,229,242,233,239,114,128,246,243,116, 4,194, + 247,195, 41,195,106,195,157, 97, 3,194,255,195, 9,195, 16,226, + 229,238,231,225,236,105,128, 9,159,228,229,246, 97,128, 9, 31, + 231,117, 2,195, 23,195, 32,234,225,242,225,244,105,128, 10,159, + 242,237,245,235,232,105,128, 10, 31,229,104, 4,195, 52,195, 61, + 195, 75,195, 91,225,242,225,226,233, 99,128, 6,121,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,103,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,251,104,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,251,105,232, 97, 3,195,115,195, + 125,195,132,226,229,238,231,225,236,105,128, 9,160,228,229,246, + 97,128, 9, 32,231,117, 2,195,139,195,148,234,225,242,225,244, + 105,128, 10,160,242,237,245,235,232,105,128, 10, 32,245,242,238, + 229,100,128, 2,135,117, 3,195,173,195,184,195,209,232,233,242, + 225,231,225,238, 97,128, 48,100,235,225,244,225,235,225,238, 97, + 129, 48,196,195,197,232,225,236,230,247,233,228,244,104,128,255, + 130,243,237,225,236,108, 2,195,219,195,230,232,233,242,225,231, + 225,238, 97,128, 48, 99,235,225,244,225,235,225,238, 97,129, 48, + 195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119, + 2,196, 5,196,110,101, 2,196, 11,196, 59,236,246,101, 3,196, + 21,196, 30,196, 51,227,233,242,227,236,101,128, 36,107,112, 2, + 196, 36,196, 43,225,242,229,110,128, 36,127,229,242,233,239,100, + 128, 36,147,242,239,237,225,110,128, 33,123,238,244,121, 3,196, + 69,196, 78,196, 89,227,233,242,227,236,101,128, 36,115,232,225, + 238,231,250,232,239,117,128, 83, 68,112, 2,196, 95,196,102,225, + 242,229,110,128, 36,135,229,242,233,239,100,128, 36,155,111,142, + 0, 50,196,142,196,151,196,161,196,191,196,243,197, 12,197, 39, + 197, 73,197, 85,197,104,197,115,197,148,197,156,197,180,225,242, + 225,226,233, 99,128, 6, 98,226,229,238,231,225,236,105,128, 9, + 232,227,233,242,227,236,101,129, 36, 97,196,172,233,238,246,229, + 242,243,229,243,225,238,243,243,229,242,233,102,128, 39,139,100, + 2,196,197,196,203,229,246, 97,128, 9,104,239,116, 2,196,210, + 196,221,229,238,236,229,225,228,229,114,128, 32, 37,236,229,225, + 228,229,114,129, 32, 37,196,232,246,229,242,244,233,227,225,108, + 128,254, 48,231,117, 2,196,250,197, 3,234,225,242,225,244,105, + 128, 10,232,242,237,245,235,232,105,128, 10,104,232, 97, 2,197, + 19,197, 30,227,235,225,242,225,226,233, 99,128, 6, 98,238,231, + 250,232,239,117,128, 48, 34,105, 2,197, 45,197, 63,228,229,239, + 231,242,225,240,232,233,227,240,225,242,229,110,128, 50, 33,238, + 230,229,242,233,239,114,128, 32,130,237,239,238,239,243,240,225, + 227,101,128,255, 18,238,245,237,229,242,225,244,239,242,226,229, + 238,231,225,236,105,128, 9,245,239,236,228,243,244,249,236,101, + 128,247, 50,112, 2,197,121,197,128,225,242,229,110,128, 36,117, + 229,114, 2,197,135,197,141,233,239,100,128, 36,137,243,233,225, + 110,128, 6,242,242,239,237,225,110,128, 33,113,115, 2,197,162, + 197,170,244,242,239,235,101,128, 1,187,245,240,229,242,233,239, + 114,128, 0,178,244,104, 2,197,187,197,192,225,105,128, 14, 82, + 233,242,228,115,128, 33, 84,117,145, 0,117,197,237,197,245,198, + 30,198, 87,198,225,199, 6,199,129,199,145,199,196,200, 10,200, + 91,200,100,200,219,200,243,201, 95,201,123,201,237,225,227,245, + 244,101,128, 0,250, 98, 4,197,255,198, 4,198, 13,198, 23,225, + 114,128, 2,137,229,238,231,225,236,105,128, 9,137,239,240,239, + 237,239,230,111,128, 49, 40,242,229,246,101,128, 1,109, 99, 3, + 198, 38,198, 45,198, 77,225,242,239,110,128, 1,212,233,242, 99, + 2,198, 53,198, 58,236,101,128, 36,228,245,237,230,236,229,120, + 129, 0,251,198, 69,226,229,236,239,119,128, 30,119,249,242,233, + 236,236,233, 99,128, 4, 67,100, 5,198, 99,198,110,198,133,198, + 139,198,215,225,244,244,225,228,229,246, 97,128, 9, 81,226,108, + 2,198,117,198,125,225,227,245,244,101,128, 1,113,231,242,225, + 246,101,128, 2, 21,229,246, 97,128, 9, 9,233,229,242,229,243, + 233,115,133, 0,252,198,159,198,167,198,175,198,198,198,206,225, + 227,245,244,101,128, 1,216,226,229,236,239,119,128, 30,115, 99, + 2,198,181,198,188,225,242,239,110,128, 1,218,249,242,233,236, + 236,233, 99,128, 4,241,231,242,225,246,101,128, 1,220,237,225, + 227,242,239,110,128, 1,214,239,244,226,229,236,239,119,128, 30, + 229,103, 2,198,231,198,238,242,225,246,101,128, 0,249,117, 2, + 198,244,198,253,234,225,242,225,244,105,128, 10,137,242,237,245, + 235,232,105,128, 10, 9,104, 3,199, 14,199, 24,199,102,233,242, + 225,231,225,238, 97,128, 48, 70,111, 2,199, 30,199, 40,239,235, + 225,226,239,246,101,128, 30,231,242,110,133, 1,176,199, 55,199, + 63,199, 74,199, 82,199, 94,225,227,245,244,101,128, 30,233,228, + 239,244,226,229,236,239,119,128, 30,241,231,242,225,246,101,128, + 30,235,232,239,239,235,225,226,239,246,101,128, 30,237,244,233, + 236,228,101,128, 30,239,245,238,231,225,242,245,237,236,225,245, + 116,129, 1,113,199,118,227,249,242,233,236,236,233, 99,128, 4, + 243,233,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, + 23,107, 3,199,153,199,177,199,188,225,244,225,235,225,238, 97, + 129, 48,166,199,165,232,225,236,230,247,233,228,244,104,128,255, + 115,227,249,242,233,236,236,233, 99,128, 4,121,239,242,229,225, + 110,128, 49, 92,109, 2,199,202,199,255, 97, 2,199,208,199,241, + 227,242,239,110,130, 1,107,199,219,199,230,227,249,242,233,236, + 236,233, 99,128, 4,239,228,233,229,242,229,243,233,115,128, 30, + 123,244,242,225,231,245,242,237,245,235,232,105,128, 10, 65,239, + 238,239,243,240,225,227,101,128,255, 85,110, 2,200, 16,200, 71, + 228,229,242,243,227,239,242,101,132, 0, 95,200, 35,200, 41,200, + 53,200, 64,228,226,108,128, 32, 23,237,239,238,239,243,240,225, + 227,101,128,255, 63,246,229,242,244,233,227,225,108,128,254, 51, + 247,225,246,121,128,254, 79,105, 2,200, 77,200, 82,239,110,128, + 34, 42,246,229,242,243,225,108,128, 34, 0,239,231,239,238,229, + 107,128, 1,115,112, 5,200,112,200,119,200,127,200,142,200,193, + 225,242,229,110,128, 36,176,226,236,239,227,107,128, 37,128,240, + 229,242,228,239,244,232,229,226,242,229,119,128, 5,196,243,233, + 236,239,110,131, 3,197,200,156,200,177,200,185,228,233,229,242, + 229,243,233,115,129, 3,203,200,169,244,239,238,239,115,128, 3, + 176,236,225,244,233,110,128, 2,138,244,239,238,239,115,128, 3, + 205,244,225,227,107, 2,200,202,200,213,226,229,236,239,247,227, + 237, 98,128, 3, 29,237,239,100,128, 2,212,114, 2,200,225,200, + 237,225,231,245,242,237,245,235,232,105,128, 10,115,233,238,103, + 128, 1,111,115, 3,200,251,201, 10,201, 55,232,239,242,244,227, + 249,242,233,236,236,233, 99,128, 4, 94,237,225,236,108, 2,201, + 19,201, 30,232,233,242,225,231,225,238, 97,128, 48, 69,235,225, + 244,225,235,225,238, 97,129, 48,165,201, 43,232,225,236,230,247, + 233,228,244,104,128,255,105,244,242,225,233,231,232,116, 2,201, + 67,201, 78,227,249,242,233,236,236,233, 99,128, 4,175,243,244, + 242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,177,244, + 233,236,228,101,130, 1,105,201,107,201,115,225,227,245,244,101, + 128, 30,121,226,229,236,239,119,128, 30,117,117, 5,201,135,201, + 145,201,152,201,177,201,193,226,229,238,231,225,236,105,128, 9, + 138,228,229,246, 97,128, 9, 10,231,117, 2,201,159,201,168,234, + 225,242,225,244,105,128, 10,138,242,237,245,235,232,105,128, 10, + 10,237,225,244,242,225,231,245,242,237,245,235,232,105,128, 10, + 66,246,239,247,229,236,243,233,231,110, 3,201,209,201,219,201, + 226,226,229,238,231,225,236,105,128, 9,194,228,229,246, 97,128, + 9, 66,231,245,234,225,242,225,244,105,128, 10,194,246,239,247, + 229,236,243,233,231,110, 3,201,253,202, 7,202, 14,226,229,238, + 231,225,236,105,128, 9,193,228,229,246, 97,128, 9, 65,231,245, + 234,225,242,225,244,105,128, 10,193,118,139, 0,118,202, 51,202, + 199,202,208,202,219,203,148,203,155,203,253,204, 9,204,109,204, + 117,204,138, 97, 4,202, 61,202, 68,202, 93,202,104,228,229,246, + 97,128, 9, 53,231,117, 2,202, 75,202, 84,234,225,242,225,244, + 105,128, 10,181,242,237,245,235,232,105,128, 10, 53,235,225,244, + 225,235,225,238, 97,128, 48,247,118,132, 5,213,202,116,202,143, + 202,175,202,187,228,225,231,229,243,104,130,251, 53,202,129,202, + 134,182, 53,128,251, 53,232,229,226,242,229,119,128,251, 53,104, + 2,202,149,202,157,229,226,242,229,119,128, 5,213,239,236,225, + 109,129,251, 75,202,166,232,229,226,242,229,119,128,251, 75,246, + 225,246,232,229,226,242,229,119,128, 5,240,249,239,228,232,229, + 226,242,229,119,128, 5,241,227,233,242,227,236,101,128, 36,229, + 228,239,244,226,229,236,239,119,128, 30,127,101, 6,202,233,202, + 244,203, 52,203, 63,203, 69,203,136,227,249,242,233,236,236,233, + 99,128, 4, 50,104, 4,202,254,203, 7,203, 21,203, 37,225,242, + 225,226,233, 99,128, 6,164,230,233,238,225,236,225,242,225,226, + 233, 99,128,251,107,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,251,108,237,229,228,233,225,236,225,242,225,226,233, + 99,128,251,109,235,225,244,225,235,225,238, 97,128, 48,249,238, + 245,115,128, 38, 64,242,244,233,227,225,108, 2,203, 80,203, 86, + 226,225,114,128, 0,124,236,233,238,101, 4,203, 99,203,110,203, + 121,203,130,225,226,239,246,229,227,237, 98,128, 3, 13,226,229, + 236,239,247,227,237, 98,128, 3, 41,236,239,247,237,239,100,128, + 2,204,237,239,100,128, 2,200,247,225,242,237,229,238,233,225, + 110,128, 5,126,232,239,239,107,128, 2,139,105, 3,203,163,203, + 174,203,213,235,225,244,225,235,225,238, 97,128, 48,248,242,225, + 237, 97, 3,203,185,203,195,203,202,226,229,238,231,225,236,105, + 128, 9,205,228,229,246, 97,128, 9, 77,231,245,234,225,242,225, + 244,105,128, 10,205,243,225,242,231, 97, 3,203,225,203,235,203, + 242,226,229,238,231,225,236,105,128, 9,131,228,229,246, 97,128, + 9, 3,231,245,234,225,242,225,244,105,128, 10,131,237,239,238, + 239,243,240,225,227,101,128,255, 86,111, 3,204, 17,204, 28,204, + 98,225,242,237,229,238,233,225,110,128, 5,120,233,227,229,100, + 2,204, 37,204, 73,233,244,229,242,225,244,233,239,110, 2,204, + 51,204, 62,232,233,242,225,231,225,238, 97,128, 48,158,235,225, + 244,225,235,225,238, 97,128, 48,254,237,225,242,235,235,225,238, + 97,129, 48,155,204, 86,232,225,236,230,247,233,228,244,104,128, + 255,158,235,225,244,225,235,225,238, 97,128, 48,250,240,225,242, + 229,110,128, 36,177,116, 2,204,123,204,130,233,236,228,101,128, + 30,125,245,242,238,229,100,128, 2,140,117, 2,204,144,204,155, + 232,233,242,225,231,225,238, 97,128, 48,148,235,225,244,225,235, + 225,238, 97,128, 48,244,119,143, 0,119,204,200,205,177,205,187, + 205,210,205,250,206, 61,206, 69,208, 40,208, 81,208, 93,208,168, + 208,176,208,183,208,194,208,203, 97, 8,204,218,204,225,204,235, + 204,246,205, 28,205, 60,205, 72,205,108,227,245,244,101,128, 30, + 131,229,235,239,242,229,225,110,128, 49, 89,232,233,242,225,231, + 225,238, 97,128, 48,143,107, 2,204,252,205, 20,225,244,225,235, + 225,238, 97,129, 48,239,205, 8,232,225,236,230,247,233,228,244, + 104,128,255,156,239,242,229,225,110,128, 49, 88,243,237,225,236, + 108, 2,205, 38,205, 49,232,233,242,225,231,225,238, 97,128, 48, + 142,235,225,244,225,235,225,238, 97,128, 48,238,244,244,239,243, + 241,245,225,242,101,128, 51, 87,118, 2,205, 78,205, 86,229,228, + 225,243,104,128, 48, 28,249,245,238,228,229,242,243,227,239,242, + 229,246,229,242,244,233,227,225,108,128,254, 52,119, 3,205,116, + 205,125,205,139,225,242,225,226,233, 99,128, 6, 72,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,238,232,225,237,250,225, + 225,226,239,246,101, 2,205,154,205,163,225,242,225,226,233, 99, + 128, 6, 36,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 134,226,243,241,245,225,242,101,128, 51,221,227,233,242, 99, 2, + 205,196,205,201,236,101,128, 36,230,245,237,230,236,229,120,128, + 1,117,100, 2,205,216,205,226,233,229,242,229,243,233,115,128, + 30,133,239,116, 2,205,233,205,242,225,227,227,229,238,116,128, + 30,135,226,229,236,239,119,128, 30,137,101, 4,206, 4,206, 15, + 206, 27,206, 51,232,233,242,225,231,225,238, 97,128, 48,145,233, + 229,242,243,244,242,225,243,115,128, 33, 24,107, 2,206, 33,206, + 43,225,244,225,235,225,238, 97,128, 48,241,239,242,229,225,110, + 128, 49, 94,239,235,239,242,229,225,110,128, 49, 93,231,242,225, + 246,101,128, 30,129,232,233,244,101, 8,206, 90,206, 99,206,183, + 207, 17,207,101,207,146,207,198,207,254,226,245,236,236,229,116, + 128, 37,230, 99, 2,206,105,206,125,233,242,227,236,101,129, 37, + 203,206,115,233,238,246,229,242,243,101,128, 37,217,239,242,238, + 229,242,226,242,225,227,235,229,116, 2,206,142,206,162,236,229, + 230,116,129, 48, 14,206,151,246,229,242,244,233,227,225,108,128, + 254, 67,242,233,231,232,116,129, 48, 15,206,172,246,229,242,244, + 233,227,225,108,128,254, 68,100, 2,206,189,206,230,233,225,237, + 239,238,100,129, 37,199,206,200,227,239,238,244,225,233,238,233, + 238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237, + 239,238,100,128, 37,200,239,247,238,240,239,233,238,244,233,238, + 103, 2,206,246,207, 6,243,237,225,236,236,244,242,233,225,238, + 231,236,101,128, 37,191,244,242,233,225,238,231,236,101,128, 37, + 189,236,101, 2,207, 24,207, 66,230,244,240,239,233,238,244,233, + 238,103, 2,207, 39,207, 55,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,195,244,242,233,225,238,231,236,101,128, + 37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229, + 116, 2,207, 86,207, 93,236,229,230,116,128, 48, 22,242,233,231, + 232,116,128, 48, 23,242,233,231,232,244,240,239,233,238,244,233, + 238,103, 2,207,119,207,135,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,185,244,242,233,225,238,231,236,101,128, + 37,183,115, 3,207,154,207,184,207,192,109, 2,207,160,207,172, + 225,236,236,243,241,245,225,242,101,128, 37,171,233,236,233,238, + 231,230,225,227,101,128, 38, 58,241,245,225,242,101,128, 37,161, + 244,225,114,128, 38, 6,116, 2,207,204,207,215,229,236,229,240, + 232,239,238,101,128, 38, 15,239,242,244,239,233,243,229,243,232, + 229,236,236,226,242,225,227,235,229,116, 2,207,239,207,246,236, + 229,230,116,128, 48, 24,242,233,231,232,116,128, 48, 25,245,240, + 240,239,233,238,244,233,238,103, 2,208, 13,208, 29,243,237,225, + 236,236,244,242,233,225,238,231,236,101,128, 37,181,244,242,233, + 225,238,231,236,101,128, 37,179,105, 2,208, 46,208, 57,232,233, + 242,225,231,225,238, 97,128, 48,144,107, 2,208, 63,208, 73,225, + 244,225,235,225,238, 97,128, 48,240,239,242,229,225,110,128, 49, + 95,237,239,238,239,243,240,225,227,101,128,255, 87,111, 4,208, + 103,208,114,208,139,208,157,232,233,242,225,231,225,238, 97,128, + 48,146,235,225,244,225,235,225,238, 97,129, 48,242,208,127,232, + 225,236,230,247,233,228,244,104,128,255,102,110,129, 32,169,208, + 145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229, + 238,244,232,225,105,128, 14, 39,240,225,242,229,110,128, 36,178, + 242,233,238,103,128, 30,152,243,245,240,229,242,233,239,114,128, + 2,183,244,245,242,238,229,100,128, 2,141,249,238,110,128, 1, + 191,120,137, 0,120,208,231,208,242,208,253,209, 6,209, 33,209, + 46,209, 50,209, 62,209, 70,225,226,239,246,229,227,237, 98,128, + 3, 61,226,239,240,239,237,239,230,111,128, 49, 18,227,233,242, + 227,236,101,128, 36,231,100, 2,209, 12,209, 22,233,229,242,229, + 243,233,115,128, 30,141,239,244,225,227,227,229,238,116,128, 30, + 139,229,232,225,242,237,229,238,233,225,110,128, 5,109,105,128, + 3,190,237,239,238,239,243,240,225,227,101,128,255, 88,240,225, + 242,229,110,128, 36,179,243,245,240,229,242,233,239,114,128, 2, + 227,121,143, 0,121,209,115,210, 74,210, 97,210,137,212,103,212, + 111,212,128,212,192,212,204,213,201,213,241,213,253,214, 8,214, + 29,215, 2, 97, 11,209,139,209,151,209,161,209,168,209,175,209, + 185,209,210,209,221,210, 3,210, 16,210, 62,225,228,239,243,241, + 245,225,242,101,128, 51, 78,226,229,238,231,225,236,105,128, 9, + 175,227,245,244,101,128, 0,253,228,229,246, 97,128, 9, 47,229, + 235,239,242,229,225,110,128, 49, 82,231,117, 2,209,192,209,201, + 234,225,242,225,244,105,128, 10,175,242,237,245,235,232,105,128, + 10, 47,232,233,242,225,231,225,238, 97,128, 48,132,107, 2,209, + 227,209,251,225,244,225,235,225,238, 97,129, 48,228,209,239,232, + 225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110, + 128, 49, 81,237,225,235,235,225,238,244,232,225,105,128, 14, 78, + 243,237,225,236,108, 2,210, 26,210, 37,232,233,242,225,231,225, + 238, 97,128, 48,131,235,225,244,225,235,225,238, 97,129, 48,227, + 210, 50,232,225,236,230,247,233,228,244,104,128,255,108,244,227, + 249,242,233,236,236,233, 99,128, 4, 99,227,233,242, 99, 2,210, + 83,210, 88,236,101,128, 36,232,245,237,230,236,229,120,128, 1, + 119,100, 2,210,103,210,113,233,229,242,229,243,233,115,128, 0, + 255,239,116, 2,210,120,210,129,225,227,227,229,238,116,128, 30, + 143,226,229,236,239,119,128, 30,245,101, 7,210,153,211,161,211, + 170,211,188,211,220,212, 40,212, 91,104, 8,210,171,210,180,210, + 214,210,228,211, 45,211, 61,211,120,211,138,225,242,225,226,233, + 99,128, 6, 74,226,225,242,242,229,101, 2,210,191,210,200,225, + 242,225,226,233, 99,128, 6,210,230,233,238,225,236,225,242,225, + 226,233, 99,128,251,175,230,233,238,225,236,225,242,225,226,233, + 99,128,254,242,232,225,237,250,225,225,226,239,246,101, 4,210, + 247,211, 0,211, 14,211, 30,225,242,225,226,233, 99,128, 6, 38, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,138,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,139,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,254,140,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,243,237,101, 2, + 211, 68,211, 81,228,233,225,236,225,242,225,226,233, 99,128,254, + 244,229,237,105, 2,211, 89,211,104,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,221,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 88,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,148,244,232,242,229,229,228, + 239,244,243,226,229,236,239,247,225,242,225,226,233, 99,128, 6, + 209,235,239,242,229,225,110,128, 49, 86,110,129, 0,165,211,176, + 237,239,238,239,243,240,225,227,101,128,255,229,111, 2,211,194, + 211,203,235,239,242,229,225,110,128, 49, 85,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,134,114, 3,211,228, + 212, 8,212, 20,225,232,226,229,238,249,239,237,111, 2,211,242, + 211,251,232,229,226,242,229,119,128, 5,170,236,229,230,244,232, + 229,226,242,229,119,128, 5,170,233,227,249,242,233,236,236,233, + 99,128, 4, 75,245,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,249,243,233,229,245,238,103, 3,212, + 53,212, 62,212, 78,235,239,242,229,225,110,128, 49,129,240,225, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,131,243,233, + 239,243,235,239,242,229,225,110,128, 49,130,244,233,246,232,229, + 226,242,229,119,128, 5,154,231,242,225,246,101,128, 30,243,232, + 239,239,107,129, 1,180,212,120,225,226,239,246,101,128, 30,247, + 105, 5,212,140,212,151,212,162,212,171,212,179,225,242,237,229, + 238,233,225,110,128, 5,117,227,249,242,233,236,236,233, 99,128, + 4, 87,235,239,242,229,225,110,128, 49, 98,238,249,225,238,103, + 128, 38, 47,247,238,225,242,237,229,238,233,225,110,128, 5,130, + 237,239,238,239,243,240,225,227,101,128,255, 89,111, 7,212,220, + 213, 34,213, 45,213, 55,213, 93,213,139,213,148,100,131, 5,217, + 212,230,212,250,213, 3,228,225,231,229,243,104,129,251, 57,212, + 241,232,229,226,242,229,119,128,251, 57,232,229,226,242,229,119, + 128, 5,217,249,239,100, 2,213, 11,213, 20,232,229,226,242,229, + 119,128, 5,242,240,225,244,225,232,232,229,226,242,229,119,128, + 251, 31,232,233,242,225,231,225,238, 97,128, 48,136,233,235,239, + 242,229,225,110,128, 49,137,107, 2,213, 61,213, 85,225,244,225, + 235,225,238, 97,129, 48,232,213, 73,232,225,236,230,247,233,228, + 244,104,128,255,150,239,242,229,225,110,128, 49, 91,243,237,225, + 236,108, 2,213,103,213,114,232,233,242,225,231,225,238, 97,128, + 48,135,235,225,244,225,235,225,238, 97,129, 48,231,213,127,232, + 225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229, + 107,128, 3,243,121, 2,213,154,213,191, 97, 2,213,160,213,170, + 229,235,239,242,229,225,110,128, 49,136,107, 2,213,176,213,184, + 239,242,229,225,110,128, 49,135,244,232,225,105,128, 14, 34,233, + 238,231,244,232,225,105,128, 14, 13,112, 2,213,207,213,214,225, + 242,229,110,128, 36,180,239,231,229,231,242,225,237,237,229,238, + 105,129, 3,122,213,230,231,242,229,229,235,227,237, 98,128, 3, + 69,114,129, 1,166,213,247,233,238,103,128, 30,153,243,245,240, + 229,242,233,239,114,128, 2,184,116, 2,214, 14,214, 21,233,236, + 228,101,128, 30,249,245,242,238,229,100,128, 2,142,117, 5,214, + 41,214, 52,214, 62,214,100,214,232,232,233,242,225,231,225,238, + 97,128, 48,134,233,235,239,242,229,225,110,128, 49,140,107, 2, + 214, 68,214, 92,225,244,225,235,225,238, 97,129, 48,230,214, 80, + 232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225, + 110,128, 49, 96,115, 3,214,108,214,146,214,187,226,233,103, 2, + 214,116,214,127,227,249,242,233,236,236,233, 99,128, 4,107,233, + 239,244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, + 4,109,236,233,244,244,236,101, 2,214,157,214,168,227,249,242, + 233,236,236,233, 99,128, 4,103,233,239,244,233,230,233,229,228, + 227,249,242,233,236,236,233, 99,128, 4,105,237,225,236,108, 2, + 214,196,214,207,232,233,242,225,231,225,238, 97,128, 48,133,235, + 225,244,225,235,225,238, 97,129, 48,229,214,220,232,225,236,230, + 247,233,228,244,104,128,255,109,249,101, 2,214,239,214,248,235, + 239,242,229,225,110,128, 49,139,239,235,239,242,229,225,110,128, + 49,138,249, 97, 2,215, 9,215, 19,226,229,238,231,225,236,105, + 128, 9,223,228,229,246, 97,128, 9, 95,122,142, 0,122,215, 58, + 216, 66,216, 77,216,120,216,147,217,182,218, 34,218, 76,218, 88, + 218,100,218,128,218,136,218,152,218,161, 97, 10,215, 80,215, 91, + 215, 98,215,105,215,116,215,194,215,224,215,235,216, 15,216, 27, + 225,242,237,229,238,233,225,110,128, 5,102,227,245,244,101,128, + 1,122,228,229,246, 97,128, 9, 91,231,245,242,237,245,235,232, + 105,128, 10, 91,104, 4,215,126,215,135,215,149,215,179,225,242, + 225,226,233, 99,128, 6, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,198,105, 2,215,155,215,170,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,199,242,225,231,225,238, 97, + 128, 48, 86,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,200,233,110, 2,215,201,215,210,225,242,225,226,233, 99,128, + 6, 50,230,233,238,225,236,225,242,225,226,233, 99,128,254,176, + 235,225,244,225,235,225,238, 97,128, 48,182,241,229,102, 2,215, + 243,216, 1,231,225,228,239,236,232,229,226,242,229,119,128, 5, + 149,241,225,244,225,238,232,229,226,242,229,119,128, 5,148,242, + 241,225,232,229,226,242,229,119,128, 5,152,249,233,110,130, 5, + 214,216, 37,216, 57,228,225,231,229,243,104,129,251, 54,216, 48, + 232,229,226,242,229,119,128,251, 54,232,229,226,242,229,119,128, + 5,214,226,239,240,239,237,239,230,111,128, 49, 23, 99, 3,216, + 85,216, 92,216,114,225,242,239,110,128, 1,126,233,242, 99, 2, + 216,100,216,105,236,101,128, 36,233,245,237,230,236,229,120,128, + 30,145,245,242,108,128, 2,145,228,239,116,130, 1,124,216,130, + 216,139,225,227,227,229,238,116,128, 1,124,226,229,236,239,119, + 128, 30,147,101, 6,216,161,216,172,216,215,216,226,216,237,217, + 177,227,249,242,233,236,236,233, 99,128, 4, 55,100, 2,216,178, + 216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,153,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,223,232,233,242,225,231,225,238, 97,128, + 48, 92,235,225,244,225,235,225,238, 97,128, 48,188,242,111,140, + 0, 48,217, 10,217, 19,217, 29,217, 36,217, 61,217, 74,217, 85, + 217, 97,217,108,217,118,217,129,217,136,225,242,225,226,233, 99, + 128, 6, 96,226,229,238,231,225,236,105,128, 9,230,228,229,246, + 97,128, 9,102,231,117, 2,217, 43,217, 52,234,225,242,225,244, + 105,128, 10,230,242,237,245,235,232,105,128, 10,102,232,225,227, + 235,225,242,225,226,233, 99,128, 6, 96,233,238,230,229,242,233, + 239,114,128, 32,128,237,239,238,239,243,240,225,227,101,128,255, + 16,239,236,228,243,244,249,236,101,128,247, 48,240,229,242,243, + 233,225,110,128, 6,240,243,245,240,229,242,233,239,114,128, 32, + 112,244,232,225,105,128, 14, 80,247,233,228,244,104, 3,217,148, + 217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238, + 234,239,233,238,229,114,128, 32, 12,243,240,225,227,101,128, 32, + 11,244, 97,128, 3,182,104, 2,217,188,217,199,226,239,240,239, + 237,239,230,111,128, 49, 19,101, 4,217,209,217,220,217,236,217, + 247,225,242,237,229,238,233,225,110,128, 5,106,226,242,229,246, + 229,227,249,242,233,236,236,233, 99,128, 4,194,227,249,242,233, + 236,236,233, 99,128, 4, 54,100, 2,217,253,218, 16,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,151, + 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, + 4,221,105, 3,218, 42,218, 53,218, 64,232,233,242,225,231,225, + 238, 97,128, 48, 88,235,225,244,225,235,225,238, 97,128, 48,184, + 238,239,242,232,229,226,242,229,119,128, 5,174,236,233,238,229, + 226,229,236,239,119,128, 30,149,237,239,238,239,243,240,225,227, + 101,128,255, 90,111, 2,218,106,218,117,232,233,242,225,231,225, + 238, 97,128, 48, 94,235,225,244,225,235,225,238, 97,128, 48,190, + 240,225,242,229,110,128, 36,181,242,229,244,242,239,230,236,229, + 248,232,239,239,107,128, 2,144,243,244,242,239,235,101,128, 1, + 182,117, 2,218,167,218,178,232,233,242,225,231,225,238, 97,128, + 48, 90,235,225,244,225,235,225,238, 97,128, 48,186 + } +#endif /* DEFINE_PS_TABLES_DATA */ + ; + + +#ifdef DEFINE_PS_TABLES + /* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + + + if ( name == 0 || name >= limit ) + goto NotFound; + + c = *name++; + count = p[1]; + p += 2; + + min = 0; + max = count; + + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + + + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + + Found: + for (;;) + { + /* assert (*p & 127) == c */ + + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + + continue; + } + + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + + p++; + + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + + NextIter: + ; + } + + NotFound: + return 0; + } +#endif /* DEFINE_PS_TABLES */ + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/ftmisc.h b/Dependencies/freetype/freetype/src/raster/ftmisc.h new file mode 100644 index 00000000..943f2aa0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/ftmisc.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * + * ftmisc.h + * + * Miscellaneous macros for stand-alone rasterizer (specification + * only). + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /**************************************************** + * + * This file is *not* portable! You have to adapt + * its definitions to your platform. + * + */ + +#ifndef FTMISC_H_ +#define FTMISC_H_ + + + /* memset */ +#include FT_CONFIG_STANDARD_LIBRARY_H + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#define FT_LOCAL_DEF( x ) static x + + + /* from include/freetype/fttypes.h */ + + typedef unsigned char FT_Byte; + typedef signed int FT_Int; + typedef unsigned int FT_UInt; + typedef signed long FT_Long; + typedef unsigned long FT_ULong; + typedef signed long FT_F26Dot6; + typedef int FT_Error; + + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(FT_Byte)(var) + + + /* from include/freetype/ftsystem.h */ + + typedef struct FT_MemoryRec_* FT_Memory; + + typedef void* (*FT_Alloc_Func)( FT_Memory memory, + long size ); + + typedef void (*FT_Free_Func)( FT_Memory memory, + void* block ); + + typedef void* (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + + typedef struct FT_MemoryRec_ + { + void* user; + + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + + } FT_MemoryRec; + + + /* from src/ftcalc.c */ + +#if ( defined _WIN32 || defined _WIN64 ) + + typedef __int64 FT_Int64; + +#else + +#include "inttypes.h" + + typedef int64_t FT_Int64; + +#endif + + + static FT_Long + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + + + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + + d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c + : 0x7FFFFFFFL ); + + return ( s > 0 ) ? d : -d; + } + +#endif /* FTMISC_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/ftraster.c b/Dependencies/freetype/freetype/src/raster/ftraster.c new file mode 100644 index 00000000..e4b7b937 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/ftraster.c @@ -0,0 +1,2738 @@ +/**************************************************************************** + * + * ftraster.c + * + * The FreeType glyph rasterizer (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file can be compiled without the rest of the FreeType engine, by + * defining the STANDALONE_ macro when compiling it. You also need to + * put the files `ftimage.h' and `ftmisc.h' into the $(incdir) + * directory. Typically, you should do something like + * + * - copy `src/raster/ftraster.c' (this file) to your current directory + * + * - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' to your + * current directory + * + * - compile `ftraster' with the STANDALONE_ macro defined, as in + * + * cc -c -DSTANDALONE_ ftraster.c + * + * The renderer can be initialized with a call to + * `ft_standard_raster.raster_new'; a bitmap can be generated + * with a call to `ft_standard_raster.raster_render'. + * + * See the comments and documentation in the file `ftimage.h' for more + * details on how the raster works. + * + */ + + + /************************************************************************** + * + * This is a rewrite of the FreeType 1.x scan-line converter + * + */ + +#ifdef STANDALONE_ + + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ +#define FT_RENDER_POOL_SIZE 16384L + +#define FT_CONFIG_STANDARD_LIBRARY_H + +#include /* for memset */ + +#include "ftmisc.h" +#include "ftimage.h" + +#else /* !STANDALONE_ */ + +#include "ftraster.h" +#include /* for FT_MulDiv_No_Round */ + +#endif /* !STANDALONE_ */ + + + /************************************************************************** + * + * A simple technical note on how the raster works + * ----------------------------------------------- + * + * Converting an outline into a bitmap is achieved in several steps: + * + * 1 - Decomposing the outline into successive `profiles'. Each + * profile is simply an array of scanline intersections on a given + * dimension. A profile's main attributes are + * + * o its scanline position boundaries, i.e. `Ymin' and `Ymax' + * + * o an array of intersection coordinates for each scanline + * between `Ymin' and `Ymax' + * + * o a direction, indicating whether it was built going `up' or + * `down', as this is very important for filling rules + * + * o its drop-out mode + * + * 2 - Sweeping the target map's scanlines in order to compute segment + * `spans' which are then filled. Additionally, this pass + * performs drop-out control. + * + * The outline data is parsed during step 1 only. The profiles are + * built from the bottom of the render pool, used as a stack. The + * following graphics shows the profile list under construction: + * + * __________________________________________________________ _ _ + * | | | | | + * | profile | coordinates for | profile | coordinates for |--> + * | 1 | profile 1 | 2 | profile 2 |--> + * |_________|_________________|_________|_________________|__ _ _ + * + * ^ ^ + * | | + * start of render pool top + * + * The top of the profile stack is kept in the `top' variable. + * + * As you can see, a profile record is pushed on top of the render + * pool, which is then followed by its coordinates/intersections. If + * a change of direction is detected in the outline, a new profile is + * generated until the end of the outline. + * + * Note that, for all generated profiles, the function End_Profile() + * is used to record all their bottom-most scanlines as well as the + * scanline above their upmost boundary. These positions are called + * `y-turns' because they (sort of) correspond to local extrema. + * They are stored in a sorted list built from the top of the render + * pool as a downwards stack: + * + * _ _ _______________________________________ + * | | + * <--| sorted list of | + * <--| extrema scanlines | + * _ _ __________________|____________________| + * + * ^ ^ + * | | + * maxBuff sizeBuff = end of pool + * + * This list is later used during the sweep phase in order to + * optimize performance (see technical note on the sweep below). + * + * Of course, the raster detects whether the two stacks collide and + * handles the situation by bisecting the job and restarting. + * + */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** CONFIGURATION MACROS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OTHER MACROS (do not change) **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT raster + + +#ifdef STANDALONE_ + + /* Auxiliary macros for token concatenation. */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + /* Disable the tracing mechanism for simplicity -- developers can */ + /* activate it easily by redefining these macros. */ +#ifndef FT_ERROR +#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ +#endif + +#ifndef FT_TRACE +#define FT_TRACE( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ +#endif + +#ifndef FT_THROW +#define FT_THROW( e ) FT_ERR_CAT( Raster_Err_, e ) +#endif + +#define Raster_Err_Ok 0 +#define Raster_Err_Invalid_Outline -1 +#define Raster_Err_Cannot_Render_Glyph -2 +#define Raster_Err_Invalid_Argument -3 +#define Raster_Err_Raster_Overflow -4 +#define Raster_Err_Raster_Uninitialized -5 +#define Raster_Err_Raster_Negative_Height -6 + +#define ft_memset memset + +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \ + raster_reset_, raster_set_mode_, \ + raster_render_, raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + +#else /* !STANDALONE_ */ + + +#include +#include /* for FT_TRACE, FT_ERROR, and FT_THROW */ + +#include "rasterrs.h" + + +#endif /* !STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + +#ifndef FT_ZERO +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) +#endif + + /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ + /* typically a small value and the result of a*b is known to fit into */ + /* 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) + + /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ + /* for clipping computations. It simply uses the FT_MulDiv() function */ + /* defined in `ftcalc.h'. */ +#define SMulDiv_No_Round FT_MulDiv_No_Round + + /* The rasterizer is a very general purpose component; please leave */ + /* the following redefinitions there (you never know your target */ + /* environment). */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL (void*)0 +#endif + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE 1 +#endif + + +#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ + /* Setting this constant to more than 32 is a */ + /* pure waste of space. */ + +#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SIMPLE TYPE DECLARATIONS **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + typedef int Int; + typedef unsigned int UInt; + typedef short Short; + typedef unsigned short UShort, *PUShort; + typedef long Long, *PLong; + typedef unsigned long ULong; + + typedef unsigned char Byte, *PByte; + typedef char Bool; + + typedef struct TPoint_ + { + Long x; + Long y; + + } TPoint; + + + /* values for the `flags' bit field */ +#define Flow_Up 0x08U +#define Overshoot_Top 0x10U +#define Overshoot_Bottom 0x20U +#define Dropout 0x40U + + + /* States of each line, arc, and profile */ + typedef enum TStates_ + { + Unknown_State, + Ascending_State, + Descending_State, + Flat_State + + } TStates; + + + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + + struct TProfile_ + { + PProfile link; /* link to next profile (various purposes) */ + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + Int offset; /* bottom or currently scanned array index */ + Int height; /* profile's height in scanlines */ + Int start; /* profile's starting scanline, also use */ + /* as activation counter */ + UShort flags; /* Bit 0-2: drop-out mode */ + /* Bit 3: profile orientation (up/down) */ + /* Bit 4: is top profile? */ + /* Bit 5: is bottom profile? */ + /* Bit 6: dropout detected */ + + FT_F26Dot6 X; /* current coordinate during sweep */ + Long x[1]; /* actually variable array of scanline */ + /* intersections with `height` elements */ + }; + + typedef PProfile TProfileList; + typedef PProfile* PProfileList; + + +#undef RAS_ARG +#undef RAS_ARGS +#undef RAS_VAR +#undef RAS_VARS + +#ifdef FT_STATIC_RASTER + + +#define RAS_ARGS /* void */ +#define RAS_ARG void + +#define RAS_VARS /* void */ +#define RAS_VAR /* void */ + +#define FT_UNUSED_RASTER do { } while ( 0 ) + + +#else /* !FT_STATIC_RASTER */ + + +#define RAS_ARGS black_PWorker worker, +#define RAS_ARG black_PWorker worker + +#define RAS_VARS worker, +#define RAS_VAR worker + +#define FT_UNUSED_RASTER FT_UNUSED( worker ) + + +#endif /* !FT_STATIC_RASTER */ + + + typedef struct black_TWorker_ black_TWorker, *black_PWorker; + + + /* prototypes used for sweep function dispatch */ + typedef void + Function_Sweep_Init( RAS_ARGS Int min, + Int max ); + + typedef void + Function_Sweep_Span( RAS_ARGS Int y, + FT_F26Dot6 x1, + FT_F26Dot6 x2 ); + + typedef void + Function_Sweep_Step( RAS_ARG ); + + + /* NOTE: These operations are only valid on 2's complement processors */ +#undef FLOOR +#undef CEILING +#undef TRUNC +#undef SCALED + +#define FLOOR( x ) ( (x) & -ras.precision ) +#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) +#define TRUNC( x ) ( (Long)(x) >> ras.precision_bits ) +#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) + + /* scale and shift grid to pixel centers */ +#define SCALED( x ) ( (x) * ras.precision_scale - ras.precision_half ) + +#define IS_BOTTOM_OVERSHOOT( x ) \ + (Bool)( CEILING( x ) - x >= ras.precision_half ) +#define IS_TOP_OVERSHOOT( x ) \ + (Bool)( x - FLOOR( x ) >= ras.precision_half ) + + /* Smart dropout rounding to find which pixel is closer to span ends. */ + /* To mimic Windows, symmetric cases do not depend on the precision. */ +#define SMART( p, q ) FLOOR( ( (p) + (q) + ras.precision * 63 / 64 ) >> 1 ) + +#if FT_RENDER_POOL_SIZE > 2048 +#define FT_MAX_BLACK_POOL ( FT_RENDER_POOL_SIZE / sizeof ( Long ) ) +#else +#define FT_MAX_BLACK_POOL ( 2048 / sizeof ( Long ) ) +#endif + + /* The most used variables are positioned at the top of the structure. */ + /* Thus, their offset can be coded with less opcodes, resulting in a */ + /* smaller executable. */ + + struct black_TWorker_ + { + Int precision_bits; /* precision related variables */ + Int precision; + Int precision_half; + Int precision_scale; + Int precision_step; + + PLong buff; /* The profiles buffer */ + PLong sizeBuff; /* Render pool size */ + PLong maxBuff; /* Profiles buffer size */ + PLong top; /* Current cursor in buffer */ + + FT_Error error; + + Byte dropOutControl; /* current drop_out control method */ + + Long lastX, lastY; + Long minY, maxY; + + UShort num_Profs; /* current number of profiles */ + Int numTurns; /* number of Y-turns in outline */ + + PProfile cProfile; /* current profile */ + PProfile fProfile; /* head of linked list of profiles */ + PProfile gProfile; /* contour's first profile in case */ + /* of impact */ + + TStates state; /* rendering state */ + + FT_Outline outline; + + Int bTop; /* target bitmap max line index */ + Int bRight; /* target bitmap rightmost index */ + Int bPitch; /* target bitmap pitch */ + PByte bOrigin; /* target bitmap bottom-left origin */ + PByte bLine; /* target bitmap current line */ + + /* dispatch variables */ + + Function_Sweep_Init* Proc_Sweep_Init; + Function_Sweep_Span* Proc_Sweep_Span; + Function_Sweep_Span* Proc_Sweep_Drop; + Function_Sweep_Step* Proc_Sweep_Step; + + }; + + + typedef struct black_TRaster_ + { + void* memory; + + } black_TRaster, *black_PRaster; + +#ifdef FT_STATIC_RASTER + + static black_TWorker ras; + +#else /* !FT_STATIC_RASTER */ + +#define ras (*worker) + +#endif /* !FT_STATIC_RASTER */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** PROFILES COMPUTATION **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * Set_High_Precision + * + * @Description: + * Set precision variables according to param flag. + * + * @Input: + * High :: + * Set to True for high precision (typically for ppem < 24), + * false otherwise. + */ + static void + Set_High_Precision( RAS_ARGS Int High ) + { + /* + * `precision_step' is used in `Bezier_Up' to decide when to split a + * given y-monotonous Bezier arc that crosses a scanline before + * approximating it as a straight segment. The default value of 32 (for + * low accuracy) corresponds to + * + * 32 / 64 == 0.5 pixels, + * + * while for the high accuracy case we have + * + * 256 / (1 << 12) = 0.0625 pixels. + * + */ + + if ( High ) + { + ras.precision_bits = 12; + ras.precision_step = 256; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + } + + ras.precision = 1 << ras.precision_bits; + ras.precision_half = ras.precision >> 1; + ras.precision_scale = ras.precision >> Pixel_Bits; + } + + + /************************************************************************** + * + * @Function: + * Insert_Y_Turn + * + * @Description: + * Insert a salient into the sorted list placed on top of the render + * pool. + * + * @Input: + * New y scanline position. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow. + */ + static Bool + Insert_Y_Turns( RAS_ARGS Int y, + Int top ) + { + Int n = ras.numTurns; + PLong y_turns = ras.maxBuff; + + + /* update top value */ + if ( n == 0 || top > y_turns[n] ) + y_turns[n] = top; + + /* look for first y value that is <= */ + while ( n-- && y < y_turns[n] ) + ; + + /* if it is <, simply insert it, ignore if == */ + if ( n < 0 || y > y_turns[n] ) + { + ras.maxBuff--; + if ( ras.maxBuff <= ras.top ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + do + { + Int y2 = (Int)y_turns[n]; + + + y_turns[n] = y; + y = y2; + } while ( n-- >= 0 ); + + ras.numTurns++; + } + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * New_Profile + * + * @Description: + * Create a new profile in the render pool. + * + * @Input: + * aState :: + * The state/orientation of the new profile. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or of incoherent + * profile. + */ + static Bool + New_Profile( RAS_ARGS TStates aState ) + { + Long e; + + + if ( !ras.cProfile || ras.cProfile->height ) + { + ras.cProfile = (PProfile)ras.top; + ras.top = ras.cProfile->x; + + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in New_Profile\n" )); + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + ras.cProfile->height = 0; + } + + ras.cProfile->flags = ras.dropOutControl; + + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flags |= Flow_Up; + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Bottom; + + e = CEILING( ras.lastY ); + break; + + case Descending_State: + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Top; + + e = FLOOR( ras.lastY ); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction\n" )); + ras.error = FT_THROW( Invalid_Outline ); + return FAILURE; + } + + if ( e > ras.maxY ) + e = ras.maxY; + if ( e < ras.minY ) + e = ras.minY; + ras.cProfile->start = (Int)TRUNC( e ); + + FT_TRACE7(( " new %s profile = %p, start = %d\n", + aState == Ascending_State ? "ascending" : "descending", + (void *)ras.cProfile, ras.cProfile->start )); + + if ( ras.lastY == e ) + *ras.top++ = ras.lastX; + + ras.state = aState; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * End_Profile + * + * @Description: + * Finalize the current profile and record y-turns. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or incoherency. + */ + static Bool + End_Profile( RAS_ARG ) + { + PProfile p = ras.cProfile; + Int h = (Int)( ras.top - p->x ); + Int bottom, top; + + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered\n" )); + ras.error = FT_THROW( Raster_Negative_Height ); + return FAILURE; + } + + if ( h > 0 ) + { + FT_TRACE7(( " ending profile %p, start = %2d, height = %+3d\n", + (void *)p, p->start, p->flags & Flow_Up ? h : -h )); + + p->height = h; + + if ( p->flags & Flow_Up ) + { + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Top; + + bottom = p->start; + top = bottom + h; + p->offset = 0; + p->X = p->x[0]; + } + else + { + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Bottom; + + top = p->start + 1; + bottom = top - h; + p->start = bottom; + p->offset = h - 1; + p->X = p->x[h - 1]; + } + + if ( Insert_Y_Turns( RAS_VARS bottom, top ) ) + return FAILURE; + + if ( !ras.gProfile ) + ras.gProfile = p; + + /* preliminary values to be finalized */ + p->next = ras.gProfile; + p->link = (PProfile)ras.top; + + ras.num_Profs++; + } + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Finalize_Profile_Table + * + * @Description: + * Adjust all links in the profiles list. + */ + static void + Finalize_Profile_Table( RAS_ARG ) + { + UShort n = ras.num_Profs; + PProfile p = ras.fProfile; + PProfile q; + + + /* there should be at least two profiles, up and down */ + while ( --n ) + { + q = p->link; + + /* fix the contour loop */ + if ( q->next == p->next ) + p->next = q; + + p = q; + } + + /* null-terminate */ + p->link = NULL; + } + + + /************************************************************************** + * + * @Function: + * Split_Conic + * + * @Description: + * Subdivide one conic Bezier into two joint sub-arcs in the Bezier + * stack. + * + * @Input: + * None (subdivided Bezier is taken from the top of the stack). + * + * @Note: + * This routine is the `beef' of this component. It is _the_ inner + * loop that should be optimized to hell to get the best performance. + */ + static void + Split_Conic( TPoint* base ) + { + Long a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + + /* hand optimized. gcc doesn't seem to be too good at common */ + /* expression substitution and instruction scheduling ;-) */ + } + + + /************************************************************************** + * + * @Function: + * Split_Cubic + * + * @Description: + * Subdivide a third-order Bezier arc into two joint sub-arcs in the + * Bezier stack. + * + * @Note: + * This routine is the `beef' of the component. It is one of _the_ + * inner loops that should be optimized like hell to get the best + * performance. + */ + static void + Split_Cubic( TPoint* base ) + { + Long a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + /************************************************************************** + * + * @Function: + * Line_Up + * + * @Description: + * Compute the x-coordinates of an ascending line segment and store + * them in the render pool. + * + * @Input: + * x1 :: + * The x-coordinate of the segment's start point. + * + * y1 :: + * The y-coordinate of the segment's start point. + * + * x2 :: + * The x-coordinate of the segment's end point. + * + * y2 :: + * The y-coordinate of the segment's end point. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Line_Up( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Long e, e2, Dx, Dy; + Long Ix, Rx, Ax; + Int size; + + PLong top; + + + if ( y2 < miny || y1 > maxy ) + return SUCCESS; + + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( y1 ); + + if ( y1 == e ) + e += ras.precision; + + if ( e2 < e ) /* nothing to do */ + return SUCCESS; + + size = (Int)TRUNC( e2 - e ) + 1; + top = ras.top; + + if ( top + size >= ras.maxBuff ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dx == 0 ) /* very easy */ + { + do + *top++ = x1; + while ( --size ); + goto Fin; + } + + Ix = SMulDiv_No_Round( e - y1, Dx, Dy ); + x1 += Ix; + *top++ = x1; + + if ( --size ) + { + Ax = Dx * ( e - y1 ) - Dy * Ix; /* remainder */ + Ix = FMulDiv( ras.precision, Dx, Dy ); + Rx = Dx * ras.precision - Dy * Ix; /* remainder */ + Dx = 1; + + if ( x2 < x1 ) + { + Ax = -Ax; + Rx = -Rx; + Dx = -Dx; + } + + do + { + x1 += Ix; + Ax += Rx; + if ( Ax >= Dy ) + { + Ax -= Dy; + x1 += Dx; + } + *top++ = x1; + } + while ( --size ); + } + + Fin: + ras.top = top; + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Line_Down + * + * @Description: + * Compute the x-coordinates of an descending line segment and store + * them in the render pool. + * + * @Input: + * x1 :: + * The x-coordinate of the segment's start point. + * + * y1 :: + * The y-coordinate of the segment's start point. + * + * x2 :: + * The x-coordinate of the segment's end point. + * + * y2 :: + * The y-coordinate of the segment's end point. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Line_Down( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + return Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); + } + + + /* A function type describing the functions used to split Bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + + + /************************************************************************** + * + * @Function: + * Bezier_Up + * + * @Description: + * Compute the x-coordinates of an ascending Bezier arc and store + * them in the render pool. + * + * @Input: + * degree :: + * The degree of the Bezier arc (either 2 or 3). + * + * splitter :: + * The function to split Bezier arcs. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Bezier_Up( RAS_ARGS Int degree, + TPoint* arc, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, dy; + Long dx, x2; + + PLong top; + + + y1 = arc[degree].y; + y2 = arc[0].y; + + if ( y2 < miny || y1 > maxy ) + return SUCCESS; + + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( y1 ); + + if ( y1 == e ) + e += ras.precision; + + if ( e2 < e ) /* nothing to do */ + return SUCCESS; + + top = ras.top; + + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + do + { + y2 = arc[0].y; + x2 = arc[0].x; + + if ( y2 > e ) + { + dy = y2 - arc[degree].y; + dx = x2 - arc[degree].x; + + /* split condition should be invariant of direction */ + if ( dy > ras.precision_step || + dx > ras.precision_step || + -dx > ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = x2 - FMulDiv( y2 - e, dx, dy ); + e += ras.precision; + arc -= degree; + } + } + else + { + if ( y2 == e ) + { + *top++ = x2; + e += ras.precision; + } + arc -= degree; + } + } + while ( e <= e2 ); + + ras.top = top; + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * Bezier_Down + * + * @Description: + * Compute the x-coordinates of an descending Bezier arc and store + * them in the render pool. + * + * @Input: + * degree :: + * The degree of the Bezier arc (either 2 or 3). + * + * splitter :: + * The function to split Bezier arcs. + * + * miny :: + * A lower vertical clipping bound value. + * + * maxy :: + * An upper vertical clipping bound value. + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow. + */ + static Bool + Bezier_Down( RAS_ARGS Int degree, + TPoint* arc, + TSplitter splitter, + Long miny, + Long maxy ) + { + Bool result; + + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if ( degree > 2 ) + arc[3].y = -arc[3].y; + + result = Bezier_Up( RAS_VARS degree, arc, splitter, -maxy, -miny ); + + arc[0].y = -arc[0].y; + return result; + } + + + /************************************************************************** + * + * @Function: + * Line_To + * + * @Description: + * Inject a new line segment and adjust the Profiles list. + * + * @Input: + * x :: + * The x-coordinate of the segment's end point (its start point + * is stored in `lastX'). + * + * y :: + * The y-coordinate of the segment's end point (its start point + * is stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Line_To( RAS_ARGS Long x, + Long y ) + { + TStates state; + + + if ( y == ras.lastY ) + goto Fin; + + /* First, detect a change of direction */ + + state = ras.lastY < y ? Ascending_State : Descending_State; + + if ( ras.state != state ) + { + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; + + /* create a new profile */ + if ( New_Profile( RAS_VARS state ) ) + goto Fail; + } + + /* Then compute the lines */ + + if ( state == Ascending_State ) + { + if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + goto Fail; + } + else + { + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + goto Fail; + } + + Fin: + ras.lastX = x; + ras.lastY = y; + return SUCCESS; + + Fail: + return FAILURE; + } + + + /************************************************************************** + * + * @Function: + * Conic_To + * + * @Description: + * Inject a new conic arc and adjust the profile list. + * + * @Input: + * cx :: + * The x-coordinate of the arc's new control point. + * + * cy :: + * The y-coordinate of the arc's new control point. + * + * x :: + * The x-coordinate of the arc's end point (its start point is + * stored in `lastX'). + * + * y :: + * The y-coordinate of the arc's end point (its start point is + * stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) + { + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; + TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ + + + arc = arcs; + arc[2].x = ras.lastX; + arc[2].y = ras.lastY; + arc[1].x = cx; + arc[1].y = cy; + arc[0].x = x; + arc[0].y = y; + + do + { + y1 = arc[2].y; + y2 = arc[1].y; + y3 = arc[0].y; + x3 = arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y3 ) + { + ymin = y1; + ymax = y3; + } + else + { + ymin = y3; + ymax = y1; + } + + if ( y2 < FLOOR( ymin ) || y2 > CEILING( ymax ) ) + { + /* this arc has no given direction, split it! */ + Split_Conic( arc ); + arc += 2; + } + else if ( y1 == y3 ) + { + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ + arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; + } + else + { + /* the arc is y-monotonous, either ascending or descending */ + /* detect a change of direction */ + state_bez = y1 < y3 ? Ascending_State : Descending_State; + if ( ras.state != state_bez ) + { + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; + + /* create a new profile */ + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* now call the appropriate routine */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) + goto Fail; + arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; + } + + } while ( arc >= arcs ); + + return SUCCESS; + + Fail: + return FAILURE; + } + + + /************************************************************************** + * + * @Function: + * Cubic_To + * + * @Description: + * Inject a new cubic arc and adjust the profile list. + * + * @Input: + * cx1 :: + * The x-coordinate of the arc's first new control point. + * + * cy1 :: + * The y-coordinate of the arc's first new control point. + * + * cx2 :: + * The x-coordinate of the arc's second new control point. + * + * cy2 :: + * The y-coordinate of the arc's second new control point. + * + * x :: + * The x-coordinate of the arc's end point (its start point is + * stored in `lastX'). + * + * y :: + * The y-coordinate of the arc's end point (its start point is + * stored in `lastY'). + * + * @Return: + * SUCCESS on success, FAILURE on render pool overflow or incorrect + * profile. + */ + static Bool + Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) + { + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; + TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ + + + arc = arcs; + arc[3].x = ras.lastX; + arc[3].y = ras.lastY; + arc[2].x = cx1; + arc[2].y = cy1; + arc[1].x = cx2; + arc[1].y = cy2; + arc[0].x = x; + arc[0].y = y; + + do + { + y1 = arc[3].y; + y2 = arc[2].y; + y3 = arc[1].y; + y4 = arc[0].y; + x4 = arc[0].x; + + /* first, categorize the Bezier arc */ + + if ( y1 <= y4 ) + { + ymin1 = y1; + ymax1 = y4; + } + else + { + ymin1 = y4; + ymax1 = y1; + } + + if ( y2 <= y3 ) + { + ymin2 = y2; + ymax2 = y3; + } + else + { + ymin2 = y3; + ymax2 = y2; + } + + if ( ymin2 < FLOOR( ymin1 ) || ymax2 > CEILING( ymax1 ) ) + { + /* this arc has no given direction, split it! */ + Split_Cubic( arc ); + arc += 3; + } + else if ( y1 == y4 ) + { + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ + arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; + } + else + { + state_bez = y1 < y4 ? Ascending_State : Descending_State; + + /* detect a change of direction */ + if ( ras.state != state_bez ) + { + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; + + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; + } + + /* compute intersections */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) + goto Fail; + arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; + } + + } while ( arc >= arcs ); + + return SUCCESS; + + Fail: + return FAILURE; + } + + +#undef SWAP_ +#define SWAP_( x, y ) do \ + { \ + Long swap = x; \ + \ + \ + x = y; \ + y = swap; \ + } while ( 0 ) + + + /************************************************************************** + * + * @Function: + * Decompose_Curve + * + * @Description: + * Scan the outline arrays in order to emit individual segments and + * Beziers by calling Line_To() and Bezier_To(). It handles all + * weird cases, like when the first point is off the curve, or when + * there are simply no `on' points in the contour! + * + * @Input: + * first :: + * The index of the first point in the contour. + * + * last :: + * The index of the last point in the contour. + * + * flipped :: + * If set, flip the direction of the curve. + * + * @Return: + * SUCCESS on success, FAILURE on error. + * + * @Note: + * Unlike FT_Outline_Decompose(), this function handles the scanmode + * dropout tags in the individual contours. Therefore, it cannot be + * replaced. + */ + static Bool + Decompose_Curve( RAS_ARGS Int first, + Int last, + Int flipped ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + FT_Byte* tags; + + UInt tag; /* current point's state */ + + + points = ras.outline.points; + limit = points + last; + + v_start.x = SCALED( points[first].x ); + v_start.y = SCALED( points[first].y ); + v_last.x = SCALED( points[last].x ); + v_last.y = SCALED( points[last].y ); + + if ( flipped ) + { + SWAP_( v_start.x, v_start.y ); + SWAP_( v_last.x, v_last.y ); + } + + v_control = v_start; + + point = points + first; + tags = ras.outline.tags + first; + + /* set scan mode if necessary */ + if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE ) + ras.dropOutControl = (Byte)tags[0] >> 5; + + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + /* v_last = v_start; */ + } + point--; + tags--; + } + + ras.lastX = v_start.x; + ras.lastY = v_start.y; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + Long x, y; + + + x = SCALED( point->x ); + y = SCALED( point->y ); + if ( flipped ) + SWAP_( x, y ); + + if ( Line_To( RAS_VARS x, y ) ) + goto Fail; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point[0].x ); + v_control.y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( v_control.x, v_control.y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector v_middle; + Long x, y; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + x = SCALED( point[0].x ); + y = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x, y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) + goto Fail; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + x ) / 2; + v_middle.y = ( v_control.y + y ) / 2; + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y ) ) + goto Fail; + + v_control.x = x; + v_control.y = y; + + goto Do_Conic; + } + + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y ) ) + goto Fail; + + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + Long x1, y1, x2, y2, x3, y3; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + x1 = SCALED( point[-2].x ); + y1 = SCALED( point[-2].y ); + x2 = SCALED( point[-1].x ); + y2 = SCALED( point[-1].y ); + + if ( flipped ) + { + SWAP_( x1, y1 ); + SWAP_( x2, y2 ); + } + + if ( point <= limit ) + { + x3 = SCALED( point[0].x ); + y3 = SCALED( point[0].y ); + + if ( flipped ) + SWAP_( x3, y3 ); + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) + goto Fail; + continue; + } + + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) + goto Fail; + goto Close; + } + } + } + + /* close the contour with a line segment */ + if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) + goto Fail; + + Close: + return SUCCESS; + + Invalid_Outline: + ras.error = FT_THROW( Invalid_Outline ); + + Fail: + return FAILURE; + } + + + /************************************************************************** + * + * @Function: + * Convert_Glyph + * + * @Description: + * Convert a glyph into a series of segments and arcs and make a + * profiles list with them. + * + * @Input: + * flipped :: + * If set, flip the direction of curve. + * + * @Return: + * SUCCESS on success, FAILURE if any error was encountered during + * rendering. + */ + static Bool + Convert_Glyph( RAS_ARGS Int flipped ) + { + Int i; + Int first, last; + + + ras.fProfile = NULL; + ras.cProfile = NULL; + + ras.top = ras.buff; + ras.maxBuff = ras.sizeBuff - 1; /* top reserve */ + + ras.numTurns = 0; + ras.num_Profs = 0; + + last = -1; + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + ras.state = Unknown_State; + ras.gProfile = NULL; + + first = last + 1; + last = ras.outline.contours[i]; + + if ( Decompose_Curve( RAS_VARS first, last, flipped ) ) + return FAILURE; + + /* Note that ras.gProfile can stay nil if the contour was */ + /* too small to be drawn or degenerate. */ + if ( !ras.gProfile ) + continue; + + /* we must now check whether the extreme arcs join or not */ + if ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) + if ( ( ras.gProfile->flags & Flow_Up ) == + ( ras.cProfile->flags & Flow_Up ) ) + ras.top--; + + if ( End_Profile( RAS_VAR ) ) + return FAILURE; + + if ( !ras.fProfile ) + ras.fProfile = ras.gProfile; + } + + if ( ras.fProfile ) + Finalize_Profile_Table( RAS_VAR ); + + return SUCCESS; + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** SCAN-LINE SWEEPS AND DRAWING **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * InsNew + * + * Inserts a new profile in a linked list, sorted by coordinate. + */ + static void + InsNew( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + Long x; + + + old = list; + current = *old; + x = profile->X; + + while ( current && current->X < x ) + { + old = ¤t->link; + current = *old; + } + + profile->link = current; + *old = profile; + } + + + /************************************************************************** + * + * Increment + * + * Advances all profile in the list to the next scanline. It also + * sorts the trace list in the unlikely case of profile crossing. + * The profiles are inserted in sorted order. We might need a single + * swap to fix it when profiles (contours) cross. + * Bubble sort with immediate restart is good enough and simple. + */ + static void + Increment( PProfileList list, + Int flow ) + { + PProfile *old, current, next; + + + /* First, set the new X coordinates and remove exhausted profiles */ + old = list; + while ( *old ) + { + current = *old; + if ( --current->height ) + { + current->offset += flow; + current->X = current->x[current->offset]; + old = ¤t->link; + } + else + *old = current->link; /* remove */ + } + + /* Then make sure the list remains sorted */ + old = list; + current = *old; + + if ( !current ) + return; + + while ( current->link ) + { + next = current->link; + + if ( current->X <= next->X ) + { + old = ¤t->link; + current = next; + } + else + { + *old = next; + current->link = next->link; + next->link = current; + + /* this is likely the only necessary swap -- restart */ + old = list; + current = *old; + } + } + } + + + /************************************************************************** + * + * Vertical Sweep Procedure Set + * + * These four routines are used during the vertical black/white sweep + * phase by the generic Draw_Sweep() function. + * + */ + + static void + Vertical_Sweep_Init( RAS_ARGS Int min, + Int max ) + { + FT_UNUSED( max ); + + + ras.bLine = ras.bOrigin - min * ras.bPitch; + } + + + static void + Vertical_Sweep_Span( RAS_ARGS Int y, + FT_F26Dot6 x1, + FT_F26Dot6 x2 ) + { + Int e1 = (Int)TRUNC( CEILING( x1 ) ); + Int e2 = (Int)TRUNC( FLOOR( x2 ) ); + + FT_UNUSED( y ); + + + FT_TRACE7(( " y=%d x=[% .*f;% .*f]", + y, + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); + + if ( e2 >= 0 && e1 <= ras.bRight ) + { + PByte target; + + Int c1, f1, c2, f2; + + + if ( e1 < 0 ) + e1 = 0; + if ( e2 > ras.bRight ) + e2 = ras.bRight; + + FT_TRACE7(( " -> x=[%d;%d]", e1, e2 )); + + c1 = e1 >> 3; + c2 = e2 >> 3; + + f1 = 0xFF >> ( e1 & 7 ); + f2 = ~0x7F >> ( e2 & 7 ); + + target = ras.bLine + c1; + c2 -= c1; + + if ( c2 > 0 ) + { + target[0] |= f1; + + /* memset() is slower than the following code on many platforms. */ + /* This is due to the fact that, in the vast majority of cases, */ + /* the span length in bytes is relatively small. */ + while ( --c2 > 0 ) + *( ++target ) = 0xFF; + + target[1] |= f2; + } + else + *target |= ( f1 & f2 ); + } + + FT_TRACE7(( "\n" )); + } + + + static void + Vertical_Sweep_Drop( RAS_ARGS Int y, + FT_F26Dot6 x1, + FT_F26Dot6 x2 ) + { + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); + Int c1, f1; + + FT_UNUSED( y ); + + + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bRight ) + e1 = e2; + + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bRight ) + { + c1 = e2 >> 3; + f1 = 0x80 >> ( e2 & 7 ); + + if ( ras.bLine[c1] & f1 ) + return; + } + + if ( e1 >= 0 && e1 <= ras.bRight ) + { + c1 = e1 >> 3; + f1 = 0x80 >> ( e1 & 7 ); + + FT_TRACE7(( " y=%d x=%d%s\n", y, e1, + ras.bLine[c1] & f1 ? " redundant" : "" )); + + ras.bLine[c1] |= f1; + } + } + + + static void + Vertical_Sweep_Step( RAS_ARG ) + { + ras.bLine -= ras.bPitch; + } + + + /************************************************************************ + * + * Horizontal Sweep Procedure Set + * + * These four routines are used during the horizontal black/white + * sweep phase by the generic Draw_Sweep() function. + * + */ + + static void + Horizontal_Sweep_Init( RAS_ARGS Int min, + Int max ) + { + /* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( min ); + FT_UNUSED( max ); + } + + + static void + Horizontal_Sweep_Span( RAS_ARGS Int y, + FT_F26Dot6 x1, + FT_F26Dot6 x2 ) + { + Long e1 = CEILING( x1 ); + Long e2 = FLOOR( x2 ); + + + FT_TRACE7(( " x=%d y=[% .*f;% .*f]", + y, + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); + + /* We should not need this procedure but the vertical sweep */ + /* mishandles horizontal lines through pixel centers. So we */ + /* have to check perfectly aligned span edges here. */ + /* */ + /* XXX: Can we handle horizontal lines better and drop this? */ + + if ( x1 == e1 ) + { + e1 = TRUNC( e1 ); + + if ( e1 >= 0 && e1 <= ras.bTop ) + { + Int f1; + PByte bits; + + + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); + + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e1 )); + + bits[0] |= f1; + } + } + + if ( x2 == e2 ) + { + e2 = TRUNC( e2 ); + + if ( e2 >= 0 && e2 <= ras.bTop ) + { + Int f1; + PByte bits; + + + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); + + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e2 )); + + bits[0] |= f1; + } + } + + FT_TRACE7(( "\n" )); + } + + + static void + Horizontal_Sweep_Drop( RAS_ARGS Int y, + FT_F26Dot6 x1, + FT_F26Dot6 x2 ) + { + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); + PByte bits; + Int f1; + + + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bTop ) + e1 = e2; + + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bTop ) + { + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); + + if ( *bits & f1 ) + return; + } + + if ( e1 >= 0 && e1 <= ras.bTop ) + { + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); + + FT_TRACE7(( " x=%d y=%d%s\n", y, e1, + *bits & f1 ? " redundant" : "" )); + + *bits |= f1; + } + } + + + static void + Horizontal_Sweep_Step( RAS_ARG ) + { + /* Nothing, really */ + FT_UNUSED_RASTER; + } + + + /************************************************************************** + * + * Generic Sweep Drawing routine + * + * Note that this routine is executed with the pool containing at least + * two valid profiles (up and down) and two y-turns (top and bottom). + * + */ + + static void + Draw_Sweep( RAS_ARG ) + { + Int min_Y, max_Y, dropouts; + Int y, y_turn; + + PProfile *Q, P, P_Left, P_Right; + + TProfileList waiting = ras.fProfile; + TProfileList draw_left = NULL; + TProfileList draw_right = NULL; + + + /* use y_turns to set the drawing range */ + + min_Y = (Int)ras.maxBuff[0]; + max_Y = (Int)ras.maxBuff[ras.numTurns] - 1; + + /* now initialize the sweep */ + + ras.Proc_Sweep_Init( RAS_VARS min_Y, max_Y ); + + /* let's go */ + + for ( y = min_Y; y <= max_Y; ) + { + /* check waiting list for new profile activations */ + + Q = &waiting; + while ( *Q ) + { + P = *Q; + if ( P->start == y ) + { + *Q = P->link; /* remove */ + + /* each active list contains profiles with the same flow */ + /* left and right are arbitrary, correspond to TrueType */ + if ( P->flags & Flow_Up ) + InsNew( &draw_left, P ); + else + InsNew( &draw_right, P ); + } + else + Q = &P->link; + } + + y_turn = (Int)*++ras.maxBuff; + + do + { + /* let's trace */ + + dropouts = 0; + + P_Left = draw_left; + P_Right = draw_right; + + while ( P_Left && P_Right ) + { + Long x1 = P_Left ->X; + Long x2 = P_Right->X; + Long xs; + + + /* TrueType should have x2 > x1, but can be opposite */ + /* by mistake or in CFF/Type1, fix it then */ + if ( x1 > x2 ) + { + xs = x1; + x1 = x2; + x2 = xs; + } + + if ( CEILING( x1 ) <= FLOOR( x2 ) ) + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2 ); + + /* otherwise, bottom ceiling > top floor, it is a drop-out */ + else + { + Int dropOutControl = P_Left->flags & 7; + + + /* Drop-out control */ + + /* e2 x2 x1 e1 */ + /* */ + /* ^ | */ + /* | | */ + /* +-------------+---------------------+------------+ */ + /* | | */ + /* | v */ + /* */ + /* pixel contour contour pixel */ + /* center center */ + + /* drop-out mode scan conversion rules (OpenType specs) */ + /* ------------------------------------------------------- */ + /* bit 0 exclude stubs if set */ + /* bit 1 ignore drop-outs if set */ + /* bit 2 smart rounding if set */ + + if ( dropOutControl & 2 ) + goto Next_Pair; + + /* The specification neither provides an exact definition */ + /* of a `stub' nor gives exact rules to exclude them. */ + /* */ + /* Here the constraints we use to recognize a stub. */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + /* We draw a stub if the following constraints are met. */ + /* */ + /* - for an upper or lower stub, there is top or bottom */ + /* overshoot, respectively */ + /* - the covered interval is greater or equal to a half */ + /* pixel */ + + if ( dropOutControl & 1 ) + { + /* upper stub test */ + if ( P_Left->height == 1 && + P_Left->next == P_Right && + !( P_Left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; + + /* lower stub test */ + if ( P_Left->offset == 0 && + P_Right->next == P_Left && + !( P_Left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; + } + + /* select the pixel to set and the other pixel */ + if ( dropOutControl & 4 ) + { + x2 = SMART( x1, x2 ); + x1 = x1 > x2 ? x2 + ras.precision : x2 - ras.precision; + } + else + { + x2 = FLOOR ( x2 ); + x1 = CEILING( x1 ); + } + + P_Left ->X = x2; + P_Right->X = x1; + + /* mark profile for drop-out processing */ + P_Left->flags |= Dropout; + dropouts++; + } + + Next_Pair: + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + /* handle drop-outs _after_ the span drawing */ + P_Left = draw_left; + P_Right = draw_right; + + while ( dropouts ) + { + if ( P_Left->flags & Dropout ) + { + ras.Proc_Sweep_Drop( RAS_VARS y, P_Left->X, P_Right->X ); + + P_Left->flags &= ~Dropout; + dropouts--; + } + + P_Left = P_Left->link; + P_Right = P_Right->link; + } + + ras.Proc_Sweep_Step( RAS_VAR ); + + Increment( &draw_left, 1 ); + Increment( &draw_right, -1 ); + } + while ( ++y < y_turn ); + } + } + + + /************************************************************************** + * + * @Function: + * Render_Single_Pass + * + * @Description: + * Perform one sweep with sub-banding. + * + * @Input: + * flipped :: + * If set, flip the direction of the outline. + * + * @Return: + * Renderer error code. + */ + static int + Render_Single_Pass( RAS_ARGS Bool flipped, + Int y_min, + Int y_max ) + { + Int y_mid; + Int band_top = 0; + Int band_stack[32]; /* enough to bisect 32-bit int bands */ + + + FT_TRACE6(( "%s pass [%d..%d]\n", + flipped ? "Horizontal" : "Vertical", + y_min, y_max )); + + while ( 1 ) + { + ras.minY = (Long)y_min * ras.precision; + ras.maxY = (Long)y_max * ras.precision; + + ras.error = Raster_Err_Ok; + + if ( Convert_Glyph( RAS_VARS flipped ) ) + { + if ( ras.error != Raster_Err_Raster_Overflow ) + return ras.error; + + /* sub-banding */ + + if ( y_min == y_max ) + return ras.error; /* still Raster_Overflow */ + + FT_TRACE6(( "band [%d..%d]: to be bisected\n", + y_min, y_max )); + + y_mid = ( y_min + y_max ) >> 1; + + band_stack[band_top++] = y_min; + y_min = y_mid + 1; + } + else + { + FT_TRACE6(( "band [%d..%d]: %hd profiles; %td bytes remaining\n", + y_min, y_max, ras.num_Profs, + (char*)ras.maxBuff - (char*)ras.top )); + + if ( ras.fProfile ) + Draw_Sweep( RAS_VAR ); + + if ( --band_top < 0 ) + break; + + y_max = y_min - 1; + y_min = band_stack[band_top]; + } + } + + return Raster_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * Render_Glyph + * + * @Description: + * Render a glyph in a bitmap. Sub-banding if needed. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + Render_Glyph( RAS_ARG ) + { + FT_Error error; + Long buffer[FT_MAX_BLACK_POOL]; + + + ras.buff = buffer; + ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + + ras.dropOutControl = 0; + + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) + ras.dropOutControl |= 2; + + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl |= 4; + + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl |= 1; + + FT_TRACE6(( "BW Raster: precision 1/%d, dropout mode %d\n", + ras.precision, ras.dropOutControl )); + + /* Vertical Sweep */ + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 0, 0, ras.bTop ); + if ( error ) + return error; + + /* Horizontal Sweep */ + if ( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + + error = Render_Single_Pass( RAS_VARS 1, 0, ras.bRight ); + if ( error ) + return error; + } + + return Raster_Err_Ok; + } + + + /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ + /**** a static object. *****/ + + +#ifdef STANDALONE_ + + + static int + ft_black_new( void* memory, + FT_Raster *araster ) + { + static black_TRaster the_raster; + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + FT_ZERO( &the_raster ); + + return 0; + } + + + static void + ft_black_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + + +#else /* !STANDALONE_ */ + + + static int + ft_black_new( void* memory_, /* FT_Memory */ + FT_Raster *araster_ ) /* black_PRaster */ + { + FT_Memory memory = (FT_Memory)memory_; + black_PRaster *araster = (black_PRaster*)araster_; + + FT_Error error; + black_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + ft_black_done( FT_Raster raster_ ) /* black_PRaster */ + { + black_PRaster raster = (black_PRaster)raster_; + FT_Memory memory = (FT_Memory)raster->memory; + + + FT_FREE( raster ); + } + + +#endif /* !STANDALONE_ */ + + + static void + ft_black_reset( FT_Raster raster, + PByte pool_base, + ULong pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static int + ft_black_set_mode( FT_Raster raster, + ULong mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return 0; + } + + + static int + ft_black_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + +#ifndef FT_STATIC_RASTER + black_TWorker worker[1]; +#endif + + + if ( !raster ) + return FT_THROW( Raster_Uninitialized ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return Raster_Err_Ok; + + if ( !outline->contours || !outline->points ) + return FT_THROW( Invalid_Outline ); + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return FT_THROW( Invalid_Outline ); + + /* this version of the raster does not support direct rendering, sorry */ + if ( params->flags & FT_RASTER_FLAG_DIRECT || + params->flags & FT_RASTER_FLAG_AA ) + return FT_THROW( Cannot_Render_Glyph ); + + if ( !target_map ) + return FT_THROW( Invalid_Argument ); + + /* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return Raster_Err_Ok; + + if ( !target_map->buffer ) + return FT_THROW( Invalid_Argument ); + + ras.outline = *outline; + + ras.bTop = (Int)target_map->rows - 1; + ras.bRight = (Int)target_map->width - 1; + ras.bPitch = (Int)target_map->pitch; + ras.bOrigin = (PByte)target_map->buffer; + + if ( ras.bPitch > 0 ) + ras.bOrigin += ras.bTop * ras.bPitch; + + return Render_Glyph( RAS_VAR ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_standard_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + ft_black_new, /* FT_Raster_New_Func raster_new */ + ft_black_reset, /* FT_Raster_Reset_Func raster_reset */ + ft_black_set_mode, /* FT_Raster_Set_Mode_Func raster_set_mode */ + ft_black_render, /* FT_Raster_Render_Func raster_render */ + ft_black_done /* FT_Raster_Done_Func raster_done */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/ftraster.h b/Dependencies/freetype/freetype/src/raster/ftraster.h new file mode 100644 index 00000000..ad9cb1b9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/ftraster.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * ftraster.h + * + * The FreeType glyph rasterizer (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTRASTER_H_ +#define FTRASTER_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + +#include + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Uncomment the following line if you are using ftraster.c as a + * standalone module, fully independent of FreeType. + */ +/* #define STANDALONE_ */ + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster; + + +FT_END_HEADER + +#endif /* FTRASTER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/ftrend1.c b/Dependencies/freetype/freetype/src/raster/ftrend1.c new file mode 100644 index 00000000..fd9f174f --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/ftrend1.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * + * ftrend1.c + * + * The FreeType glyph rasterizer interface (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftrend1.h" +#include "ftraster.h" + +#include "rasterrs.h" + + + /* initialize renderer -- init its raster */ + static FT_Error + ft_raster1_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return FT_Err_Ok; + } + + + /* set render-specific mode */ + static FT_Error + ft_raster1_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + /* transform a given glyph image */ + static FT_Error + ft_raster1_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_raster1_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_raster1_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = render->root.memory; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + FT_Raster_Params params; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check rendering mode */ + if ( mode != FT_RENDER_MODE_MONO ) + { + /* raster1 is only capable of producing monochrome bitmaps */ + return FT_THROW( Cannot_Render_Glyph ); + } + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + /* allocate new one */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + x_shift = -slot->bitmap_left * 64; + y_shift = ( (FT_Int)bitmap->rows - slot->bitmap_top ) * 64; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + /* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_DEFAULT; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + Exit: + if ( !error ) + /* everything is fine; the glyph is now officially a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_raster1_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + + "raster1", + 0x10000L, + 0x20000L, + + NULL, /* module specific interface */ + + ft_raster1_init, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + NULL, /* FT_Module_Requester get_interface */ + + FT_GLYPH_FORMAT_OUTLINE, + + ft_raster1_render, /* FT_Renderer_RenderFunc render_glyph */ + ft_raster1_transform, /* FT_Renderer_TransformFunc transform_glyph */ + ft_raster1_get_cbox, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + ft_raster1_set_mode, /* FT_Renderer_SetModeFunc set_mode */ + + &ft_standard_raster /* FT_Raster_Funcs* raster_class */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/ftrend1.h b/Dependencies/freetype/freetype/src/raster/ftrend1.h new file mode 100644 index 00000000..cf3e73c0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/ftrend1.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftrend1.h + * + * The FreeType glyph rasterizer interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTREND1_H_ +#define FTREND1_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_RENDERER( ft_raster1_renderer_class ) + + +FT_END_HEADER + +#endif /* FTREND1_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/raster.c b/Dependencies/freetype/freetype/src/raster/raster.c new file mode 100644 index 00000000..fe33af24 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/raster.c @@ -0,0 +1,25 @@ +/**************************************************************************** + * + * raster.c + * + * FreeType monochrome rasterer module component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftraster.c" +#include "ftrend1.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/raster/rasterrs.h b/Dependencies/freetype/freetype/src/raster/rasterrs.h new file mode 100644 index 00000000..326d42e0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/raster/rasterrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * rasterrs.h + * + * monochrome renderer error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the monochrome renderer error enumeration + * constants. + * + */ + +#ifndef RASTERRS_H_ +#define RASTERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Raster_Err_ +#define FT_ERR_BASE FT_Mod_Err_Raster + +#include + +#endif /* RASTERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftbsdf.c b/Dependencies/freetype/freetype/src/sdf/ftbsdf.c new file mode 100644 index 00000000..adde05ba --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftbsdf.c @@ -0,0 +1,1350 @@ +/**************************************************************************** + * + * ftbsdf.c + * + * Signed Distance Field support for bitmap fonts (body only). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "ftsdf.h" +#include "ftsdferrs.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * A brief technical overview of how the BSDF rasterizer works + * ----------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * BSDF stands for Bitmap to Signed Distance Field rasterizer. + * + * * This renderer converts rasterized bitmaps to SDF. There is another + * renderer called 'sdf', which generates SDF directly from outlines; + * see file `ftsdf.c` for more. + * + * * The idea of generating SDF from bitmaps is taken from two research + * papers, where one is dependent on the other: + * + * - Per-Erik Danielsson: Euclidean Distance Mapping + * http://webstaff.itn.liu.se/~stegu/JFA/Danielsson.pdf + * + * From this paper we use the eight-point sequential Euclidean + * distance mapping (8SED). This is the heart of the process used + * in this rasterizer. + * + * - Stefan Gustavson, Robin Strand: Anti-aliased Euclidean distance transform. + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * + * The original 8SED algorithm discards the pixels' alpha values, + * which can contain information about the actual outline of the + * glyph. This paper takes advantage of those alpha values and + * approximates outline pretty accurately. + * + * * This rasterizer also works for monochrome bitmaps. However, the + * result is not as accurate since we don't have any way to + * approximate outlines from binary bitmaps. + * + * ======================================================================== + * + * Generating SDF from bitmap is done in several steps. + * + * (1) The only information we have is the bitmap itself. It can + * be monochrome or anti-aliased. If it is anti-aliased, pixel values + * are nothing but coverage values. These coverage values can be used + * to extract information about the outline of the image. For + * example, if the pixel's alpha value is 0.5, then we can safely + * assume that the outline passes through the center of the pixel. + * + * (2) Find edge pixels in the bitmap (see `bsdf_is_edge` for more). For + * all edge pixels we use the Anti-aliased Euclidean distance + * transform algorithm and compute approximate edge distances (see + * `compute_edge_distance` and/or the second paper for more). + * + * (3) Now that we have computed approximate distances for edge pixels we + * use the 8SED algorithm to basically sweep the entire bitmap and + * compute distances for the rest of the pixels. (Since the algorithm + * is pretty convoluted it is only explained briefly in a comment to + * function `edt8`. To see the actual algorithm refer to the first + * paper.) + * + * (4) Finally, compute the sign for each pixel. This is done in function + * `finalize_sdf`. The basic idea is that if a pixel's original + * alpha/coverage value is greater than 0.5 then it is 'inside' (and + * 'outside' otherwise). + * + * Pseudo Code: + * + * ``` + * b = source bitmap; + * t = target bitmap; + * dm = list of distances; // dimension equal to b + * + * foreach grid_point (x, y) in b: + * { + * if (is_edge(x, y)): + * dm = approximate_edge_distance(b, x, y); + * + * // do the 8SED on the distances + * edt8(dm); + * + * // determine the signs + * determine_signs(dm): + * + * // copy SDF data to the target bitmap + * copy(dm to t); + * } + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT bsdf + + + /************************************************************************** + * + * useful macros + * + */ + +#define ONE 65536 /* 1 in 16.16 */ + + + /************************************************************************** + * + * structs + * + */ + + + /************************************************************************** + * + * @Struct: + * BSDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing this is passed + * to the @FT_Raster_RenderFunc function, which then can be used however + * we want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct BSDF_TRaster_ + { + FT_Memory memory; + + } BSDF_TRaster, *BSDF_PRaster; + + + /************************************************************************** + * + * @Struct: + * ED + * + * @Description: + * Euclidean distance. It gets used for Euclidean distance transforms; + * it can also be interpreted as an edge distance. + * + * @Fields: + * dist :: + * Vector length of the `prox` parameter. Can be squared or absolute + * depending on the `USE_SQUARED_DISTANCES` macro defined in file + * `ftsdfcommon.h`. + * + * prox :: + * Vector to the nearest edge. Can also be interpreted as shortest + * distance of a point. + * + * alpha :: + * Alpha value of the original bitmap from which we generate SDF. + * Needed for computing the gradient and determining the proper sign + * of a pixel. + * + */ + typedef struct ED_ + { + FT_16D16 dist; + FT_16D16_Vec prox; + FT_Byte alpha; + + } ED; + + + /************************************************************************** + * + * @Struct: + * BSDF_Worker + * + * @Description: + * A convenience struct that is passed to functions while generating + * SDF; most of those functions require the same parameters. + * + * @Fields: + * distance_map :: + * A one-dimensional array that gets interpreted as two-dimensional + * one. It contains the Euclidean distances of all points of the + * bitmap. + * + * width :: + * Width of the above `distance_map`. + * + * rows :: + * Number of rows in the above `distance_map`. + * + * params :: + * Internal parameters and properties required by the rasterizer. See + * file `ftsdf.h` for more. + * + */ + typedef struct BSDF_Worker_ + { + ED* distance_map; + + FT_Int width; + FT_Int rows; + + SDF_Raster_Params params; + + } BSDF_Worker; + + + /************************************************************************** + * + * initializer + * + */ + + static const ED zero_ed = { 0, { 0, 0 }, 0 }; + + + /************************************************************************** + * + * rasterizer functions + * + */ + + /************************************************************************** + * + * @Function: + * bsdf_is_edge + * + * @Description: + * Check whether a pixel is an edge pixel, i.e., whether it is + * surrounded by a completely black pixel (zero alpha), and the current + * pixel is not a completely black pixel. + * + * @Input: + * dm :: + * Array of distances. The parameter must point to the current + * pixel, i.e., the pixel that is to be checked for being an edge. + * + * x :: + * The x position of the current pixel. + * + * y :: + * The y position of the current pixel. + * + * w :: + * Width of the bitmap. + * + * r :: + * Number of rows in the bitmap. + * + * @Return: + * 1~if the current pixel is an edge pixel, 0~otherwise. + * + */ + +#ifdef CHECK_NEIGHBOR +#undef CHECK_NEIGHBOR +#endif + +#define CHECK_NEIGHBOR( x_offset, y_offset ) \ + do \ + { \ + if ( x + x_offset >= 0 && x + x_offset < w && \ + y + y_offset >= 0 && y + y_offset < r ) \ + { \ + num_neighbors++; \ + \ + to_check = dm + y_offset * w + x_offset; \ + if ( to_check->alpha == 0 ) \ + { \ + is_edge = 1; \ + goto Done; \ + } \ + } \ + } while ( 0 ) + + static FT_Bool + bsdf_is_edge( ED* dm, /* distance map */ + FT_Int x, /* x index of point to check */ + FT_Int y, /* y index of point to check */ + FT_Int w, /* width */ + FT_Int r ) /* rows */ + { + FT_Bool is_edge = 0; + ED* to_check = NULL; + FT_Int num_neighbors = 0; + + + if ( dm->alpha == 0 ) + goto Done; + + if ( dm->alpha > 0 && dm->alpha < 255 ) + { + is_edge = 1; + goto Done; + } + + /* up */ + CHECK_NEIGHBOR( 0, -1 ); + + /* down */ + CHECK_NEIGHBOR( 0, 1 ); + + /* left */ + CHECK_NEIGHBOR( -1, 0 ); + + /* right */ + CHECK_NEIGHBOR( 1, 0 ); + + /* up left */ + CHECK_NEIGHBOR( -1, -1 ); + + /* up right */ + CHECK_NEIGHBOR( 1, -1 ); + + /* down left */ + CHECK_NEIGHBOR( -1, 1 ); + + /* down right */ + CHECK_NEIGHBOR( 1, 1 ); + + if ( num_neighbors != 8 ) + is_edge = 1; + + Done: + return is_edge; + } + +#undef CHECK_NEIGHBOR + + + /************************************************************************** + * + * @Function: + * compute_edge_distance + * + * @Description: + * Approximate the outline and compute the distance from `current` + * to the approximated outline. + * + * @Input: + * current :: + * Array of Euclidean distances. `current` must point to the position + * for which the distance is to be caculated. We treat this array as + * a two-dimensional array mapped to a one-dimensional array. + * + * x :: + * The x coordinate of the `current` parameter in the array. + * + * y :: + * The y coordinate of the `current` parameter in the array. + * + * w :: + * The width of the distances array. + * + * r :: + * Number of rows in the distances array. + * + * @Return: + * A vector pointing to the approximate edge distance. + * + * @Note: + * This is a computationally expensive function. Try to reduce the + * number of calls to this function. Moreover, this must only be used + * for edge pixel positions. + * + */ + static FT_16D16_Vec + compute_edge_distance( ED* current, + FT_Int x, + FT_Int y, + FT_Int w, + FT_Int r ) + { + /* + * This function, based on the paper presented by Stefan Gustavson and + * Robin Strand, gets used to approximate edge distances from + * anti-aliased bitmaps. + * + * The algorithm is as follows. + * + * (1) In anti-aliased images, the pixel's alpha value is the coverage + * of the pixel by the outline. For example, if the alpha value is + * 0.5f we can assume that the outline passes through the center of + * the pixel. + * + * (2) For this reason we can use that alpha value to approximate the real + * distance of the pixel to edge pretty accurately. A simple + * approximation is `(0.5f - alpha)`, assuming that the outline is + * parallel to the x or y~axis. However, in this algorithm we use a + * different approximation which is quite accurate even for + * non-axis-aligned edges. + * + * (3) The only remaining piece of information that we cannot + * approximate directly from the alpha is the direction of the edge. + * This is where we use Sobel's operator to compute the gradient of + * the pixel. The gradient give us a pretty good approximation of + * the edge direction. We use a 3x3 kernel filter to compute the + * gradient. + * + * (4) After the above two steps we have both the direction and the + * distance to the edge which is used to generate the Signed + * Distance Field. + * + * References: + * + * - Anti-Aliased Euclidean Distance Transform: + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * - Sobel Operator: + * https://en.wikipedia.org/wiki/Sobel_operator + */ + + FT_16D16_Vec g = { 0, 0 }; + FT_16D16 dist, current_alpha; + FT_16D16 a1, temp; + FT_16D16 gx, gy; + FT_16D16 alphas[9]; + + + /* Since our spread cannot be 0, this condition */ + /* can never be true. */ + if ( x <= 0 || x >= w - 1 || + y <= 0 || y >= r - 1 ) + return g; + + /* initialize the alphas */ + alphas[0] = 256 * (FT_16D16)current[-w - 1].alpha; + alphas[1] = 256 * (FT_16D16)current[-w ].alpha; + alphas[2] = 256 * (FT_16D16)current[-w + 1].alpha; + alphas[3] = 256 * (FT_16D16)current[ -1].alpha; + alphas[4] = 256 * (FT_16D16)current[ 0].alpha; + alphas[5] = 256 * (FT_16D16)current[ 1].alpha; + alphas[6] = 256 * (FT_16D16)current[ w - 1].alpha; + alphas[7] = 256 * (FT_16D16)current[ w ].alpha; + alphas[8] = 256 * (FT_16D16)current[ w + 1].alpha; + + current_alpha = alphas[4]; + + /* Compute the gradient using the Sobel operator. */ + /* In this case we use the following 3x3 filters: */ + /* */ + /* For x: | -1 0 -1 | */ + /* | -root(2) 0 root(2) | */ + /* | -1 0 1 | */ + /* */ + /* For y: | -1 -root(2) -1 | */ + /* | 0 0 0 | */ + /* | 1 root(2) 1 | */ + /* */ + /* [Note]: 92681 is root(2) in 16.16 format. */ + g.x = -alphas[0] - + FT_MulFix( alphas[3], 92681 ) - + alphas[6] + + alphas[2] + + FT_MulFix( alphas[5], 92681 ) + + alphas[8]; + + g.y = -alphas[0] - + FT_MulFix( alphas[1], 92681 ) - + alphas[2] + + alphas[6] + + FT_MulFix( alphas[7], 92681 ) + + alphas[8]; + + FT_Vector_NormLen( &g ); + + /* The gradient gives us the direction of the */ + /* edge for the current pixel. Once we have the */ + /* approximate direction of the edge, we can */ + /* approximate the edge distance much better. */ + + if ( g.x == 0 || g.y == 0 ) + dist = ONE / 2 - alphas[4]; + else + { + gx = g.x; + gy = g.y; + + gx = FT_ABS( gx ); + gy = FT_ABS( gy ); + + if ( gx < gy ) + { + temp = gx; + gx = gy; + gy = temp; + } + + a1 = FT_DivFix( gy, gx ) / 2; + + if ( current_alpha < a1 ) + dist = ( gx + gy ) / 2 - + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + current_alpha ) ) ); + + else if ( current_alpha < ( ONE - a1 ) ) + dist = FT_MulFix( ONE / 2 - current_alpha, gx ); + + else + dist = -( gx + gy ) / 2 + + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + ONE - current_alpha ) ) ); + } + + g.x = FT_MulFix( g.x, dist ); + g.y = FT_MulFix( g.y, dist ); + + return g; + } + + + /************************************************************************** + * + * @Function: + * bsdf_approximate_edge + * + * @Description: + * Loops over all the pixels and call `compute_edge_distance` only for + * edge pixels. This maked the process a lot faster since + * `compute_edge_distance` uses functions such as `FT_Vector_NormLen', + * which are quite slow. + * + * @InOut: + * worker :: + * Contains the distance map as well as all the relevant parameters + * required by the function. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function directly manipulates `worker->distance_map`. + * + */ + static FT_Error + bsdf_approximate_edge( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + FT_Int i, j; + FT_Int index; + ED* ed; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + ed = worker->distance_map; + + for ( j = 0; j < worker->rows; j++ ) + { + for ( i = 0; i < worker->width; i++ ) + { + index = j * worker->width + i; + + if ( bsdf_is_edge( worker->distance_map + index, + i, j, + worker->width, + worker->rows ) ) + { + /* approximate the edge distance for edge pixels */ + ed[index].prox = compute_edge_distance( ed + index, + i, j, + worker->width, + worker->rows ); + ed[index].dist = VECTOR_LENGTH_16D16( ed[index].prox ); + } + else + { + /* for non-edge pixels assign far away distances */ + ed[index].dist = 400 * ONE; + ed[index].prox.x = 200 * ONE; + ed[index].prox.y = 200 * ONE; + } + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * bsdf_init_distance_map + * + * @Description: + * Initialize the distance map according to the '8-point sequential + * Euclidean distance mapping' (8SED) algorithm. Basically it copies + * the `source` bitmap alpha values to the `distance_map->alpha` + * parameter of `worker`. + * + * @Input: + * source :: + * Source bitmap to copy the data from. + * + * @Output: + * worker :: + * Target distance map to copy the data to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + bsdf_init_distance_map( const FT_Bitmap* source, + BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + FT_Int x_diff, y_diff; + FT_Int t_i, t_j, s_i, s_j; + FT_Byte* s; + ED* t; + + + /* again check the parameters (probably unnecessary) */ + if ( !source || !worker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Because of the way we convert a bitmap to SDF, */ + /* i.e., aligning the source to the center of the */ + /* target, the target's width and rows must be */ + /* checked before copying. */ + if ( worker->width < (FT_Int)source->width || + worker->rows < (FT_Int)source->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check pixel mode */ + if ( source->pixel_mode == FT_PIXEL_MODE_NONE ) + { + FT_ERROR(( "bsdf_copy_source_to_target:" + " Invalid pixel mode of source bitmap" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( source->pixel_mode == FT_PIXEL_MODE_MONO ) + { + FT_TRACE0(( "bsdf_copy_source_to_target:" + " The `bsdf' renderer can convert monochrome\n" )); + FT_TRACE0(( " " + " bitmaps to SDF but the results are not perfect\n" )); + FT_TRACE0(( " " + " because there is no way to approximate actual\n" )); + FT_TRACE0(( " " + " outlines from monochrome bitmaps. Consider\n" )); + FT_TRACE0(( " " + " using an anti-aliased bitmap instead.\n" )); + } +#endif + + /* Calculate the width and row differences */ + /* between target and source. */ + x_diff = worker->width - (int)source->width; + y_diff = worker->rows - (int)source->rows; + + x_diff /= 2; + y_diff /= 2; + + t = (ED*)worker->distance_map; + s = source->buffer; + + /* For now we only support pixel mode `FT_PIXEL_MODE_MONO` */ + /* and `FT_PIXEL_MODE_GRAY`. More will be added later. */ + /* */ + /* [NOTE]: We can also use @FT_Bitmap_Convert to convert */ + /* bitmap to 8bpp. To avoid extra allocation and */ + /* since the target bitmap can be 16bpp we manually */ + /* convert the source bitmap to the desired bpp. */ + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + FT_Int div, mod; + FT_Byte pixel, byte; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * source->pitch; + else + s_index = s_j * source->pitch; + + div = s_index + s_i / 8; + mod = 7 - s_i % 8; + + pixel = s[div]; + byte = (FT_Byte)( 1 << mod ); + + t[t_index].alpha = pixel & byte ? 255 : 0; + } + } + } + break; + + case FT_PIXEL_MODE_GRAY: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + /* loop over all pixels and assign pixel values from source */ + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * s_width + s_i; + else + s_index = s_j * s_width + s_i; + + /* simply copy the alpha values */ + t[t_index].alpha = s[s_index]; + } + } + } + break; + + default: + FT_ERROR(( "bsdf_copy_source_to_target:" + " unsopported pixel mode of source bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + break; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * compare_neighbor + * + * @Description: + * Compare neighbor pixel (which is defined by the offset) and update + * `current` distance if the new distance is shorter than the original. + * + * @Input: + * x_offset :: + * X offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * y_offset :: + * Y offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * width :: + * Width of the `current` array. + * + * @InOut: + * current :: + * Pointer into array of distances. This parameter must point to the + * position whose neighbor is to be checked. The array is treated as + * a two-dimensional array. + * + */ + static void + compare_neighbor( ED* current, + FT_Int x_offset, + FT_Int y_offset, + FT_Int width ) + { + ED* to_check; + FT_16D16 dist; + FT_16D16_Vec dist_vec; + + + to_check = current + ( y_offset * width ) + x_offset; + + /* + * While checking for the nearest point we first approximate the + * distance of `current` by adding the deviation (which is sqrt(2) at + * most). Only if the new value is less than the current value we + * calculate the actual distances using `FT_Vector_Length`. This last + * step can be omitted by using squared distances. + */ + + /* + * Approximate the distance. We subtract 1 to avoid precision errors, + * which could happen because the two directions can be opposite. + */ + dist = to_check->dist - ONE; + + if ( dist < current->dist ) + { + dist_vec = to_check->prox; + + dist_vec.x += x_offset * ONE; + dist_vec.y += y_offset * ONE; + dist = VECTOR_LENGTH_16D16( dist_vec ); + + if ( dist < current->dist ) + { + current->dist = dist; + current->prox = dist_vec; + } + } + } + + + /************************************************************************** + * + * @Function: + * first_pass + * + * @Description: + * First pass of the 8SED algorithm. Loop over the bitmap from top to + * bottom and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + first_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from top to bottom and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the first row as it has no top */ + /* neighbor; it will be covered in the second scan of */ + /* the image (from bottom to top). */ + for ( j = 1; j < r; j++ ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, -1, w ); + /* up */ + compare_neighbor( current, 0, -1, w ); + /* up-right */ + compare_neighbor( current, 1, -1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * second_pass + * + * @Description: + * Second pass of the 8SED algorithm. Loop over the bitmap from bottom + * to top and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + second_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from bottom to top and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the last row as it has no down */ + /* neighbor; it is already covered in the first scan */ + /* of the image (from top to bottom). */ + for ( j = r - 2; j >= 0; j-- ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, 1, w ); + /* up */ + compare_neighbor( current, 0, 1, w ); + /* up-right */ + compare_neighbor( current, 1, 1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * edt8 + * + * @Description: + * Compute the distance map of the a bitmap. Execute both first and + * second pass of the 8SED algorithm. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + edt8( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* first scan of the image */ + first_pass( worker ); + + /* second scan of the image */ + second_pass( worker ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * finalize_sdf + * + * @Description: + * Copy the SDF data from `worker->distance_map` to the `target` bitmap. + * Also transform the data to output format, (which is 6.10 fixed-point + * format at the moment). + * + * @Input: + * worker :: + * Contains source distance map and other SDF data. + * + * @Output: + * target :: + * Target bitmap to which the SDF data is copied to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + finalize_sdf( BSDF_Worker* worker, + const FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + + FT_Int w, r; + FT_Int i, j; + + FT_SDFFormat* t_buffer; + FT_16D16 sp_sq, spread; + + + if ( !worker || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + w = (int)target->width; + r = (int)target->rows; + t_buffer = (FT_SDFFormat*)target->buffer; + + if ( w != worker->width || + r != worker->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + spread = (FT_16D16)FT_INT_16D16( worker->params.spread ); + +#if USE_SQUARED_DISTANCES + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread * + worker->params.spread ); +#else + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread ); +#endif + + for ( j = 0; j < r; j++ ) + { + for ( i = 0; i < w; i++ ) + { + FT_Int index; + FT_16D16 dist; + FT_SDFFormat final_dist; + FT_Char sign; + + + index = j * w + i; + dist = worker->distance_map[index].dist; + + if ( dist < 0 || dist > sp_sq ) + dist = sp_sq; + +#if USE_SQUARED_DISTANCES + dist = square_root( dist ); +#endif + + /* We assume that if the pixel is inside a contour */ + /* its coverage value must be > 127. */ + sign = worker->distance_map[index].alpha < 127 ? -1 : 1; + + /* flip the sign according to the property */ + if ( worker->params.flip_sign ) + sign = -sign; + + /* concatenate from 16.16 to appropriate format */ + final_dist = map_fixed_to_sdf( dist * sign, spread ); + + t_buffer[index] = final_dist; + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + /* called when adding a new module through @FT_Add_Module */ + static FT_Error + bsdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* BSDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + BSDF_PRaster* araster = (BSDF_PRaster*)araster_; + + FT_Error error; + BSDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + /* unused */ + static void + bsdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + /* unused */ + static FT_Error + bsdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + /* called while rendering through @FT_Render_Glyph */ + static FT_Error + bsdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + const FT_Bitmap* source = NULL; + const FT_Bitmap* target = NULL; + + BSDF_TRaster* bsdf_raster = (BSDF_TRaster*)raster; + BSDF_Worker worker; + + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + + worker.distance_map = NULL; + + /* check for valid parameters */ + if ( !raster || !params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check whether the flag is set */ + if ( sdf_params->root.flags != FT_RASTER_FLAG_SDF ) + { + error = FT_THROW( Raster_Corrupted ); + goto Exit; + } + + source = (const FT_Bitmap*)sdf_params->root.source; + target = (const FT_Bitmap*)sdf_params->root.target; + + /* check source and target bitmap */ + if ( !source || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = bsdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "bsdf_raster_render: Raster not set up properly,\n" )); + FT_TRACE0(( " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "bsdf_raster_render:" + " The `spread' field of `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " is invalid; the value of this field must be\n" )); + FT_TRACE0(( " " + " within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " instead of the default `FT_Raster_Params'\n" )); + FT_TRACE0(( " " + " while calling this function and set the fields\n" )); + FT_TRACE0(( " " + " accordingly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* set up the worker */ + + /* allocate the distance map */ + if ( FT_QALLOC_MULT( worker.distance_map, target->rows, + target->width * sizeof ( *worker.distance_map ) ) ) + goto Exit; + + worker.width = (int)target->width; + worker.rows = (int)target->rows; + worker.params = *sdf_params; + + FT_CALL( bsdf_init_distance_map( source, &worker ) ); + FT_CALL( bsdf_approximate_edge( &worker ) ); + FT_CALL( edt8( &worker ) ); + FT_CALL( finalize_sdf( &worker, target ) ); + + FT_TRACE0(( "bsdf_raster_render: Total memory used = %ld\n", + worker.width * worker.rows * + (long)sizeof ( *worker.distance_map ) )); + + Exit: + if ( worker.distance_map ) + FT_FREE( worker.distance_map ); + + return error; + } + + + /* called while deleting `FT_Library` only if the module is added */ + static void + bsdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((BSDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_bitmap_sdf_raster, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Raster_New_Func) bsdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) bsdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)bsdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) bsdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) bsdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdf.c b/Dependencies/freetype/freetype/src/sdf/ftsdf.c new file mode 100644 index 00000000..dc55d426 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdf.c @@ -0,0 +1,3932 @@ +/**************************************************************************** + * + * ftsdf.c + * + * Signed Distance Field support for outline fonts (body). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include "ftsdf.h" + +#include "ftsdferrs.h" + + + /************************************************************************** + * + * A brief technical overview of how the SDF rasterizer works + * ---------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * This renderer generates SDF directly from outlines. There is + * another renderer called 'bsdf', which converts bitmaps to SDF; see + * file `ftbsdf.c` for more. + * + * * The basic idea of generating the SDF is taken from Viktor Chlumsky's + * research paper. The paper explains both single and multi-channel + * SDF, however, this implementation only generates single-channel SDF. + * + * Chlumsky, Viktor: Shape Decomposition for Multi-channel Distance + * Fields. Master's thesis. Czech Technical University in Prague, + * Faculty of InformationTechnology, 2015. + * + * For more information: https://github.com/Chlumsky/msdfgen + * + * ======================================================================== + * + * Generating SDF from outlines is pretty straightforward. + * + * (1) We have a set of contours that make the outline of a shape/glyph. + * Each contour comprises of several edges, with three types of edges. + * + * * line segments + * * conic Bezier curves + * * cubic Bezier curves + * + * (2) Apart from the outlines we also have a two-dimensional grid, namely + * the bitmap that is used to represent the final SDF data. + * + * (3) In order to generate SDF, our task is to find shortest signed + * distance from each grid point to the outline. The 'signed + * distance' means that if the grid point is filled by any contour + * then its sign is positive, otherwise it is negative. The pseudo + * code is as follows. + * + * ``` + * foreach grid_point (x, y): + * { + * int min_dist = INT_MAX; + * + * foreach contour in outline: + * { + * foreach edge in contour: + * { + * // get shortest distance from point (x, y) to the edge + * d = get_min_dist(x, y, edge); + * + * if (d < min_dist) + * min_dist = d; + * } + * + * bitmap[x, y] = min_dist; + * } + * } + * ``` + * + * (4) After running this algorithm the bitmap contains information about + * the shortest distance from each point to the outline of the shape. + * Of course, while this is the most straightforward way of generating + * SDF, we use various optimizations in our implementation. See the + * `sdf_generate_*' functions in this file for all details. + * + * The optimization currently used by default is subdivision; see + * function `sdf_generate_subdivision` for more. + * + * Also, to see how we compute the shortest distance from a point to + * each type of edge, check out the `get_min_distance_*' functions. + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sdf + + + /************************************************************************** + * + * definitions + * + */ + + /* + * If set to 1, the rasterizer uses Newton-Raphson's method for finding + * the shortest distance from a point to a conic curve. + * + * If set to 0, an analytical method gets used instead, which computes the + * roots of a cubic polynomial to find the shortest distance. However, + * the analytical method can currently underflow; we thus use Newton's + * method by default. + */ +#ifndef USE_NEWTON_FOR_CONIC +#define USE_NEWTON_FOR_CONIC 1 +#endif + + /* + * The number of intervals a Bezier curve gets sampled and checked to find + * the shortest distance. + */ +#define MAX_NEWTON_DIVISIONS 4 + + /* + * The number of steps of Newton's iterations in each interval of the + * Bezier curve. Basically, we run Newton's approximation + * + * x -= Q(t) / Q'(t) + * + * for each division to get the shortest distance. + */ +#define MAX_NEWTON_STEPS 4 + + /* + * The epsilon distance (in 16.16 fractional units) used for corner + * resolving. If the difference of two distances is less than this value + * they will be checked for a corner if they are ambiguous. + */ +#define CORNER_CHECK_EPSILON 32 + +#if 0 + /* + * Coarse grid dimension. Will probably be removed in the future because + * coarse grid optimization is the slowest algorithm. + */ +#define CG_DIMEN 8 +#endif + + + /************************************************************************** + * + * macros + * + */ + +#define MUL_26D6( a, b ) ( ( ( a ) * ( b ) ) / 64 ) +#define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) + \ + MUL_26D6( p.y, q.y ) ) + + + /************************************************************************** + * + * structures and enums + * + */ + + /************************************************************************** + * + * @Struct: + * SDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing it is passed to + * the @FT_Raster_RenderFunc function, which then can be used however we + * want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct SDF_TRaster_ + { + FT_Memory memory; + + } SDF_TRaster, *SDF_PRaster; + + + /************************************************************************** + * + * @Enum: + * SDF_Edge_Type + * + * @Description: + * Enumeration of all curve types present in fonts. + * + * @Fields: + * SDF_EDGE_UNDEFINED :: + * Undefined edge, simply used to initialize and detect errors. + * + * SDF_EDGE_LINE :: + * Line segment with start and end point. + * + * SDF_EDGE_CONIC :: + * A conic/quadratic Bezier curve with start, end, and one control + * point. + * + * SDF_EDGE_CUBIC :: + * A cubic Bezier curve with start, end, and two control points. + * + */ + typedef enum SDF_Edge_Type_ + { + SDF_EDGE_UNDEFINED = 0, + SDF_EDGE_LINE = 1, + SDF_EDGE_CONIC = 2, + SDF_EDGE_CUBIC = 3 + + } SDF_Edge_Type; + + + /************************************************************************** + * + * @Enum: + * SDF_Contour_Orientation + * + * @Description: + * Enumeration of all orientation values of a contour. We determine the + * orientation by calculating the area covered by a contour. Contrary + * to values returned by @FT_Outline_Get_Orientation, + * `SDF_Contour_Orientation` is independent of the fill rule, which can + * be different for different font formats. + * + * @Fields: + * SDF_ORIENTATION_NONE :: + * Undefined orientation, used for initialization and error detection. + * + * SDF_ORIENTATION_CW :: + * Clockwise orientation (positive area covered). + * + * SDF_ORIENTATION_CCW :: + * Counter-clockwise orientation (negative area covered). + * + * @Note: + * See @FT_Outline_Get_Orientation for more details. + * + */ + typedef enum SDF_Contour_Orientation_ + { + SDF_ORIENTATION_NONE = 0, + SDF_ORIENTATION_CW = 1, + SDF_ORIENTATION_CCW = 2 + + } SDF_Contour_Orientation; + + + /************************************************************************** + * + * @Struct: + * SDF_Edge + * + * @Description: + * Represent an edge of a contour. + * + * @Fields: + * start_pos :: + * Start position of an edge. Valid for all types of edges. + * + * end_pos :: + * Etart position of an edge. Valid for all types of edges. + * + * control_a :: + * A control point of the edge. Valid only for `SDF_EDGE_CONIC` + * and `SDF_EDGE_CUBIC`. + * + * control_b :: + * Another control point of the edge. Valid only for + * `SDF_EDGE_CONIC`. + * + * edge_type :: + * Type of the edge, see @SDF_Edge_Type for all possible edge types. + * + * next :: + * Used to create a singly linked list, which can be interpreted + * as a contour. + * + */ + typedef struct SDF_Edge_ + { + FT_26D6_Vec start_pos; + FT_26D6_Vec end_pos; + FT_26D6_Vec control_a; + FT_26D6_Vec control_b; + + SDF_Edge_Type edge_type; + + struct SDF_Edge_* next; + + } SDF_Edge; + + + /************************************************************************** + * + * @Struct: + * SDF_Contour + * + * @Description: + * Represent a complete contour, which contains a list of edges. + * + * @Fields: + * last_pos :: + * Contains the value of `end_pos' of the last edge in the list of + * edges. Useful while decomposing the outline with + * @FT_Outline_Decompose. + * + * edges :: + * Linked list of all the edges that make the contour. + * + * next :: + * Used to create a singly linked list, which can be interpreted as a + * complete shape or @FT_Outline. + * + */ + typedef struct SDF_Contour_ + { + FT_26D6_Vec last_pos; + SDF_Edge* edges; + + struct SDF_Contour_* next; + + } SDF_Contour; + + + /************************************************************************** + * + * @Struct: + * SDF_Shape + * + * @Description: + * Represent a complete shape, which is the decomposition of + * @FT_Outline. + * + * @Fields: + * memory :: + * Used internally to allocate memory. + * + * contours :: + * Linked list of all the contours that make the shape. + * + */ + typedef struct SDF_Shape_ + { + FT_Memory memory; + SDF_Contour* contours; + + } SDF_Shape; + + + /************************************************************************** + * + * @Struct: + * SDF_Signed_Distance + * + * @Description: + * Represent signed distance of a point, i.e., the distance of the edge + * nearest to the point. + * + * @Fields: + * distance :: + * Distance of the point from the nearest edge. Can be squared or + * absolute depending on the `USE_SQUARED_DISTANCES` macro defined in + * file `ftsdfcommon.h`. + * + * cross :: + * Cross product of the shortest distance vector (i.e., the vector + * from the point to the nearest edge) and the direction of the edge + * at the nearest point. This is used to resolve ambiguities of + * `sign`. + * + * sign :: + * A value used to indicate whether the distance vector is outside or + * inside the contour corresponding to the edge. + * + * @Note: + * `sign` may or may not be correct, therefore it must be checked + * properly in case there is an ambiguity. + * + */ + typedef struct SDF_Signed_Distance_ + { + FT_16D16 distance; + FT_16D16 cross; + FT_Char sign; + + } SDF_Signed_Distance; + + + /************************************************************************** + * + * @Struct: + * SDF_Params + * + * @Description: + * Yet another internal parameters required by the rasterizer. + * + * @Fields: + * orientation :: + * This is not the @SDF_Contour_Orientation value but @FT_Orientation, + * which determines whether clockwise-oriented outlines are to be + * filled or counter-clockwise-oriented ones. + * + * flip_sign :: + * If set to true, flip the sign. By default the points filled by the + * outline are positive. + * + * flip_y :: + * If set to true the output bitmap is upside-down. Can be useful + * because OpenGL and DirectX use different coordinate systems for + * textures. + * + * overload_sign :: + * In the subdivision and bounding box optimization, the default + * outside sign is taken as -1. This parameter can be used to modify + * that behaviour. For example, while generating SDF for a single + * counter-clockwise contour, the outside sign should be 1. + * + */ + typedef struct SDF_Params_ + { + FT_Orientation orientation; + FT_Bool flip_sign; + FT_Bool flip_y; + + FT_Int overload_sign; + + } SDF_Params; + + + /************************************************************************** + * + * constants, initializer, and destructor + * + */ + + static + const FT_Vector zero_vector = { 0, 0 }; + + static + const SDF_Edge null_edge = { { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, + SDF_EDGE_UNDEFINED, NULL }; + + static + const SDF_Contour null_contour = { { 0, 0 }, NULL, NULL }; + + static + const SDF_Shape null_shape = { NULL, NULL }; + + static + const SDF_Signed_Distance max_sdf = { INT_MAX, 0, 0 }; + + + /* Create a new @SDF_Edge on the heap and assigns the `edge` */ + /* pointer to the newly allocated memory. */ + static FT_Error + sdf_edge_new( FT_Memory memory, + SDF_Edge** edge ) + { + FT_Error error = FT_Err_Ok; + SDF_Edge* ptr = NULL; + + + if ( !memory || !edge ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_edge; + *edge = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `edge` variable. */ + static void + sdf_edge_done( FT_Memory memory, + SDF_Edge** edge ) + { + if ( !memory || !edge || !*edge ) + return; + + FT_FREE( *edge ); + } + + + /* Create a new @SDF_Contour on the heap and assign */ + /* the `contour` pointer to the newly allocated memory. */ + static FT_Error + sdf_contour_new( FT_Memory memory, + SDF_Contour** contour ) + { + FT_Error error = FT_Err_Ok; + SDF_Contour* ptr = NULL; + + + if ( !memory || !contour ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_contour; + *contour = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `contour` variable. */ + /* Also free the list of edges. */ + static void + sdf_contour_done( FT_Memory memory, + SDF_Contour** contour ) + { + SDF_Edge* edges; + SDF_Edge* temp; + + + if ( !memory || !contour || !*contour ) + return; + + edges = (*contour)->edges; + + /* release all edges */ + while ( edges ) + { + temp = edges; + edges = edges->next; + + sdf_edge_done( memory, &temp ); + } + + FT_FREE( *contour ); + } + + + /* Create a new @SDF_Shape on the heap and assign */ + /* the `shape` pointer to the newly allocated memory. */ + static FT_Error + sdf_shape_new( FT_Memory memory, + SDF_Shape** shape ) + { + FT_Error error = FT_Err_Ok; + SDF_Shape* ptr = NULL; + + + if ( !memory || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_shape; + ptr->memory = memory; + *shape = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `shape` variable. */ + /* Also free the list of contours. */ + static void + sdf_shape_done( SDF_Shape** shape ) + { + FT_Memory memory; + SDF_Contour* contours; + SDF_Contour* temp; + + + if ( !shape || !*shape ) + return; + + memory = (*shape)->memory; + contours = (*shape)->contours; + + if ( !memory ) + return; + + /* release all contours */ + while ( contours ) + { + temp = contours; + contours = contours->next; + + sdf_contour_done( memory, &temp ); + } + + /* release the allocated shape struct */ + FT_FREE( *shape ); + } + + + /************************************************************************** + * + * shape decomposition functions + * + */ + + /* This function is called when starting a new contour at `to`, */ + /* which gets added to the shape's list. */ + static FT_Error + sdf_move_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_CALL( sdf_contour_new( memory, &contour ) ); + + contour->last_pos = *to; + contour->next = shape->contours; + shape->contours = contour; + + Exit: + return error; + } + + + /* This function is called when there is a line in the */ + /* contour. The line starts at the previous edge point and */ + /* stops at `to`. */ + static FT_Error + sdf_line_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + if ( contour->last_pos.x == to->x && + contour->last_pos.y == to->y ) + goto Exit; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_LINE; + edge->start_pos = contour->last_pos; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a conic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with control point `control_1`. */ + static FT_Error + sdf_conic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + /* If the control point coincides with any of the end points */ + /* then it is a line and should be treated as one to avoid */ + /* unnecessary complexity later in the algorithm. */ + if ( ( contour->last_pos.x == control_1->x && + contour->last_pos.y == control_1->y ) || + ( control_1->x == to->x && + control_1->y == to->y ) ) + { + sdf_line_to( to, user ); + goto Exit; + } + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CONIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a cubic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with two control points `control_1` and */ + /* `control_2`. */ + static FT_Error + sdf_cubic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* control_2, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_2 || !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CUBIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->control_b = *control_2; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* Construct the structure to hold all four outline */ + /* decomposition functions. */ + FT_DEFINE_OUTLINE_FUNCS( + sdf_decompose_funcs, + + (FT_Outline_MoveTo_Func) sdf_move_to, /* move_to */ + (FT_Outline_LineTo_Func) sdf_line_to, /* line_to */ + (FT_Outline_ConicTo_Func)sdf_conic_to, /* conic_to */ + (FT_Outline_CubicTo_Func)sdf_cubic_to, /* cubic_to */ + + 0, /* shift */ + 0 /* delta */ + ) + + + /* Decompose `outline` and put it into the `shape` structure. */ + static FT_Error + sdf_outline_decompose( FT_Outline* outline, + SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + + + if ( !outline || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = FT_Outline_Decompose( outline, + &sdf_decompose_funcs, + (void*)shape ); + + Exit: + return error; + } + + + /************************************************************************** + * + * utility functions + * + */ + + /* Return the control box of an edge. The control box is a rectangle */ + /* in which all the control points can fit tightly. */ + static FT_CBox + get_control_box( SDF_Edge edge ) + { + FT_CBox cbox = { 0, 0, 0, 0 }; + FT_Bool is_set = 0; + + + switch ( edge.edge_type ) + { + case SDF_EDGE_CUBIC: + cbox.xMin = edge.control_b.x; + cbox.xMax = edge.control_b.x; + cbox.yMin = edge.control_b.y; + cbox.yMax = edge.control_b.y; + + is_set = 1; + FALL_THROUGH; + + case SDF_EDGE_CONIC: + if ( is_set ) + { + cbox.xMin = edge.control_a.x < cbox.xMin + ? edge.control_a.x + : cbox.xMin; + cbox.xMax = edge.control_a.x > cbox.xMax + ? edge.control_a.x + : cbox.xMax; + + cbox.yMin = edge.control_a.y < cbox.yMin + ? edge.control_a.y + : cbox.yMin; + cbox.yMax = edge.control_a.y > cbox.yMax + ? edge.control_a.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.control_a.x; + cbox.xMax = edge.control_a.x; + cbox.yMin = edge.control_a.y; + cbox.yMax = edge.control_a.y; + + is_set = 1; + } + FALL_THROUGH; + + case SDF_EDGE_LINE: + if ( is_set ) + { + cbox.xMin = edge.start_pos.x < cbox.xMin + ? edge.start_pos.x + : cbox.xMin; + cbox.xMax = edge.start_pos.x > cbox.xMax + ? edge.start_pos.x + : cbox.xMax; + + cbox.yMin = edge.start_pos.y < cbox.yMin + ? edge.start_pos.y + : cbox.yMin; + cbox.yMax = edge.start_pos.y > cbox.yMax + ? edge.start_pos.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.start_pos.x; + cbox.xMax = edge.start_pos.x; + cbox.yMin = edge.start_pos.y; + cbox.yMax = edge.start_pos.y; + } + + cbox.xMin = edge.end_pos.x < cbox.xMin + ? edge.end_pos.x + : cbox.xMin; + cbox.xMax = edge.end_pos.x > cbox.xMax + ? edge.end_pos.x + : cbox.xMax; + + cbox.yMin = edge.end_pos.y < cbox.yMin + ? edge.end_pos.y + : cbox.yMin; + cbox.yMax = edge.end_pos.y > cbox.yMax + ? edge.end_pos.y + : cbox.yMax; + + break; + + default: + break; + } + + return cbox; + } + + + /* Return orientation of a single contour. */ + /* Note that the orientation is independent of the fill rule! */ + /* So, for TTF a clockwise-oriented contour has to be filled */ + /* and the opposite for OTF fonts. */ + static SDF_Contour_Orientation + get_contour_orientation ( SDF_Contour* contour ) + { + SDF_Edge* head = NULL; + FT_26D6 area = 0; + + + /* return none if invalid parameters */ + if ( !contour || !contour->edges ) + return SDF_ORIENTATION_NONE; + + head = contour->edges; + + /* Calculate the area of the control box for all edges. */ + while ( head ) + { + switch ( head->edge_type ) + { + case SDF_EDGE_LINE: + area += MUL_26D6( ( head->end_pos.x - head->start_pos.x ), + ( head->end_pos.y + head->start_pos.y ) ); + break; + + case SDF_EDGE_CONIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->end_pos.x - head->control_a.x, + head->end_pos.y + head->control_a.y ); + break; + + case SDF_EDGE_CUBIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->control_b.x - head->control_a.x, + head->control_b.y + head->control_a.y ); + area += MUL_26D6( head->end_pos.x - head->control_b.x, + head->end_pos.y + head->control_b.y ); + break; + + default: + return SDF_ORIENTATION_NONE; + } + + head = head->next; + } + + /* Clockwise contours cover a positive area, and counter-clockwise */ + /* contours cover a negative area. */ + if ( area > 0 ) + return SDF_ORIENTATION_CW; + else + return SDF_ORIENTATION_CCW; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a conic */ + /* into two conics exactly half way at t = 0.5. */ + static void + split_conic( FT_26D6_Vec* base ) + { + FT_26D6 a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b / 2; + base[2].x = ( a + b ) / 4; + base[1].x = a / 2; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b / 2; + base[2].y = ( a + b ) / 4; + base[1].y = a / 2; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a cubic */ + /* into two cubics exactly half way at t = 0.5. */ + static void + split_cubic( FT_26D6_Vec* base ) + { + FT_26D6 a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c / 2; + c += b; + base[4].x = c / 4; + base[1].x = a / 2; + a += b; + base[2].x = a / 4; + base[3].x = ( a + c ) / 8; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c / 2; + c += b; + base[4].y = c / 4; + base[1].y = a / 2; + a += b; + base[2].y = a / 4; + base[3].y = ( a + c ) / 8; + } + + + /* Split a conic Bezier curve into a number of lines */ + /* and add them to `out'. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_conic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[5]; + SDF_Edge* left,* right; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split conic outline */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + + split_conic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_conic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_conic( memory, &cpos[2], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left ) ); + FT_CALL( sdf_edge_new( memory, &right ) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[2]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[2]; + right->end_pos = cpos[4]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Split a cubic Bezier curve into a number of lines */ + /* and add them to `out`. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_cubic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[7]; + SDF_Edge* left, *right; + const FT_26D6 threshold = ONE_PIXEL / 4; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split the cubic */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + cpos[3] = control_points[3]; + + /* If the segment is flat enough we won't get any benefit by */ + /* splitting it further, so we can just stop splitting. */ + /* */ + /* Check the deviation of the Bezier curve and stop if it is */ + /* smaller than the pre-defined `threshold` value. */ + if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold && + FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold && + FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold && + FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold ) + { + split_cubic( cpos ); + goto Append; + } + + split_cubic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left) ); + FT_CALL( sdf_edge_new( memory, &right) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[3]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[3]; + right->end_pos = cpos[6]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Subdivide an entire shape into line segments */ + /* such that it doesn't look visually different */ + /* from the original curve. */ + static FT_Error + split_sdf_shape( SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + SDF_Contour* contours; + SDF_Contour* new_contours = NULL; + + + if ( !shape || !shape->memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contours = shape->contours; + memory = shape->memory; + + /* for each contour */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + SDF_Edge* new_edges = NULL; + + SDF_Contour* tempc; + + + /* for each edge */ + while ( edges ) + { + SDF_Edge* edge = edges; + SDF_Edge* temp; + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + /* Just create a duplicate edge in case */ + /* it is a line. We can use the same edge. */ + FT_CALL( sdf_edge_new( memory, &temp ) ); + + ft_memcpy( temp, edge, sizeof ( *edge ) ); + + temp->next = new_edges; + new_edges = temp; + break; + + case SDF_EDGE_CONIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[3]; + FT_26D6 dx, dy; + FT_UInt num_splits; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->end_pos; + + dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x ); + dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y ); + if ( dx < dy ) + dx = dy; + + /* Calculate the number of necessary bisections. Each */ + /* bisection causes a four-fold reduction of the deviation, */ + /* hence we bisect the Bezier curve until the deviation */ + /* becomes less than 1/8 of a pixel. For more details */ + /* check file `ftgrays.c`. */ + num_splits = 1; + while ( dx > ONE_PIXEL / 8 ) + { + dx >>= 2; + num_splits <<= 1; + } + + error = split_sdf_conic( memory, ctrls, num_splits, &new_edges ); + } + break; + + case SDF_EDGE_CUBIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[4]; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->control_b; + ctrls[3] = edge->end_pos; + + error = split_sdf_cubic( memory, ctrls, 32, &new_edges ); + } + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + if ( error != FT_Err_Ok ) + goto Exit; + + edges = edges->next; + } + + /* add to the contours list */ + FT_CALL( sdf_contour_new( memory, &tempc ) ); + + tempc->next = new_contours; + tempc->edges = new_edges; + new_contours = tempc; + new_edges = NULL; + + /* deallocate the contour */ + tempc = contours; + contours = contours->next; + + sdf_contour_done( memory, &tempc ); + } + + shape->contours = new_contours; + + Exit: + return error; + } + + + /************************************************************************** + * + * for debugging + * + */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + static void + sdf_shape_dump( SDF_Shape* shape ) + { + FT_UInt num_contours = 0; + + FT_UInt total_edges = 0; + FT_UInt total_lines = 0; + FT_UInt total_conic = 0; + FT_UInt total_cubic = 0; + + SDF_Contour* contour_list; + + + if ( !shape ) + { + FT_TRACE5(( "sdf_shape_dump: null shape\n" )); + return; + } + + contour_list = shape->contours; + + FT_TRACE5(( "sdf_shape_dump (values are in 26.6 format):\n" )); + + while ( contour_list ) + { + FT_UInt num_edges = 0; + SDF_Edge* edge_list; + SDF_Contour* contour = contour_list; + + + FT_TRACE5(( " Contour %d\n", num_contours )); + + edge_list = contour->edges; + + while ( edge_list ) + { + SDF_Edge* edge = edge_list; + + + FT_TRACE5(( " %3d: ", num_edges )); + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + FT_TRACE5(( "Line: (%ld, %ld) -- (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->end_pos.x, edge->end_pos.y )); + total_lines++; + break; + + case SDF_EDGE_CONIC: + FT_TRACE5(( "Conic: (%ld, %ld) .. (%ld, %ld) .. (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->end_pos.x, edge->end_pos.y )); + total_conic++; + break; + + case SDF_EDGE_CUBIC: + FT_TRACE5(( "Cubic: (%ld, %ld) .. (%ld, %ld)" + " .. (%ld, %ld) .. (%ld %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->control_b.x, edge->control_b.y, + edge->end_pos.x, edge->end_pos.y )); + total_cubic++; + break; + + default: + break; + } + + num_edges++; + total_edges++; + edge_list = edge_list->next; + } + + num_contours++; + contour_list = contour_list->next; + } + + FT_TRACE5(( "\n" )); + FT_TRACE5(( " total number of contours = %d\n", num_contours )); + FT_TRACE5(( " total number of edges = %d\n", total_edges )); + FT_TRACE5(( " |__lines = %d\n", total_lines )); + FT_TRACE5(( " |__conic = %d\n", total_conic )); + FT_TRACE5(( " |__cubic = %d\n", total_cubic )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * math functions + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* [NOTE]: All the functions below down until rasterizer */ + /* can be avoided if we decide to subdivide the */ + /* curve into lines. */ + + /* This function uses Newton's iteration to find */ + /* the cube root of a fixed-point integer. */ + static FT_16D16 + cube_root( FT_16D16 val ) + { + /* [IMPORTANT]: This function is not good as it may */ + /* not break, so use a lookup table instead. Or we */ + /* can use an algorithm similar to `square_root`. */ + + FT_Int v, g, c; + + + if ( val == 0 || + val == -FT_INT_16D16( 1 ) || + val == FT_INT_16D16( 1 ) ) + return val; + + v = val < 0 ? -val : val; + g = square_root( v ); + c = 0; + + while ( 1 ) + { + c = FT_MulFix( FT_MulFix( g, g ), g ) - v; + c = FT_DivFix( c, 3 * FT_MulFix( g, g ) ); + + g -= c; + + if ( ( c < 0 ? -c : c ) < 30 ) + break; + } + + return val < 0 ? -g : g; + } + + + /* Calculate the perpendicular by using '1 - base^2'. */ + /* Then use arctan to compute the angle. */ + static FT_16D16 + arc_cos( FT_16D16 val ) + { + FT_16D16 p; + FT_16D16 b = val; + FT_16D16 one = FT_INT_16D16( 1 ); + + + if ( b > one ) + b = one; + if ( b < -one ) + b = -one; + + p = one - FT_MulFix( b, b ); + p = square_root( p ); + + return FT_Atan2( b, p ); + } + + + /* Compute roots of a quadratic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/QuadraticFormula.html */ + static FT_UShort + solve_quadratic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_16D16 out[2] ) + { + FT_16D16 discriminant = 0; + + + a = FT_26D6_16D16( a ); + b = FT_26D6_16D16( b ); + c = FT_26D6_16D16( c ); + + if ( a == 0 ) + { + if ( b == 0 ) + return 0; + else + { + out[0] = FT_DivFix( -c, b ); + + return 1; + } + } + + discriminant = FT_MulFix( b, b ) - 4 * FT_MulFix( a, c ); + + if ( discriminant < 0 ) + return 0; + else if ( discriminant == 0 ) + { + out[0] = FT_DivFix( -b, 2 * a ); + + return 1; + } + else + { + discriminant = square_root( discriminant ); + + out[0] = FT_DivFix( -b + discriminant, 2 * a ); + out[1] = FT_DivFix( -b - discriminant, 2 * a ); + + return 2; + } + } + + + /* Compute roots of a cubic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/CubicFormula.html */ + static FT_UShort + solve_cubic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_26D6 d, + FT_16D16 out[3] ) + { + FT_16D16 q = 0; /* intermediate */ + FT_16D16 r = 0; /* intermediate */ + + FT_16D16 a2 = b; /* x^2 coefficients */ + FT_16D16 a1 = c; /* x coefficients */ + FT_16D16 a0 = d; /* constant */ + + FT_16D16 q3 = 0; + FT_16D16 r2 = 0; + FT_16D16 a23 = 0; + FT_16D16 a22 = 0; + FT_16D16 a1x2 = 0; + + + /* cutoff value for `a` to be a cubic, otherwise solve quadratic */ + if ( a == 0 || FT_ABS( a ) < 16 ) + return solve_quadratic_equation( b, c, d, out ); + + if ( d == 0 ) + { + out[0] = 0; + + return solve_quadratic_equation( a, b, c, out + 1 ) + 1; + } + + /* normalize the coefficients; this also makes them 16.16 */ + a2 = FT_DivFix( a2, a ); + a1 = FT_DivFix( a1, a ); + a0 = FT_DivFix( a0, a ); + + /* compute intermediates */ + a1x2 = FT_MulFix( a1, a2 ); + a22 = FT_MulFix( a2, a2 ); + a23 = FT_MulFix( a22, a2 ); + + q = ( 3 * a1 - a22 ) / 9; + r = ( 9 * a1x2 - 27 * a0 - 2 * a23 ) / 54; + + /* [BUG]: `q3` and `r2` still cause underflow. */ + + q3 = FT_MulFix( q, q ); + q3 = FT_MulFix( q3, q ); + + r2 = FT_MulFix( r, r ); + + if ( q3 < 0 && r2 < -q3 ) + { + FT_16D16 t = 0; + + + q3 = square_root( -q3 ); + t = FT_DivFix( r, q3 ); + + if ( t > ( 1 << 16 ) ) + t = ( 1 << 16 ); + if ( t < -( 1 << 16 ) ) + t = -( 1 << 16 ); + + t = arc_cos( t ); + a2 /= 3; + q = 2 * square_root( -q ); + + out[0] = FT_MulFix( q, FT_Cos( t / 3 ) ) - a2; + out[1] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 2 ) / 3 ) ) - a2; + out[2] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 4 ) / 3 ) ) - a2; + + return 3; + } + + else if ( r2 == -q3 ) + { + FT_16D16 s = 0; + + + s = cube_root( r ); + a2 /= -3; + + out[0] = a2 + ( 2 * s ); + out[1] = a2 - s; + + return 2; + } + + else + { + FT_16D16 s = 0; + FT_16D16 t = 0; + FT_16D16 dis = 0; + + + if ( q3 == 0 ) + dis = FT_ABS( r ); + else + dis = square_root( q3 + r2 ); + + s = cube_root( r + dis ); + t = cube_root( r - dis ); + a2 /= -3; + out[0] = ( a2 + ( s + t ) ); + + return 1; + } + } + +#endif /* !USE_NEWTON_FOR_CONIC */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** RASTERIZER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * resolve_corner + * + * @Description: + * At some places on the grid two edges can give opposite directions; + * this happens when the closest point is on one of the endpoint. In + * that case we need to check the proper sign. + * + * This can be visualized by an example: + * + * ``` + * x + * + * o + * ^ \ + * / \ + * / \ + * (a) / \ (b) + * / \ + * / \ + * / v + * ``` + * + * Suppose `x` is the point whose shortest distance from an arbitrary + * contour we want to find out. It is clear that `o` is the nearest + * point on the contour. Now to determine the sign we do a cross + * product of the shortest distance vector and the edge direction, i.e., + * + * ``` + * => sign = cross(x - o, direction(a)) + * ``` + * + * Using the right hand thumb rule we can see that the sign will be + * positive. + * + * If we use `b', however, we have + * + * ``` + * => sign = cross(x - o, direction(b)) + * ``` + * + * In this case the sign will be negative. To determine the correct + * sign we thus divide the plane in two halves and check which plane the + * point lies in. + * + * ``` + * | + * x | + * | + * o + * ^|\ + * / | \ + * / | \ + * (a) / | \ (b) + * / | \ + * / \ + * / v + * ``` + * + * We can see that `x` lies in the plane of `a`, so we take the sign + * determined by `a`. This test can be easily done by calculating the + * orthogonality and taking the greater one. + * + * The orthogonality is simply the sinus of the two vectors (i.e., + * x - o) and the corresponding direction. We efficiently pre-compute + * the orthogonality with the corresponding `get_min_distance_*` + * functions. + * + * @Input: + * sdf1 :: + * First signed distance (can be any of `a` or `b`). + * + * sdf1 :: + * Second signed distance (can be any of `a` or `b`). + * + * @Return: + * The correct signed distance, which is computed by using the above + * algorithm. + * + * @Note: + * The function does not care about the actual distance, it simply + * returns the signed distance which has a larger cross product. As a + * consequence, this function should not be used if the two distances + * are fairly apart. In that case simply use the signed distance with + * a shorter absolute distance. + * + */ + static SDF_Signed_Distance + resolve_corner( SDF_Signed_Distance sdf1, + SDF_Signed_Distance sdf2 ) + { + return FT_ABS( sdf1.cross ) > FT_ABS( sdf2.cross ) ? sdf1 : sdf2; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_line + * + * @Description: + * Find the shortest distance from the `line` segment to a given `point` + * and assign it to `out`. Use it for line segments only. + * + * @Input: + * line :: + * The line segment to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `line`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `line' parameter must have an edge type of `SDF_EDGE_LINE`. + * + */ + static FT_Error + get_min_distance_line( SDF_Edge* line, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * In order to calculate the shortest distance from a point to + * a line segment, we do the following. Let's assume that + * + * ``` + * a = start point of the line segment + * b = end point of the line segment + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) Write the parametric equation of the line. + * + * ``` + * point_on_line = a + (b - a) * t (t is the factor) + * ``` + * + * (2) Find the projection of point `p` on the line. The projection + * will be perpendicular to the line, which allows us to get the + * solution by making the dot product zero. + * + * ``` + * (point_on_line - a) . (p - point_on_line) = 0 + * + * (point_on_line) + * (a) x-------o----------------x (b) + * |_| + * | + * | + * (p) + * ``` + * + * (3) Simplification of the above equation yields the factor of + * `point_on_line`: + * + * ``` + * t = ((p - a) . (b - a)) / |b - a|^2 + * ``` + * + * (4) We clamp factor `t` between [0.0f, 1.0f] because `point_on_line` + * can be outside of the line segment: + * + * ``` + * (point_on_line) + * (a) x------------------------x (b) -----o--- + * |_| + * | + * | + * (p) + * ``` + * + * (5) Finally, the distance we are interested in is + * + * ``` + * |point_on_line - p| + * ``` + */ + + FT_Error error = FT_Err_Ok; + + FT_Vector a; /* start position */ + FT_Vector b; /* end position */ + FT_Vector p; /* current point */ + + FT_26D6_Vec line_segment; /* `b` - `a` */ + FT_26D6_Vec p_sub_a; /* `p` - `a` */ + + FT_26D6 sq_line_length; /* squared length of `line_segment` */ + FT_16D16 factor; /* factor of the nearest point */ + FT_26D6 cross; /* used to determine sign */ + + FT_16D16_Vec nearest_point; /* `point_on_line` */ + FT_16D16_Vec nearest_vector; /* `p` - `nearest_point` */ + + + if ( !line || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( line->edge_type != SDF_EDGE_LINE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + a = line->start_pos; + b = line->end_pos; + p = point; + + line_segment.x = b.x - a.x; + line_segment.y = b.y - a.y; + + p_sub_a.x = p.x - a.x; + p_sub_a.y = p.y - a.y; + + sq_line_length = ( line_segment.x * line_segment.x ) / 64 + + ( line_segment.y * line_segment.y ) / 64; + + /* currently factor is 26.6 */ + factor = ( p_sub_a.x * line_segment.x ) / 64 + + ( p_sub_a.y * line_segment.y ) / 64; + + /* now factor is 16.16 */ + factor = FT_DivFix( factor, sq_line_length ); + + /* clamp the factor between 0.0 and 1.0 in fixed-point */ + if ( factor > FT_INT_16D16( 1 ) ) + factor = FT_INT_16D16( 1 ); + if ( factor < 0 ) + factor = 0; + + nearest_point.x = FT_MulFix( FT_26D6_16D16( line_segment.x ), + factor ); + nearest_point.y = FT_MulFix( FT_26D6_16D16( line_segment.y ), + factor ); + + nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x; + nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y; + + nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x ); + nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y ); + + cross = FT_MulFix( nearest_vector.x, line_segment.y ) - + FT_MulFix( nearest_vector.y, line_segment.x ); + + /* assign the output */ + out->sign = cross < 0 ? 1 : -1; + out->distance = VECTOR_LENGTH_16D16( nearest_vector ); + + /* Instead of finding `cross` for checking corner we */ + /* directly set it here. This is more efficient */ + /* because if the distance is perpendicular we can */ + /* directly set it to 1. */ + if ( factor != 0 && factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); + else + { + /* [OPTIMIZATION]: Pre-compute this direction. */ + /* If not perpendicular then compute `cross`. */ + FT_Vector_NormLen( &line_segment ); + FT_Vector_NormLen( &nearest_vector ); + + out->cross = FT_MulFix( line_segment.x, nearest_vector.y ) - + FT_MulFix( line_segment.y, nearest_vector.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_conic + * + * @Description: + * Find the shortest distance from the `conic` Bezier curve to a given + * `point` and assign it to `out`. Use it for conic/quadratic curves + * only. + * + * @Input: + * conic :: + * The conic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `conic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `conic` parameter must have an edge type of `SDF_EDGE_CONIC`. + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* + * The function uses an analytical method to find the shortest distance + * which is faster than the Newton-Raphson method, but has underflows at + * the moment. Use Newton's method if you can see artifacts in the SDF. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a + * quadratic Bezier curve is similar to the line segment algorithm. The + * shortest distance is perpendicular to the Bezier curve; the only + * difference from line is that there can be more than one + * perpendicular, and we also have to check the endpoints, because the + * perpendicular may not be the shortest. + * + * Let's assume that + * ``` + * p0 = first endpoint + * p1 = control point + * p2 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` a factor in the range [0.0f, 1.0f]. This equation can + * be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = p1 - p0 + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + 2t * B + p0 + * ``` + * + * (2) The derivative of the last equation above is + * + * ``` + * B'(t) = 2 *(tA + B) + * ``` + * + * (3) To find the shortest distance from `p` to `B(t)` we find the + * point on the curve at which the shortest distance vector (i.e., + * `B(t) - p`) and the direction (i.e., `B'(t)`) make 90 degrees. + * In other words, we make the dot product zero. + * + * ``` + * (B(t) - p) . (B'(t)) = 0 + * (t^2 * A + 2t * B + p0 - p) . (2 * (tA + B)) = 0 + * ``` + * + * After simplifying we get a cubic equation + * + * ``` + * at^3 + bt^2 + ct + d = 0 + * ``` + * + * with + * + * ``` + * a = A.A + * b = 3A.B + * c = 2B.B + A.p0 - A.p + * d = p0.B - p.B + * ``` + * + * (4) Now the roots of the equation can be computed using 'Cardano's + * Cubic formula'; we clamp the roots in the range [0.0f, 1.0f]. + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB; /* A, B in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_26D6 a, b, c, d; /* cubic coefficients */ + + FT_16D16 roots[3] = { 0, 0, 0 }; /* real roots of the cubic eq. */ + FT_16D16 min_factor; /* factor at `nearest_point` */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort num_roots; /* number of real roots of cubic */ + FT_UShort i; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = p1.x - p0.x; + bB.y = p1.y - p0.y; + + /* compute cubic coefficients */ + a = VEC_26D6_DOT( aA, aA ); + + b = 3 * VEC_26D6_DOT( aA, bB ); + + c = 2 * VEC_26D6_DOT( bB, bB ) + + VEC_26D6_DOT( aA, p0 ) - + VEC_26D6_DOT( aA, p ); + + d = VEC_26D6_DOT( p0, bB ) - + VEC_26D6_DOT( p, bB ); + + /* find the roots */ + num_roots = solve_cubic_equation( a, b, c, d, roots ); + + if ( num_roots == 0 ) + { + roots[0] = 0; + roots[1] = FT_INT_16D16( 1 ); + num_roots = 2; + } + + /* [OPTIMIZATION]: Check the roots, clamp them and discard */ + /* duplicate roots. */ + + /* convert these values to 16.16 for further computation */ + aA.x = FT_26D6_16D16( aA.x ); + aA.y = FT_26D6_16D16( aA.y ); + + bB.x = FT_26D6_16D16( bB.x ); + bB.y = FT_26D6_16D16( bB.y ); + + p0.x = FT_26D6_16D16( p0.x ); + p0.y = FT_26D6_16D16( p0.y ); + + p.x = FT_26D6_16D16( p.x ); + p.y = FT_26D6_16D16( p.y ); + + for ( i = 0; i < num_roots; i++ ) + { + FT_16D16 t = roots[i]; + FT_16D16 t2 = 0; + FT_16D16 dist = 0; + + FT_16D16_Vec curve_point; + FT_16D16_Vec dist_vector; + + /* + * Ideally we should discard the roots which are outside the range + * [0.0, 1.0] and check the endpoints of the Bezier curve, but Behdad + * Esfahbod proved the following lemma. + * + * Lemma: + * + * (1) If the closest point on the curve [0, 1] is to the endpoint at + * `t` = 1 and the cubic has no real roots at `t` = 1 then the + * cubic must have a real root at some `t` > 1. + * + * (2) Similarly, if the closest point on the curve [0, 1] is to the + * endpoint at `t` = 0 and the cubic has no real roots at `t` = 0 + * then the cubic must have a real root at some `t` < 0. + * + * Now because of this lemma we only need to clamp the roots and that + * will take care of the endpoints. + * + * For more details see + * + * https://lists.nongnu.org/archive/html/freetype-devel/2020-06/msg00147.html + */ + + if ( t < 0 ) + t = 0; + if ( t > FT_INT_16D16( 1 ) ) + t = FT_INT_16D16( 1 ); + + t2 = FT_MulFix( t, t ); + + /* B(t) = t^2 * A + 2t * B + p0 - p */ + curve_point.x = FT_MulFix( aA.x, t2 ) + + 2 * FT_MulFix( bB.x, t ) + p0.x; + curve_point.y = FT_MulFix( aA.y, t2 ) + + 2 * FT_MulFix( bB.y, t ) + p0.y; + + /* `curve_point` - `p` */ + dist_vector.x = curve_point.x - p.x; + dist_vector.y = curve_point.y - p.y; + + dist = VECTOR_LENGTH_16D16( dist_vector ); + + if ( dist < min ) + { + min = dist; + nearest_point = curve_point; + min_factor = t; + } + } + + /* B'(t) = 2 * (tA + B) */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - p.x, direction.y ) - + FT_MulFix( nearest_point.y - p.y, direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + +#else /* USE_NEWTON_FOR_CONIC */ + + /* + * The function uses Newton's approximation to find the shortest distance, + * which is a bit slower than the analytical method but doesn't cause + * underflow. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * This method uses Newton-Raphson's approximation to find the shortest + * distance from a point to a conic curve. It does not involve solving + * any cubic equation, that is why there is no risk of underflow. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` the factor in the range [0.0f, 1.0f]. The above + * equation can be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = 2 * (p1 - p0) + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + t * B + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 2t * A + B + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 2A + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^2 * A + t^2 * B + p0 - p + * ``` + * + * With + * + * ``` + * C = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^2 * A + t * B + C + * ``` + * + * (5) Finally, the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degrees with the curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC; /* A, B, C in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at `nearest_point' */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = 2 * ( p1.x - p0.x ); + bB.y = 2 * ( p1.y - p0.y ); + + cC.x = p0.x; + cC.y = p0.y; + + /* do Newton's iterations */ + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + FT_16D16 factor2; + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point` - `p` */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + + /* B(t) = t^2 * A + t * B + p0 */ + curve_point.x = FT_MulFix( aA.x, factor2 ) + + FT_MulFix( bB.x, factor ) + cC.x; + curve_point.y = FT_MulFix( aA.y, factor2 ) + + FT_MulFix( bB.y, factor ) + cC.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + nearest_point = curve_point; + } + + /* This is Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 2tA + B */ + d1.x = FT_MulFix( aA.x, 2 * factor ) + bB.x; + d1.y = FT_MulFix( aA.y, 2 * factor ) + bB.y; + + /* B''(t) = 2A */ + d2.x = 2 * aA.x; + d2.y = 2 * aA.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 2t * A + B */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + +#endif /* USE_NEWTON_FOR_CONIC */ + + + /************************************************************************** + * + * @Function: + * get_min_distance_cubic + * + * @Description: + * Find the shortest distance from the `cubic` Bezier curve to a given + * `point` and assigns it to `out`. Use it for cubic curves only. + * + * @Input: + * cubic :: + * The cubic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `cubic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function uses Newton's approximation to find the shortest + * distance. Another way would be to divide the cubic into conic or + * subdivide the curve into lines, but that is not implemented. + * + * The `cubic` parameter must have an edge type of `SDF_EDGE_CUBIC`. + * + */ + static FT_Error + get_min_distance_cubic( SDF_Edge* cubic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a cubic + * Bezier curve is similar to quadratic curve algorithm. The only + * difference is that while calculating factor `t`, instead of a cubic + * polynomial equation we have to find the roots of a 5th degree + * polynomial equation. Solving this would require a significant amount + * of time, and still the results may not be accurate. We are thus + * going to directly approximate the value of `t` using the Newton-Raphson + * method. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = first control point + * p2 = second control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a cubic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^3 * p0 + 3(1 - t)^2 t * p1 + + * 3(1 - t)t^2 * p2 + t^3 * p3 + * ``` + * + * The equation can be expanded and written as + * + * ``` + * B(t) = t^3 * (-p0 + 3p1 - 3p2 + p3) + + * 3t^2 * (p0 - 2p1 + p2) + 3t * (-p0 + p1) + p0 + * ``` + * + * With + * + * ``` + * A = -p0 + 3p1 - 3p2 + p3 + * B = 3(p0 - 2p1 + p2) + * C = 3(-p0 + p1) + * ``` + * + * we have + * + * ``` + * B(t) = t^3 * A + t^2 * B + t * C + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 3t^2 * A + 2t * B + C + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 6t * A + 2B + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + p0 - p + * ``` + * + * With + * + * ``` + * D = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + D + * ``` + * + * (5) Finally the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degree with curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'( t ) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC, dD; /* A, B, C, D in the above comment */ + FT_16D16_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_16D16_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at shortest distance */ + FT_16D16 min_factor_sq = 0; /* factor at shortest distance */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !cubic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( cubic->edge_type != SDF_EDGE_CUBIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = cubic->start_pos; + p1 = cubic->control_a; + p2 = cubic->control_b; + p3 = cubic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = -p0.x + 3 * ( p1.x - p2.x ) + p3.x; + aA.y = -p0.y + 3 * ( p1.y - p2.y ) + p3.y; + + bB.x = 3 * ( p0.x - 2 * p1.x + p2.x ); + bB.y = 3 * ( p0.y - 2 * p1.y + p2.y ); + + cC.x = 3 * ( p1.x - p0.x ); + cC.y = 3 * ( p1.y - p0.y ); + + dD.x = p0.x; + dD.y = p0.y; + + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + + FT_16D16 factor2; /* factor^2 */ + FT_16D16 factor3; /* factor^3 */ + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point' - `p' */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + factor3 = FT_MulFix( factor2, factor ); + + /* B(t) = t^3 * A + t^2 * B + t * C + D */ + curve_point.x = FT_MulFix( aA.x, factor3 ) + + FT_MulFix( bB.x, factor2 ) + + FT_MulFix( cC.x, factor ) + dD.x; + curve_point.y = FT_MulFix( aA.y, factor3 ) + + FT_MulFix( bB.y, factor2 ) + + FT_MulFix( cC.y, factor ) + dD.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + min_factor_sq = factor2; + nearest_point = curve_point; + } + + /* This the Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 3t^2 * A + 2t * B + C */ + d1.x = FT_MulFix( aA.x, 3 * factor2 ) + + FT_MulFix( bB.x, 2 * factor ) + cC.x; + d1.y = FT_MulFix( aA.y, 3 * factor2 ) + + FT_MulFix( bB.y, 2 * factor ) + cC.y; + + /* B''(t) = 6t * A + 2B */ + d2.x = FT_MulFix( aA.x, 6 * factor ) + 2 * bB.x; + d2.y = FT_MulFix( aA.y, 6 * factor ) + 2 * bB.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 3t^2 * A + 2t * B + C */ + direction.x = FT_MulFix( aA.x, 3 * min_factor_sq ) + + FT_MulFix( bB.x, 2 * min_factor ) + cC.x; + direction.y = FT_MulFix( aA.y, 3 * min_factor_sq ) + + FT_MulFix( bB.y, 2 * min_factor ) + cC.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_edge_get_min_distance + * + * @Description: + * Find shortest distance from `point` to any type of `edge`. It checks + * the edge type and then calls the relevant `get_min_distance_*` + * function. + * + * @Input: + * edge :: + * An edge to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `edge`. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_edge_get_min_distance( SDF_Edge* edge, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + + + if ( !edge || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* edge-specific distance calculation */ + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + get_min_distance_line( edge, point, out ); + break; + + case SDF_EDGE_CONIC: + get_min_distance_conic( edge, point, out ); + break; + + case SDF_EDGE_CUBIC: + get_min_distance_cubic( edge, point, out ); + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + Exit: + return error; + } + + + /* `sdf_generate' is not used at the moment */ +#if 0 + + #error "DO NOT USE THIS!" + #error "The function still outputs 16-bit data, which might cause memory" + #error "corruption. If required I will add this later." + + /************************************************************************** + * + * @Function: + * sdf_contour_get_min_distance + * + * @Description: + * Iterate over all edges that make up the contour, find the shortest + * distance from a point to this contour, and assigns result to `out`. + * + * @Input: + * contour :: + * A contour to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from the `point' to the `contour'. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function does not return a signed distance for each edge which + * makes up the contour, it simply returns the shortest of all the + * edges. + * + */ + static FT_Error + sdf_contour_get_min_distance( SDF_Contour* contour, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Edge* edge_list; + + + if ( !contour || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + edge_list = contour->edges; + + /* iterate over all the edges manually */ + while ( edge_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + FT_16D16 diff; + + + FT_CALL( sdf_edge_get_min_distance( edge_list, + point, + ¤t_dist ) ); + + if ( current_dist.distance >= 0 ) + { + diff = current_dist.distance - min_dist.distance; + + + if ( FT_ABS( diff ) < CORNER_CHECK_EPSILON ) + min_dist = resolve_corner( min_dist, current_dist ); + else if ( diff < 0 ) + min_dist = current_dist; + } + else + FT_TRACE0(( "sdf_contour_get_min_distance: Overflow.\n" )); + + edge_list = edge_list->next; + } + + *out = min_dist; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate + * + * @Description: + * This is the main function that is responsible for generating signed + * distance fields. The function does not align or compute the size of + * `bitmap`; therefore the calling application must set up `bitmap` + * properly and transform the `shape' appropriately in advance. + * + * Currently we check all pixels against all contours and all edges. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_UInt width = 0; + FT_UInt rows = 0; + FT_UInt x = 0; /* used to loop in x direction, i.e., width */ + FT_UInt y = 0; /* used to loop in y direction, i.e., rows */ + FT_UInt sp_sq = 0; /* `spread` [* `spread`] as a 16.16 fixed value */ + + FT_Short* buffer; + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + width = bitmap->width; + rows = bitmap->rows; + buffer = (FT_Short*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( spread * spread ); + else + sp_sq = FT_INT_16D16( spread ); + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])\n", + width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all rows */ + for ( y = 0; y < rows; y++ ) + { + /* loop over all pixels of a row */ + for ( x = 0; x < width; x++ ) + { + /* `grid_point` is the current pixel position; */ + /* our task is to find the shortest distance */ + /* from this point to the entire shape. */ + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Contour* contour_list; + + FT_UInt index; + FT_Short value; + + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point' is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + contour_list = shape->contours; + + /* iterate over all contours manually */ + while ( contour_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + + + FT_CALL( sdf_contour_get_min_distance( contour_list, + grid_point, + ¤t_dist ) ); + + if ( current_dist.distance < min_dist.distance ) + min_dist = current_dist; + + contour_list = contour_list->next; + } + + /* [OPTIMIZATION]: if (min_dist > sp_sq) then simply clamp */ + /* the value to spread to avoid square_root */ + + /* clamp the values to spread */ + if ( min_dist.distance > sp_sq ) + min_dist.distance = sp_sq; + + /* square_root the values and fit in a 6.10 fixed-point */ + if ( USE_SQUARED_DISTANCES ) + min_dist.distance = square_root( min_dist.distance ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + min_dist.sign = -min_dist.sign; + if ( internal_params.flip_sign ) + min_dist.sign = -min_dist.sign; + + min_dist.distance /= 64; /* convert from 16.16 to 22.10 */ + + value = min_dist.distance & 0x0000FFFF; /* truncate to 6.10 */ + value *= min_dist.sign; + + if ( internal_params.flip_y ) + index = y * width + x; + else + index = ( rows - y - 1 ) * width + x; + + buffer[index] = value; + } + } + + Exit: + return error; + } + +#endif /* 0 */ + + + /************************************************************************** + * + * @Function: + * sdf_generate_bounding_box + * + * @Description: + * This function does basically the same thing as `sdf_generate` above + * but more efficiently. + * + * Instead of checking all pixels against all edges, we loop over all + * edges and only check pixels around the control box of the edge; the + * control box is increased by the spread in all directions. Anything + * outside of the control box that exceeds `spread` doesn't need to be + * computed. + * + * Lastly, to determine the sign of unchecked pixels, we do a single + * pass of all rows starting with a '+' sign and flipping when we come + * across a '-' sign and continue. This also eliminates the possibility + * of overflow because we only check the proximity of the curve. + * Therefore we can use squared distanced safely. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_bounding_box( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Int width, rows, i, j; + FT_Int sp_sq; /* max value to check */ + + SDF_Contour* contours; /* list of all contours */ + FT_SDFFormat* buffer; /* the bitmap buffer */ + + /* This buffer has the same size in indices as the */ + /* bitmap buffer. When we check a pixel position for */ + /* a shortest distance we keep it in this buffer. */ + /* This way we can find out which pixel is set, */ + /* and also determine the signs properly. */ + SDF_Signed_Distance* dists = NULL; + + const FT_16D16 fixed_spread = (FT_16D16)FT_INT_16D16( spread ); + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = shape->memory; + if ( !memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_ALLOC( dists, + bitmap->width * bitmap->rows * sizeof ( *dists ) ) ) + goto Exit; + + contours = shape->contours; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + buffer = (FT_SDFFormat*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( (FT_Int)( spread * spread ) ); + else + sp_sq = fixed_spread; + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])", width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all contours */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + + + /* loop over all edges */ + while ( edges ) + { + FT_CBox cbox; + FT_Int x, y; + + + /* get the control box and increase it by `spread' */ + cbox = get_control_box( *edges ); + + cbox.xMin = ( cbox.xMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.xMax = ( cbox.xMax + 63 ) / 64 + ( FT_Pos )spread; + cbox.yMin = ( cbox.yMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.yMax = ( cbox.yMax + 63 ) / 64 + ( FT_Pos )spread; + + /* now loop over the pixels in the control box. */ + for ( y = cbox.yMin; y < cbox.yMax; y++ ) + { + for ( x = cbox.xMin; x < cbox.xMax; x++ ) + { + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance dist = max_sdf; + FT_UInt index = 0; + FT_16D16 diff = 0; + + + if ( x < 0 || x >= width ) + continue; + if ( y < 0 || y >= rows ) + continue; + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point` is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + FT_CALL( sdf_edge_get_min_distance( edges, + grid_point, + &dist ) ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + dist.sign = -dist.sign; + + /* ignore if the distance is greater than spread; */ + /* otherwise it creates artifacts due to the wrong sign */ + if ( dist.distance > sp_sq ) + continue; + + /* take the square root of the distance if required */ + if ( USE_SQUARED_DISTANCES ) + dist.distance = square_root( dist.distance ); + + if ( internal_params.flip_y ) + index = (FT_UInt)( y * width + x ); + else + index = (FT_UInt)( ( rows - y - 1 ) * width + x ); + + /* check whether the pixel is set or not */ + if ( dists[index].sign == 0 ) + dists[index] = dist; + else + { + diff = FT_ABS( dists[index].distance - dist.distance ); + + if ( diff <= CORNER_CHECK_EPSILON ) + dists[index] = resolve_corner( dists[index], dist ); + else if ( dists[index].distance > dist.distance ) + dists[index] = dist; + } + } + } + + edges = edges->next; + } + + contours = contours->next; + } + + /* final pass */ + for ( j = 0; j < rows; j++ ) + { + /* We assume the starting pixel of each row is outside. */ + FT_Char current_sign = -1; + FT_UInt index; + + + if ( internal_params.overload_sign != 0 ) + current_sign = internal_params.overload_sign < 0 ? -1 : 1; + + for ( i = 0; i < width; i++ ) + { + index = (FT_UInt)( j * width + i ); + + /* if the pixel is not set */ + /* its shortest distance is more than `spread` */ + if ( dists[index].sign == 0 ) + dists[index].distance = fixed_spread; + else + current_sign = dists[index].sign; + + /* clamp the values */ + if ( dists[index].distance > fixed_spread ) + dists[index].distance = fixed_spread; + + /* flip sign if required */ + dists[index].distance *= internal_params.flip_sign ? -current_sign + : current_sign; + + /* concatenate to appropriate format */ + buffer[index] = map_fixed_to_sdf( dists[index].distance, + fixed_spread ); + } + } + + Exit: + FT_FREE( dists ); + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_subdivision + * + * @Description: + * Subdivide the shape into a number of straight lines, then use the + * above `sdf_generate_bounding_box` function to generate the SDF. + * + * Note: After calling this function `shape` no longer has the original + * edges, it only contains lines. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed inthe output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_subdivision( const SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + /* + * Thanks to Alexei for providing the idea of this optimization. + * + * We take advantage of two facts. + * + * (1) Computing the shortest distance from a point to a line segment is + * very fast. + * (2) We don't have to compute the shortest distance for the entire + * two-dimensional grid. + * + * Both ideas lead to the following optimization. + * + * (1) Split the outlines into a number of line segments. + * + * (2) For each line segment, only process its neighborhood. + * + * (3) Compute the closest distance to the line only for neighborhood + * grid points. + * + * This greatly reduces the number of grid points to check. + */ + + FT_Error error = FT_Err_Ok; + + + FT_CALL( split_sdf_shape( shape ) ); + FT_CALL( sdf_generate_bounding_box( internal_params, + shape, spread, bitmap ) ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_with_overlaps + * + * @Description: + * This function can be used to generate SDF for glyphs with overlapping + * contours. The function generates SDF for contours separately on + * separate bitmaps (to generate SDF it uses + * `sdf_generate_subdivision`). At the end it simply combines all the + * SDF into the output bitmap; this fixes all the signs and removes + * overlaps. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function cannot generate a proper SDF for glyphs with + * self-intersecting contours because we cannot separate them into two + * separate bitmaps. In case of self-intersecting contours it is + * necessary to remove the overlaps before generating the SDF. + * + */ + static FT_Error + sdf_generate_with_overlaps( SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_Int num_contours; /* total number of contours */ + FT_Int i, j; /* iterators */ + FT_Int width, rows; /* width and rows of the bitmap */ + FT_Bitmap* bitmaps; /* separate bitmaps for contours */ + + SDF_Contour* contour; /* temporary variable to iterate */ + SDF_Contour* temp_contour; /* temporary contour */ + SDF_Contour* head; /* head of the contour list */ + SDF_Shape temp_shape; /* temporary shape */ + + FT_Memory memory; /* to allocate memory */ + FT_SDFFormat* t; /* target bitmap buffer */ + FT_Bool flip_sign; /* flip sign? */ + + /* orientation of all the separate contours */ + SDF_Contour_Orientation* orientations; + + + bitmaps = NULL; + orientations = NULL; + head = NULL; + + if ( !shape || !bitmap || !shape->memory ) + return FT_THROW( Invalid_Argument ); + + /* Disable `flip_sign` to avoid extra complication */ + /* during the combination phase. */ + flip_sign = internal_params.flip_sign; + internal_params.flip_sign = 0; + + contour = shape->contours; + memory = shape->memory; + temp_shape.memory = memory; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + num_contours = 0; + + /* find the number of contours in the shape */ + while ( contour ) + { + num_contours++; + contour = contour->next; + } + + /* allocate the bitmaps to generate SDF for separate contours */ + if ( FT_ALLOC( bitmaps, + (FT_UInt)num_contours * sizeof ( *bitmaps ) ) ) + goto Exit; + + /* allocate array to hold orientation for all contours */ + if ( FT_ALLOC( orientations, + (FT_UInt)num_contours * sizeof ( *orientations ) ) ) + goto Exit; + + contour = shape->contours; + + /* Iterate over all contours and generate SDF separately. */ + for ( i = 0; i < num_contours; i++ ) + { + /* initialize the corresponding bitmap */ + FT_Bitmap_Init( &bitmaps[i] ); + + bitmaps[i].width = bitmap->width; + bitmaps[i].rows = bitmap->rows; + bitmaps[i].pitch = bitmap->pitch; + bitmaps[i].num_grays = bitmap->num_grays; + bitmaps[i].pixel_mode = bitmap->pixel_mode; + + /* allocate memory for the buffer */ + if ( FT_ALLOC( bitmaps[i].buffer, + bitmap->rows * (FT_UInt)bitmap->pitch ) ) + goto Exit; + + /* determine the orientation */ + orientations[i] = get_contour_orientation( contour ); + + /* The `overload_sign` property is specific to */ + /* `sdf_generate_bounding_box`. This basically */ + /* overloads the default sign of the outside */ + /* pixels, which is necessary for */ + /* counter-clockwise contours. */ + if ( orientations[i] == SDF_ORIENTATION_CCW && + internal_params.orientation == FT_ORIENTATION_FILL_RIGHT ) + internal_params.overload_sign = 1; + else if ( orientations[i] == SDF_ORIENTATION_CW && + internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + internal_params.overload_sign = 1; + else + internal_params.overload_sign = 0; + + /* Make `contour->next` NULL so that there is */ + /* one contour in the list. Also hold the next */ + /* contour in a temporary variable so as to */ + /* restore the original value. */ + temp_contour = contour->next; + contour->next = NULL; + + /* Use `temp_shape` to hold the new contour. */ + /* Now, `temp_shape` has only one contour. */ + temp_shape.contours = contour; + + /* finally generate the SDF */ + FT_CALL( sdf_generate_subdivision( internal_params, + &temp_shape, + spread, + &bitmaps[i] ) ); + + /* Restore the original `next` variable. */ + contour->next = temp_contour; + + /* Since `split_sdf_shape` deallocated the original */ + /* contours list we need to assign the new value to */ + /* the shape's contour. */ + temp_shape.contours->next = head; + head = temp_shape.contours; + + /* Simply flip the orientation in case of post-script fonts */ + /* so as to avoid modificatons in the combining phase. */ + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + { + if ( orientations[i] == SDF_ORIENTATION_CW ) + orientations[i] = SDF_ORIENTATION_CCW; + else if ( orientations[i] == SDF_ORIENTATION_CCW ) + orientations[i] = SDF_ORIENTATION_CW; + } + + contour = contour->next; + } + + /* assign the new contour list to `shape->contours` */ + shape->contours = head; + + /* cast the output bitmap buffer */ + t = (FT_SDFFormat*)bitmap->buffer; + + /* Iterate over all pixels and combine all separate */ + /* contours. These are the rules for combining: */ + /* */ + /* (1) For all clockwise contours, compute the largest */ + /* value. Name this as `val_c`. */ + /* (2) For all counter-clockwise contours, compute the */ + /* smallest value. Name this as `val_ac`. */ + /* (3) Now, finally use the smaller value of `val_c' */ + /* and `val_ac'. */ + for ( j = 0; j < rows; j++ ) + { + for ( i = 0; i < width; i++ ) + { + FT_Int id = j * width + i; /* index of current pixel */ + FT_Int c; /* contour iterator */ + + FT_SDFFormat val_c = 0; /* max clockwise value */ + FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */ + + + /* iterate through all the contours */ + for ( c = 0; c < num_contours; c++ ) + { + /* current contour value */ + FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id]; + + + if ( orientations[c] == SDF_ORIENTATION_CW ) + val_c = FT_MAX( val_c, temp ); /* clockwise */ + else + val_ac = FT_MIN( val_ac, temp ); /* counter-clockwise */ + } + + /* Finally find the smaller of the two and assign to output. */ + /* Also apply `flip_sign` if set. */ + t[id] = FT_MIN( val_c, val_ac ); + + if ( flip_sign ) + t[id] = invert_sign( t[id] ); + } + } + + Exit: + /* deallocate orientations array */ + if ( orientations ) + FT_FREE( orientations ); + + /* deallocate temporary bitmaps */ + if ( bitmaps ) + { + if ( num_contours == 0 ) + error = FT_THROW( Raster_Corrupted ); + else + { + for ( i = 0; i < num_contours; i++ ) + FT_FREE( bitmaps[i].buffer ); + + FT_FREE( bitmaps ); + } + } + + /* restore the `flip_sign` property */ + internal_params.flip_sign = flip_sign; + + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + sdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* SDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + SDF_PRaster* araster = (SDF_PRaster*)araster_; + + + FT_Error error; + SDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + sdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static FT_Error + sdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + static FT_Error + sdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + SDF_TRaster* sdf_raster = (SDF_TRaster*)raster; + FT_Outline* outline = NULL; + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + FT_Memory memory = NULL; + SDF_Shape* shape = NULL; + SDF_Params internal_params; + + + /* check for valid arguments */ + if ( !sdf_raster || !sdf_params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + outline = (FT_Outline*)sdf_params->root.source; + + /* check whether outline is valid */ + if ( !outline ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* if the outline is empty, return */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + goto Exit; + + /* check whether the outline has valid fields */ + if ( !outline->contours || !outline->points ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "sdf_raster_render:" + " The `spread' field of `SDF_Raster_Params' is invalid,\n" )); + FT_TRACE0(( " " + " the value of this field must be within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params' instead of\n" )); + FT_TRACE0(( " " + " the default `FT_Raster_Params' while calling\n" )); + FT_TRACE0(( " " + " this function and set the fields properly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = sdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "sdf_raster_render:" + " Raster not setup properly,\n" )); + FT_TRACE0(( " " + " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* set up the parameters */ + internal_params.orientation = FT_Outline_Get_Orientation( outline ); + internal_params.flip_sign = sdf_params->flip_sign; + internal_params.flip_y = sdf_params->flip_y; + internal_params.overload_sign = 0; + + FT_CALL( sdf_shape_new( memory, &shape ) ); + + FT_CALL( sdf_outline_decompose( outline, shape ) ); + + if ( sdf_params->overlaps ) + FT_CALL( sdf_generate_with_overlaps( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + else + FT_CALL( sdf_generate_subdivision( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + + if ( shape ) + sdf_shape_done( &shape ); + + Exit: + return error; + } + + + static void + sdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((SDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_sdf_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) sdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) sdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)sdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) sdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) sdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdf.h b/Dependencies/freetype/freetype/src/sdf/ftsdf.h new file mode 100644 index 00000000..25a0a13b --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdf.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * + * ftsdf.h + * + * Signed Distance Field support (specification). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDF_H_ +#define FTSDF_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + +/* common properties and function */ +#include "ftsdfcommon.h" + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @struct: + * SDF_Raster_Params + * + * @description: + * This struct must be passed to the raster render function + * @FT_Raster_RenderFunc instead of @FT_Raster_Params because the + * rasterizer requires some additional information to render properly. + * + * @fields: + * root :: + * The native raster parameters structure. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true maked the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties are valid for both the 'sdf' and 'bsdf' renderers; the + * exception is `overlaps`, which gets ignored by the 'bsdf' renderer. + * + */ + typedef struct SDF_Raster_Params_ + { + FT_Raster_Params root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Raster_Params; + + + /* rasterizer to convert outline to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_sdf_raster; + + /* rasterizer to convert bitmap to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_bitmap_sdf_raster; + +FT_END_HEADER + +#endif /* FTSDF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.c b/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.c new file mode 100644 index 00000000..6b2cf7df --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * ftsdfcommon.c + * + * Auxiliary data for Signed Distance Field support (body). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "ftsdf.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * format and sign manipulating functions + * + */ + + /* + * Convert 16.16 fixed-point values to the desired output format. + * In this case we reduce 16.16 fixed-point values to normalized + * 8-bit values. + * + * The `max_value` in the parameter is the maximum value in the + * distance field map and is equal to the spread. We normalize + * the distances using this value instead of computing the maximum + * value for the entire bitmap. + * + * You can use this function to map the 16.16 signed values to any + * format required. Do note that the output buffer is 8-bit, so only + * use an 8-bit format for `FT_SDFFormat`, or increase the buffer size in + * `ftsdfrend.c`. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ) + { + FT_SDFFormat out; + FT_16D16 udist; + + + /* normalize the distance values */ + dist = FT_DivFix( dist, max_value ); + + udist = dist < 0 ? -dist : dist; + + /* Reduce the distance values to 8 bits. */ + /* */ + /* Since +1/-1 in 16.16 takes the 16th bit, we right-shift */ + /* the number by 9 to make it fit into the 7-bit range. */ + /* */ + /* One bit is reserved for the sign. */ + udist >>= 9; + + /* Since `char` can only store a maximum positive value */ + /* of 127 we need to make sure it does not wrap around and */ + /* give a negative value. */ + if ( dist > 0 && udist > 127 ) + udist = 127; + if ( dist < 0 && udist > 128 ) + udist = 128; + + /* Output the data; negative values are from [0, 127] and positive */ + /* from [128, 255]. One important thing is that negative values */ + /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */ + /* More on that in `freetype.h` near the documentation of */ + /* `FT_RENDER_MODE_SDF`. */ + out = dist < 0 ? 128 - (FT_SDFFormat)udist + : (FT_SDFFormat)udist + 128; + + return out; + } + + + /* + * Invert the signed distance packed into the corresponding format. + * So if the values are negative they will become positive in the + * chosen format. + * + * [Note]: This function should only be used after converting the + * 16.16 signed distance values to `FT_SDFFormat`. If that + * conversion has not been done, then simply invert the sign + * and use the above function to pack the values. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ) + { + return 255 - dist; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.h b/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.h new file mode 100644 index 00000000..d0f623f9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdfcommon.h @@ -0,0 +1,140 @@ +/**************************************************************************** + * + * ftsdfcommon.h + * + * Auxiliary data for Signed Distance Field support (specification). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /**************************************************** + * + * This file contains common functions and properties + * for both the 'sdf' and 'bsdf' renderers. + * + */ + +#ifndef FTSDFCOMMON_H_ +#define FTSDFCOMMON_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * default values (cannot be set individually for each renderer) + * + */ + + /* default spread value */ +#define DEFAULT_SPREAD 8 + /* minimum spread supported by the renderer */ +#define MIN_SPREAD 2 + /* maximum spread supported by the renderer */ +#define MAX_SPREAD 32 + /* pixel size in 26.6 */ +#define ONE_PIXEL ( 1 << 6 ) + + + /************************************************************************** + * + * common definitions (cannot be set individually for each renderer) + * + */ + + /* If this macro is set to 1 the rasterizer uses squared distances for */ + /* computation. It can greatly improve the performance but there is a */ + /* chance of overflow and artifacts. You can safely use it up to a */ + /* pixel size of 128. */ +#ifndef USE_SQUARED_DISTANCES +#define USE_SQUARED_DISTANCES 0 +#endif + + + /************************************************************************** + * + * common macros + * + */ + + /* convert int to 26.6 fixed-point */ +#define FT_INT_26D6( x ) ( x * 64 ) + /* convert int to 16.16 fixed-point */ +#define FT_INT_16D16( x ) ( x * 65536 ) + /* convert 26.6 to 16.16 fixed-point */ +#define FT_26D6_16D16( x ) ( x * 1024 ) + + + /* Convenience macro to call a function; it */ + /* jumps to label `Exit` if an error occurs. */ +#define FT_CALL( x ) do \ + { \ + error = ( x ); \ + if ( error != FT_Err_Ok ) \ + goto Exit; \ + } while ( 0 ) + + + /* + * The macro `VECTOR_LENGTH_16D16` computes either squared distances or + * actual distances, depending on the value of `USE_SQUARED_DISTANCES`. + * + * By using squared distances the performance can be greatly improved but + * there is a risk of overflow. + */ +#if USE_SQUARED_DISTANCES +#define VECTOR_LENGTH_16D16( v ) ( FT_MulFix( v.x, v.x ) + \ + FT_MulFix( v.y, v.y ) ) +#else +#define VECTOR_LENGTH_16D16( v ) FT_Vector_Length( &v ) +#endif + + + /************************************************************************** + * + * common typedefs + * + */ + + typedef FT_Vector FT_26D6_Vec; /* with 26.6 fixed-point components */ + typedef FT_Vector FT_16D16_Vec; /* with 16.16 fixed-point components */ + + typedef FT_Int32 FT_16D16; /* 16.16 fixed-point representation */ + typedef FT_Int32 FT_26D6; /* 26.6 fixed-point representation */ + typedef FT_Byte FT_SDFFormat; /* format to represent SDF data */ + + typedef FT_BBox FT_CBox; /* control box of a curve */ + + +#define square_root( x ) (FT_16D16)FT_SqrtFixed( (FT_UInt32)( x ) ) + + FT_LOCAL( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ); + + FT_LOCAL( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ); + + +FT_END_HEADER + +#endif /* FTSDFCOMMON_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdferrs.h b/Dependencies/freetype/freetype/src/sdf/ftsdferrs.h new file mode 100644 index 00000000..5af873fa --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdferrs.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftsdferrs.h + * + * Signed Distance Field error codes (specification only). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDFERRS_H_ +#define FTSDFERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Sdf_Err_ +#define FT_ERR_BASE FT_Mod_Err_Sdf + +#include + +#endif /* FTSDFERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdfrend.c b/Dependencies/freetype/freetype/src/sdf/ftsdfrend.c new file mode 100644 index 00000000..d3324678 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdfrend.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * ftsdfrend.c + * + * Signed Distance Field renderer interface (body). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include +#include "ftsdfrend.h" +#include "ftsdf.h" + +#include "ftsdferrs.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sdf + + + /************************************************************************** + * + * macros and default property values + * + */ +#define SDF_RENDERER( rend ) ( (SDF_Renderer)rend ) + + + /************************************************************************** + * + * for setting properties + * + */ + + /* property setter function */ + static FT_Error + sdf_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + FT_UNUSED( value_is_string ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + if ( val > MAX_SPREAD || val < MIN_SPREAD ) + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " the `spread' property can have a value\n" )); + FT_TRACE0(( " " + " within range [%d, %d] (value provided: %d)\n", + MIN_SPREAD, MAX_SPREAD, val )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + render->spread = (FT_UInt)val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `spread' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_sign = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_sign' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_y = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_y' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Bool val = *(const FT_Bool*)value; + + + render->overlaps = val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `overlaps' to %d\n", val )); + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + Exit: + return error; + } + + + /* property getter function */ + static FT_Error + sdf_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_UInt* val = (FT_UInt*)value; + + + *val = render->spread; + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_sign; + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_y; + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->overlaps; + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_get:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + sdf_service_properties, + + (FT_Properties_SetFunc)sdf_property_set, /* set_property */ + (FT_Properties_GetFunc)sdf_property_get ) /* get_property */ + + + FT_DEFINE_SERVICEDESCREC1( + sdf_services, + + FT_SERVICE_ID_PROPERTIES, &sdf_service_properties ) + + + static FT_Module_Interface + ft_sdf_requester( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sdf_services, module_interface ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OUTLINE TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + ft_sdf_init( FT_Module module ) /* SDF_Renderer */ + { + SDF_Renderer sdf_render = SDF_RENDERER( module ); + + + sdf_render->spread = DEFAULT_SPREAD; + sdf_render->flip_sign = 0; + sdf_render->flip_y = 0; + sdf_render->overlaps = 0; + + return FT_Err_Ok; + } + + + static void + ft_sdf_done( FT_Module module ) + { + FT_UNUSED( module ); + } + + + /* generate signed distance field from a glyph's slot image */ + static FT_Error + ft_sdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = NULL; + FT_Renderer render = NULL; + + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* deallocate the previously allocated bitmap */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* preset the bitmap using the glyph's outline; */ + /* the sdf bitmap is similar to an anti-aliased bitmap */ + /* with a slightly bigger size and different pixel mode */ + if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* the padding will simply be equal to the `spread' */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply the padding; will be in all the directions */ + bitmap->rows += y_pad * 2; + bitmap->width += x_pad * 2; + + /* ignore the pitch, pixel mode and set custom */ + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->pitch = (int)( bitmap->width ); + bitmap->num_grays = 255; + + /* allocate new buffer */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + x_shift = 64 * -slot->bitmap_left; + y_shift = 64 * -slot->bitmap_top; + y_shift += 64 * (FT_Int)bitmap->rows; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + /* set up parameters */ + params.root.target = bitmap; + params.root.source = outline; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + params.overlaps = sdf_module->overlaps; + + /* render the outline */ + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + /* transform the outline back to the original state */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + Exit: + if ( !error ) + { + /* the glyph is successfully rendered to a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + } + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + return error; + } + + + /* transform the glyph using matrix and/or delta */ + static FT_Error + ft_sdf_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the control box of a glyph's outline */ + static void + ft_sdf_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* set render specific modes or attributes */ + static FT_Error + ft_sdf_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* pass it to the rasterizer */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + FT_DEFINE_RENDERER( + ft_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "sdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_sdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_sdf_raster /* raster_class */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** BITMAP TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /* generate signed distance field from glyph's bitmap */ + static FT_Error + ft_bsdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Bitmap* bitmap = &slot->bitmap; + FT_Renderer render = NULL; + FT_Bitmap target; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + /* initialize the bitmap in case any error occurs */ + FT_Bitmap_Init( &target ); + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + if ( origin ) + { + FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* Do not generate SDF if the bitmap is not owned by the */ + /* glyph: it might be that the source buffer is already freed. */ + if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_ERROR(( "ft_bsdf_render: can't generate SDF from" + " unowned source bitmap\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_Bitmap_New( &target ); + + /* padding will simply be equal to `spread` */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply padding, which extends to all directions */ + target.rows = bitmap->rows + y_pad * 2; + target.width = bitmap->width + x_pad * 2; + + /* set up the target bitmap */ + target.pixel_mode = FT_PIXEL_MODE_GRAY; + target.pitch = (int)( target.width ); + target.num_grays = 255; + + if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) ) + goto Exit; + + /* set up parameters */ + params.root.target = ⌖ + params.root.source = bitmap; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + Exit: + if ( !error ) + { + /* the glyph is successfully converted to a SDF */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( bitmap->buffer ); + + slot->bitmap = target; + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + if ( target.buffer ) + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + else if ( target.buffer ) + FT_FREE( target.buffer ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_bitmap_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "bsdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Renderer_RenderFunc) ft_bsdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_bitmap_sdf_raster /* raster_class */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/ftsdfrend.h b/Dependencies/freetype/freetype/src/sdf/ftsdfrend.h new file mode 100644 index 00000000..2ea6f868 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/ftsdfrend.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * + * ftsdfrend.h + * + * Signed Distance Field renderer interface (specification). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSDFREND_H_ +#define FTSDFREND_H_ + +#include +#include +#include + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * SDF_Renderer_Module + * + * @description: + * This struct extends the native renderer struct `FT_RendererRec`. It + * is basically used to store various parameters required by the + * renderer and some additional parameters that can be used to tweak the + * output of the renderer. + * + * @fields: + * root :: + * The native rendere struct. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true makes the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties except `overlaps` are valid for both the 'sdf' and + * 'bsdf' renderers. + * + */ + typedef struct SDF_Renderer_Module_ + { + FT_RendererRec root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Renderer_Module, *SDF_Renderer; + + + /************************************************************************** + * + * @renderer: + * ft_sdf_renderer_class + * + * @description: + * Renderer to convert @FT_Outline to signed distance fields. + * + */ + FT_DECLARE_RENDERER( ft_sdf_renderer_class ) + + + /************************************************************************** + * + * @renderer: + * ft_bitmap_sdf_renderer_class + * + * @description: + * This is not exactly a renderer; it is just a converter that + * transforms bitmaps to signed distance fields. + * + * @note: + * This is not a separate module, it is part of the 'sdf' module. + * + */ + FT_DECLARE_RENDERER( ft_bitmap_sdf_renderer_class ) + + +FT_END_HEADER + +#endif /* FTSDFREND_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sdf/sdf.c b/Dependencies/freetype/freetype/src/sdf/sdf.c new file mode 100644 index 00000000..6045b833 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sdf/sdf.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * sdf.c + * + * FreeType Signed Distance Field renderer module component (body only). + * + * Copyright (C) 2020-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftsdfrend.c" +#include "ftsdfcommon.c" +#include "ftbsdf.c" +#include "ftsdf.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/pngshim.c b/Dependencies/freetype/freetype/src/sfnt/pngshim.c new file mode 100644 index 00000000..76181568 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/pngshim.c @@ -0,0 +1,462 @@ +/**************************************************************************** + * + * pngshim.c + * + * PNG Bitmap glyph support. + * + * Copyright (C) 2013-2024 by + * Google, Inc. + * Written by Stuart Gill and Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#if defined( TT_CONFIG_OPTION_EMBEDDED_BITMAPS ) && \ + defined( FT_CONFIG_OPTION_USE_PNG ) + + /* We always include , so make libpng shut up! */ +#define PNG_SKIP_SETJMP_CHECK 1 +#include +#include "pngshim.h" + +#include "sferrors.h" + + + /* This code is freely based on cairo-png.c. There's so many ways */ + /* to call libpng, and the way cairo does it is defacto standard. */ + + static unsigned int + multiply_alpha( unsigned int alpha, + unsigned int color ) + { + unsigned int temp = alpha * color + 0x80; + + + return ( temp + ( temp >> 8 ) ) >> 8; + } + + + /* Premultiplies data and converts RGBA bytes => BGRA. */ + static void + premultiply_data( png_structp png, + png_row_infop row_info, + png_bytep data ) + { + unsigned int i = 0, limit; + + /* The `vector_size' attribute was introduced in gcc 3.1, which */ + /* predates clang; the `__BYTE_ORDER__' preprocessor symbol was */ + /* introduced in gcc 4.6 and clang 3.2, respectively. */ + /* `__builtin_shuffle' for gcc was introduced in gcc 4.7.0. */ + /* */ + /* Intel compilers do not currently support __builtin_shuffle; */ + + /* The Intel check must be first. */ +#if !defined( __INTEL_COMPILER ) && \ + ( ( defined( __GNUC__ ) && \ + ( ( __GNUC__ >= 5 ) || \ + ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 7 ) ) ) ) || \ + ( defined( __clang__ ) && \ + ( ( __clang_major__ >= 4 ) || \ + ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ + defined( __OPTIMIZE__ ) && \ + defined( __SSE__ ) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +#ifdef __clang__ + /* the clang documentation doesn't cover the two-argument case of */ + /* `__builtin_shufflevector'; however, it is is implemented since */ + /* version 2.8 */ +#define vector_shuffle __builtin_shufflevector +#else +#define vector_shuffle __builtin_shuffle +#endif + + typedef unsigned short v82 __attribute__(( vector_size( 16 ) )); + + + if ( row_info->rowbytes > 15 ) + { + /* process blocks of 16 bytes in one rush, which gives a nice speed-up */ + limit = row_info->rowbytes - 16 + 1; + for ( ; i < limit; i += 16 ) + { + unsigned char* base = &data[i]; + + v82 s, s0, s1, a; + + /* clang <= 3.9 can't apply scalar values to vectors */ + /* (or rather, it needs a different syntax) */ + v82 n0x80 = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + v82 n0xFF = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + v82 n8 = { 8, 8, 8, 8, 8, 8, 8, 8 }; + + v82 ma = { 1, 1, 3, 3, 5, 5, 7, 7 }; + v82 o1 = { 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF }; + v82 m0 = { 1, 0, 3, 2, 5, 4, 7, 6 }; + + + ft_memcpy( &s, base, 16 ); /* RGBA RGBA RGBA RGBA */ + s0 = s & n0xFF; /* R B R B R B R B */ + s1 = s >> n8; /* G A G A G A G A */ + + a = vector_shuffle( s1, ma ); /* A A A A A A A A */ + s1 |= o1; /* G 1 G 1 G 1 G 1 */ + s0 = vector_shuffle( s0, m0 ); /* B R B R B R B R */ + + s0 *= a; + s1 *= a; + s0 += n0x80; + s1 += n0x80; + s0 = ( s0 + ( s0 >> n8 ) ) >> n8; + s1 = ( s1 + ( s1 >> n8 ) ) >> n8; + + s = s0 | ( s1 << n8 ); + ft_memcpy( base, &s, 16 ); + } + } +#endif /* use `vector_size' */ + + FT_UNUSED( png ); + + limit = row_info->rowbytes; + for ( ; i < limit; i += 4 ) + { + unsigned char* base = &data[i]; + unsigned int alpha = base[3]; + + + if ( alpha == 0 ) + base[0] = base[1] = base[2] = base[3] = 0; + + else + { + unsigned int red = base[0]; + unsigned int green = base[1]; + unsigned int blue = base[2]; + + + if ( alpha != 0xFF ) + { + red = multiply_alpha( alpha, red ); + green = multiply_alpha( alpha, green ); + blue = multiply_alpha( alpha, blue ); + } + + base[0] = (unsigned char)blue; + base[1] = (unsigned char)green; + base[2] = (unsigned char)red; + base[3] = (unsigned char)alpha; + } + } + } + + + /* Converts RGBx bytes to BGRA. */ + static void + convert_bytes_to_data( png_structp png, + png_row_infop row_info, + png_bytep data ) + { + unsigned int i; + + FT_UNUSED( png ); + + + for ( i = 0; i < row_info->rowbytes; i += 4 ) + { + unsigned char* base = &data[i]; + unsigned int red = base[0]; + unsigned int green = base[1]; + unsigned int blue = base[2]; + + + base[0] = (unsigned char)blue; + base[1] = (unsigned char)green; + base[2] = (unsigned char)red; + base[3] = 0xFF; + } + } + + + /* Use error callback to avoid png writing to stderr. */ + static void + error_callback( png_structp png, + png_const_charp error_msg ) + { + FT_Error* error = (FT_Error*)png_get_error_ptr( png ); + + FT_UNUSED( error_msg ); + + + *error = FT_THROW( Out_Of_Memory ); +#ifdef PNG_SETJMP_SUPPORTED + ft_longjmp( png_jmpbuf( png ), 1 ); +#endif + /* if we get here, then we have no choice but to abort ... */ + } + + + /* Use warning callback to avoid png writing to stderr. */ + static void + warning_callback( png_structp png, + png_const_charp error_msg ) + { + FT_UNUSED( png ); + FT_UNUSED( error_msg ); + + /* Just ignore warnings. */ + } + + + static void + read_data_from_FT_Stream( png_structp png, + png_bytep data, + png_size_t length ) + { + FT_Error error; + png_voidp p = png_get_io_ptr( png ); + FT_Stream stream = (FT_Stream)p; + + + if ( FT_FRAME_ENTER( length ) ) + { + FT_Error* e = (FT_Error*)png_get_error_ptr( png ); + + + *e = FT_THROW( Invalid_Stream_Read ); + png_error( png, NULL ); + + /* return; (never reached) */ + } + + ft_memcpy( data, stream->cursor, length ); + + FT_FRAME_EXIT(); + } + + + FT_LOCAL_DEF( FT_Error ) + Load_SBit_Png( FT_GlyphSlot slot, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + TT_SBit_Metrics metrics, + FT_Memory memory, + FT_Byte* data, + FT_UInt png_len, + FT_Bool populate_map_and_metrics, + FT_Bool metrics_only ) + { + FT_Bitmap *map = &slot->bitmap; + FT_Error error = FT_Err_Ok; + FT_StreamRec stream; + + png_structp png; + png_infop info; + png_uint_32 imgWidth, imgHeight; + + int bitdepth, color_type, interlace; + FT_Int i; + + /* `rows` gets modified within a 'setjmp' scope; */ + /* we thus need the `volatile` keyword. */ + png_byte* *volatile rows = NULL; + + + if ( x_offset < 0 || + y_offset < 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !populate_map_and_metrics && + ( (FT_UInt)x_offset + metrics->width > map->width || + (FT_UInt)y_offset + metrics->height > map->rows || + pix_bits != 32 || + map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_Stream_OpenMemory( &stream, data, png_len ); + + png = png_create_read_struct( PNG_LIBPNG_VER_STRING, + &error, + error_callback, + warning_callback ); + if ( !png ) + { + error = FT_THROW( Out_Of_Memory ); + goto Exit; + } + + info = png_create_info_struct( png ); + if ( !info ) + { + error = FT_THROW( Out_Of_Memory ); + png_destroy_read_struct( &png, NULL, NULL ); + goto Exit; + } + + if ( ft_setjmp( png_jmpbuf( png ) ) ) + { + error = FT_THROW( Invalid_File_Format ); + goto DestroyExit; + } + + png_set_read_fn( png, &stream, read_data_from_FT_Stream ); + + png_read_info( png, info ); + png_get_IHDR( png, info, + &imgWidth, &imgHeight, + &bitdepth, &color_type, &interlace, + NULL, NULL ); + + if ( error || + ( !populate_map_and_metrics && + ( (FT_Int)imgWidth != metrics->width || + (FT_Int)imgHeight != metrics->height ) ) ) + goto DestroyExit; + + if ( populate_map_and_metrics ) + { + /* reject too large bitmaps similarly to the rasterizer */ + if ( imgHeight > 0x7FFF || imgWidth > 0x7FFF ) + { + error = FT_THROW( Array_Too_Large ); + goto DestroyExit; + } + + metrics->width = (FT_UShort)imgWidth; + metrics->height = (FT_UShort)imgHeight; + + map->width = metrics->width; + map->rows = metrics->height; + map->pixel_mode = FT_PIXEL_MODE_BGRA; + map->pitch = (int)( map->width * 4 ); + map->num_grays = 256; + } + + /* convert palette/gray image to rgb */ + if ( color_type == PNG_COLOR_TYPE_PALETTE ) + png_set_palette_to_rgb( png ); + + /* expand gray bit depth if needed */ + if ( color_type == PNG_COLOR_TYPE_GRAY ) + { +#if PNG_LIBPNG_VER >= 10209 + png_set_expand_gray_1_2_4_to_8( png ); +#else + png_set_gray_1_2_4_to_8( png ); +#endif + } + + /* transform transparency to alpha */ + if ( png_get_valid( png, info, PNG_INFO_tRNS ) ) + png_set_tRNS_to_alpha( png ); + + if ( bitdepth == 16 ) + png_set_strip_16( png ); + + if ( bitdepth < 8 ) + png_set_packing( png ); + + /* convert grayscale to RGB */ + if ( color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) + png_set_gray_to_rgb( png ); + + if ( interlace != PNG_INTERLACE_NONE ) + png_set_interlace_handling( png ); + + png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); + + /* recheck header after setting EXPAND options */ + png_read_update_info( png, info ); + png_get_IHDR( png, info, + &imgWidth, &imgHeight, + &bitdepth, &color_type, &interlace, + NULL, NULL ); + + if ( bitdepth != 8 || + !( color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) + { + error = FT_THROW( Invalid_File_Format ); + goto DestroyExit; + } + + if ( metrics_only ) + goto DestroyExit; + + switch ( color_type ) + { + default: /* Shouldn't happen, but ... */ + case PNG_COLOR_TYPE_RGB_ALPHA: + png_set_read_user_transform_fn( png, premultiply_data ); + break; + + case PNG_COLOR_TYPE_RGB: + /* Humm, this smells. Carry on though. */ + png_set_read_user_transform_fn( png, convert_bytes_to_data ); + break; + } + + if ( populate_map_and_metrics ) + { + /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */ + FT_ULong size = map->rows * (FT_ULong)map->pitch; + + + error = ft_glyphslot_alloc_bitmap( slot, size ); + if ( error ) + goto DestroyExit; + } + + if ( FT_QNEW_ARRAY( rows, imgHeight ) ) + { + error = FT_THROW( Out_Of_Memory ); + goto DestroyExit; + } + + for ( i = 0; i < (FT_Int)imgHeight; i++ ) + rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; + + png_read_image( png, rows ); + + png_read_end( png, info ); + + DestroyExit: + /* even if reading fails with longjmp, rows must be freed */ + FT_FREE( rows ); + png_destroy_read_struct( &png, &info, NULL ); + FT_Stream_Close( &stream ); + + Exit: + return error; + } + +#else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ + + /* ANSI C doesn't like empty source files */ + typedef int pngshim_dummy_; + +#endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/pngshim.h b/Dependencies/freetype/freetype/src/sfnt/pngshim.h new file mode 100644 index 00000000..6e7a5c08 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/pngshim.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * pngshim.h + * + * PNG Bitmap glyph support. + * + * Copyright (C) 2013-2024 by + * Google, Inc. + * Written by Stuart Gill and Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef PNGSHIM_H_ +#define PNGSHIM_H_ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_PNG + + FT_LOCAL( FT_Error ) + Load_SBit_Png( FT_GlyphSlot slot, + FT_Int x_offset, + FT_Int y_offset, + FT_Int pix_bits, + TT_SBit_Metrics metrics, + FT_Memory memory, + FT_Byte* data, + FT_UInt png_len, + FT_Bool populate_map_and_metrics, + FT_Bool metrics_only ); + +#endif + +FT_END_HEADER + +#endif /* PNGSHIM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfdriver.c b/Dependencies/freetype/freetype/src/sfnt/sfdriver.c new file mode 100644 index 00000000..81072207 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfdriver.c @@ -0,0 +1,1384 @@ +/**************************************************************************** + * + * sfdriver.c + * + * High-level SFNT driver interface (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "sfdriver.h" +#include "ttload.h" +#include "sfobjs.h" + +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#include "ttsbit.h" +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#include "ttcolr.h" +#include "ttcpal.h" +#endif + +#ifdef FT_CONFIG_OPTION_SVG +#include "ttsvg.h" +#endif + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#include "ttpost.h" +#endif + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#include +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.h" +#endif + +#include "ttcmap.h" +#include "ttkern.h" +#include "ttmtx.h" + +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfdriver + + + /* + * SFNT TABLE SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + sfnt_load_table( FT_Face face, /* TT_Face */ + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + TT_Face ttface = (TT_Face)face; + + + return tt_face_load_any( ttface, tag, offset, buffer, length ); + } + + + FT_CALLBACK_DEF( void* ) + get_sfnt_table( FT_Face face, /* TT_Face */ + FT_Sfnt_Tag tag ) + { + TT_Face ttface = (TT_Face)face; + + void* table; + + + switch ( tag ) + { + case FT_SFNT_HEAD: + table = &ttface->header; + break; + + case FT_SFNT_HHEA: + table = &ttface->horizontal; + break; + + case FT_SFNT_VHEA: + table = ttface->vertical_info ? &ttface->vertical : NULL; + break; + + case FT_SFNT_OS2: + table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2; + break; + + case FT_SFNT_POST: + table = &ttface->postscript; + break; + + case FT_SFNT_MAXP: + table = &ttface->max_profile; + break; + + case FT_SFNT_PCLT: + table = ttface->pclt.Version ? &ttface->pclt : NULL; + break; + + default: + table = NULL; + } + + return table; + } + + + FT_CALLBACK_DEF( FT_Error ) + sfnt_table_info( FT_Face face, /* TT_Face */ + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ) + { + TT_Face ttface = (TT_Face)face; + + + if ( !offset || !length ) + return FT_THROW( Invalid_Argument ); + + if ( !tag ) + *length = ttface->num_tables; + else + { + if ( idx >= ttface->num_tables ) + return FT_THROW( Table_Missing ); + + *tag = ttface->dir_tables[idx].Tag; + *offset = ttface->dir_tables[idx].Offset; + *length = ttface->dir_tables[idx].Length; + } + + return FT_Err_Ok; + } + + + FT_DEFINE_SERVICE_SFNT_TABLEREC( + sfnt_service_sfnt_table, + + sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */ + get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */ + sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */ + ) + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + sfnt_get_glyph_name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + FT_Error error; + + + error = tt_face_get_ps_name( (TT_Face)face, glyph_index, &gname ); + if ( !error ) + FT_STRCPYN( buffer, gname, buffer_max ); + + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + sfnt_get_name_index( FT_Face face, + const FT_String* glyph_name ) + { + TT_Face ttface = (TT_Face)face; + + FT_UInt i, max_gid = FT_UINT_MAX; + + + if ( face->num_glyphs < 0 ) + return 0; + else if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX ) + max_gid = (FT_UInt)face->num_glyphs; + else + FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08lx\n", + FT_UINT_MAX, face->num_glyphs )); + + for ( i = 0; i < max_gid; i++ ) + { + FT_String* gname; + FT_Error error = tt_face_get_ps_name( ttface, i, &gname ); + + + if ( error ) + continue; + + if ( !ft_strcmp( glyph_name, gname ) ) + return i; + } + + return 0; + } + + + FT_DEFINE_SERVICE_GLYPHDICTREC( + sfnt_service_glyph_dict, + + sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + ) + +#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + /* an array representing allowed ASCII characters in a PS string */ + static const unsigned char sfnt_ps_map[16] = + { + /* 4 0 C 8 */ + 0x00, 0x00, /* 0x00: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0x00, 0x00, /* 0x10: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */ + 0xDE, 0x7C, /* 0x20: 1 1 0 1 1 1 1 0 0 1 1 1 1 1 0 0 */ + 0xFF, 0xAF, /* 0x30: 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 */ + 0xFF, 0xFF, /* 0x40: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0xD7, /* 0x50: 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 */ + 0xFF, 0xFF, /* 0x60: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 */ + 0xFF, 0x57 /* 0x70: 1 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 */ + }; + + + static int + sfnt_is_postscript( int c ) + { + unsigned int cc; + + + if ( c < 0 || c >= 0x80 ) + return 0; + + cc = (unsigned int)c; + + return sfnt_ps_map[cc >> 3] & ( 1 << ( cc & 0x07 ) ); + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* Only ASCII letters and digits are taken for a variation font */ + /* instance's PostScript name. */ + /* */ + /* `ft_isalnum' is a macro, but we need a function here, thus */ + /* this definition. */ + static int + sfnt_is_alphanumeric( int c ) + { + return ft_isalnum( c ); + } + + + /* the implementation of MurmurHash3 is taken and adapted from */ + /* https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp */ + +#define ROTL32( x, r ) ( x << r ) | ( x >> ( 32 - r ) ) + + + static FT_UInt32 + fmix32( FT_UInt32 h ) + { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; + } + + + static void + murmur_hash_3_128( const void* key, + const unsigned int len, + FT_UInt32 seed, + void* out ) + { + const FT_Byte* data = (const FT_Byte*)key; + const int nblocks = (int)len / 16; + + FT_UInt32 h1 = seed; + FT_UInt32 h2 = seed; + FT_UInt32 h3 = seed; + FT_UInt32 h4 = seed; + + const FT_UInt32 c1 = 0x239b961b; + const FT_UInt32 c2 = 0xab0e9789; + const FT_UInt32 c3 = 0x38b34ae5; + const FT_UInt32 c4 = 0xa1e38b93; + + const FT_UInt32* blocks = (const FT_UInt32*)( data + nblocks * 16 ); + + int i; + + + for( i = -nblocks; i; i++ ) + { + FT_UInt32 k1 = blocks[i * 4 + 0]; + FT_UInt32 k2 = blocks[i * 4 + 1]; + FT_UInt32 k3 = blocks[i * 4 + 2]; + FT_UInt32 k4 = blocks[i * 4 + 3]; + + + k1 *= c1; + k1 = ROTL32( k1, 15 ); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL32( h1, 19 ); + h1 += h2; + h1 = h1 * 5 + 0x561ccd1b; + + k2 *= c2; + k2 = ROTL32( k2, 16 ); + k2 *= c3; + h2 ^= k2; + + h2 = ROTL32( h2, 17 ); + h2 += h3; + h2 = h2 * 5 + 0x0bcaa747; + + k3 *= c3; + k3 = ROTL32( k3, 17 ); + k3 *= c4; + h3 ^= k3; + + h3 = ROTL32( h3, 15 ); + h3 += h4; + h3 = h3 * 5 + 0x96cd1c35; + + k4 *= c4; + k4 = ROTL32( k4, 18 ); + k4 *= c1; + h4 ^= k4; + + h4 = ROTL32( h4, 13 ); + h4 += h1; + h4 = h4 * 5 + 0x32ac3b17; + } + + { + const FT_Byte* tail = (const FT_Byte*)( data + nblocks * 16 ); + + FT_UInt32 k1 = 0; + FT_UInt32 k2 = 0; + FT_UInt32 k3 = 0; + FT_UInt32 k4 = 0; + + + switch ( len & 15 ) + { + case 15: + k4 ^= (FT_UInt32)tail[14] << 16; + FALL_THROUGH; + case 14: + k4 ^= (FT_UInt32)tail[13] << 8; + FALL_THROUGH; + case 13: + k4 ^= (FT_UInt32)tail[12]; + k4 *= c4; + k4 = ROTL32( k4, 18 ); + k4 *= c1; + h4 ^= k4; + FALL_THROUGH; + + case 12: + k3 ^= (FT_UInt32)tail[11] << 24; + FALL_THROUGH; + case 11: + k3 ^= (FT_UInt32)tail[10] << 16; + FALL_THROUGH; + case 10: + k3 ^= (FT_UInt32)tail[9] << 8; + FALL_THROUGH; + case 9: + k3 ^= (FT_UInt32)tail[8]; + k3 *= c3; + k3 = ROTL32( k3, 17 ); + k3 *= c4; + h3 ^= k3; + FALL_THROUGH; + + case 8: + k2 ^= (FT_UInt32)tail[7] << 24; + FALL_THROUGH; + case 7: + k2 ^= (FT_UInt32)tail[6] << 16; + FALL_THROUGH; + case 6: + k2 ^= (FT_UInt32)tail[5] << 8; + FALL_THROUGH; + case 5: + k2 ^= (FT_UInt32)tail[4]; + k2 *= c2; + k2 = ROTL32( k2, 16 ); + k2 *= c3; + h2 ^= k2; + FALL_THROUGH; + + case 4: + k1 ^= (FT_UInt32)tail[3] << 24; + FALL_THROUGH; + case 3: + k1 ^= (FT_UInt32)tail[2] << 16; + FALL_THROUGH; + case 2: + k1 ^= (FT_UInt32)tail[1] << 8; + FALL_THROUGH; + case 1: + k1 ^= (FT_UInt32)tail[0]; + k1 *= c1; + k1 = ROTL32( k1, 15 ); + k1 *= c2; + h1 ^= k1; + } + } + + h1 ^= len; + h2 ^= len; + h3 ^= len; + h4 ^= len; + + h1 += h2; + h1 += h3; + h1 += h4; + + h2 += h1; + h3 += h1; + h4 += h1; + + h1 = fmix32( h1 ); + h2 = fmix32( h2 ); + h3 = fmix32( h3 ); + h4 = fmix32( h4 ); + + h1 += h2; + h1 += h3; + h1 += h4; + + h2 += h1; + h3 += h1; + h4 += h1; + + ((FT_UInt32*)out)[0] = h1; + ((FT_UInt32*)out)[1] = h2; + ((FT_UInt32*)out)[2] = h3; + ((FT_UInt32*)out)[3] = h4; + } + + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + typedef int (*char_type_func)( int c ); + + + /* Handling of PID/EID 3/0 and 3/1 is the same. */ +#define IS_WIN( n ) ( (n)->platformID == 3 && \ + ( (n)->encodingID == 1 || (n)->encodingID == 0 ) ) + +#define IS_APPLE( n ) ( (n)->platformID == 1 && \ + (n)->encodingID == 0 ) + + static char* + get_win_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) + { + FT_Error error; + + char* result = NULL; + FT_String* r; + FT_Char* p; + FT_UInt len; + + + if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) ) + return NULL; + + if ( FT_STREAM_SEEK( entry->stringOffset ) || + FT_FRAME_ENTER( entry->stringLength ) ) + goto get_win_string_error; + + r = (FT_String*)result; + p = (FT_Char*)stream->cursor; + + for ( len = entry->stringLength / 2; len > 0; len--, p += 2 ) + { + if ( p[0] == 0 && char_type( p[1] ) ) + *r++ = p[1]; + else + { + if ( report_invalid_characters ) + FT_TRACE0(( "get_win_string:" + " Character 0x%X invalid in PS name string\n", + ((unsigned)p[0])*256 + (unsigned)p[1] )); + continue; + } + } + *r = '\0'; + + FT_FRAME_EXIT(); + + if ( r != result ) + return result; + + get_win_string_error: + FT_FREE( result ); + + entry->stringLength = 0; + entry->stringOffset = 0; + FT_FREE( entry->string ); + + return NULL; + } + + + static char* + get_apple_string( FT_Memory memory, + FT_Stream stream, + TT_Name entry, + char_type_func char_type, + FT_Bool report_invalid_characters ) + { + FT_Error error; + + char* result = NULL; + FT_String* r; + FT_Char* p; + FT_UInt len; + + + if ( FT_QALLOC( result, entry->stringLength + 1 ) ) + return NULL; + + if ( FT_STREAM_SEEK( entry->stringOffset ) || + FT_FRAME_ENTER( entry->stringLength ) ) + goto get_apple_string_error; + + r = (FT_String*)result; + p = (FT_Char*)stream->cursor; + + for ( len = entry->stringLength; len > 0; len--, p++ ) + { + if ( char_type( *p ) ) + *r++ = *p; + else + { + if ( report_invalid_characters ) + FT_TRACE0(( "get_apple_string:" + " Character `%c' (0x%X) invalid in PS name string\n", + *p, *p )); + continue; + } + } + *r = '\0'; + + FT_FRAME_EXIT(); + + if ( r != result ) + return result; + + get_apple_string_error: + FT_FREE( result ); + + entry->stringOffset = 0; + entry->stringLength = 0; + FT_FREE( entry->string ); + + return NULL; + } + + + FT_CALLBACK_DEF( FT_Bool ) + sfnt_get_name_id( TT_Face face, + FT_UShort id, + FT_Int *win, + FT_Int *apple ) + { + FT_Int n; + + + *win = -1; + *apple = -1; + + for ( n = 0; n < face->num_names; n++ ) + { + TT_Name name = face->name_table.names + n; + + + if ( name->nameID == id && name->stringLength > 0 ) + { + if ( IS_WIN( name ) && ( name->languageID == 0x409 || *win == -1 ) ) + *win = n; + + if ( IS_APPLE( name ) && ( name->languageID == 0 || *apple == -1 ) ) + *apple = n; + } + } + + return ( *win >= 0 ) || ( *apple >= 0 ); + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* + The maximum length of an axis value descriptor. + + We need 65536 different values for the decimal fraction; this fits + nicely into five decimal places. Consequently, it consists of + + . the minus sign if the number is negative, + . up to five characters for the digits before the decimal point, + . the decimal point if there is a fractional part, and + . up to five characters for the digits after the decimal point. + + We also need one byte for the leading `_' character and up to four + bytes for the axis tag. + */ +#define MAX_VALUE_DESCRIPTOR_LEN ( 1 + 5 + 1 + 5 + 1 + 4 ) + + + /* the maximum length of PostScript font names */ +#define MAX_PS_NAME_LEN 127 + + + /* + * Find the shortest decimal representation of a 16.16 fixed-point + * number. The function fills `buf' with the result, returning a pointer + * to the position after the representation's last byte. + */ + + static char* + fixed2float( FT_Int fixed, + char* buf ) + { + char* p; + char* q; + char tmp[5]; + + FT_Int int_part; + FT_Int frac_part; + + FT_Int i; + + + p = buf; + + if ( fixed == 0 ) + { + *p++ = '0'; + return p; + } + + if ( fixed < 0 ) + { + *p++ = '-'; + fixed = NEG_INT( fixed ); + } + + int_part = ( fixed >> 16 ) & 0xFFFF; + frac_part = fixed & 0xFFFF; + + /* get digits of integer part (in reverse order) */ + q = tmp; + while ( int_part > 0 ) + { + *q++ = '0' + int_part % 10; + int_part /= 10; + } + + /* copy digits in correct order to buffer */ + while ( q > tmp ) + *p++ = *--q; + + if ( !frac_part ) + return p; + + /* save position of point */ + q = p; + *p++ = '.'; + + /* apply rounding */ + frac_part = frac_part * 10 + 5; + + /* get digits of fractional part */ + for ( i = 0; i < 5; i++ ) + { + *p++ = '0' + (char)( frac_part / 0x10000L ); + + frac_part %= 0x10000L; + if ( !frac_part ) + break; + + frac_part *= 10; + } + + /* + If the remainder stored in `frac_part' (after the last FOR loop) is + smaller than 34480*10, the resulting decimal value minus 0.00001 is + an equivalent representation of `fixed'. + + The above FOR loop always finds the larger of the two values; I + verified this by iterating over all possible fixed-point numbers. + + If the remainder is 17232*10, both values are equally good, and we + take the next even number (following IEEE 754's `round to nearest, + ties to even' rounding rule). + + If the remainder is smaller than 17232*10, the lower of the two + numbers is nearer to the exact result (values 17232 and 34480 were + also found by testing all possible fixed-point values). + + We use this to find a shorter decimal representation. If not ending + with digit zero, we take the representation with less error. + */ + p--; + if ( p - q == 5 ) /* five digits? */ + { + /* take the representation that has zero as the last digit */ + if ( frac_part < 34480 * 10 && + *p == '1' ) + *p = '0'; + + /* otherwise use the one with less error */ + else if ( frac_part == 17232 * 10 && + *p & 1 ) + *p -= 1; + + else if ( frac_part < 17232 * 10 && + *p != '0' ) + *p -= 1; + } + + /* remove trailing zeros */ + while ( *p == '0' ) + *p-- = '\0'; + + return p + 1; + } + + + static const char hexdigits[16] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + + static const char* + sfnt_get_var_ps_name( TT_Face face ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt num_coords; + FT_Fixed* coords; + FT_MM_Var* mm_var; + + FT_Int found, win, apple; + FT_UInt i, j; + + char* result = NULL; + char* p; + + + if ( !face->var_postscript_prefix ) + { + FT_UInt len; + + + /* check whether we have a Variations PostScript Name Prefix */ + found = sfnt_get_name_id( face, + TT_NAME_ID_VARIATIONS_PREFIX, + &win, + &apple ); + if ( !found ) + { + /* otherwise use the typographic family name */ + found = sfnt_get_name_id( face, + TT_NAME_ID_TYPOGRAPHIC_FAMILY, + &win, + &apple ); + } + + if ( !found ) + { + /* according to the 'name' documentation in the OpenType */ + /* specification the font family name is to be used if the */ + /* typographic family name is missing, so let's do that */ + found = sfnt_get_name_id( face, + TT_NAME_ID_FONT_FAMILY, + &win, + &apple ); + } + + if ( !found ) + { + FT_TRACE0(( "sfnt_get_var_ps_name:" + " Can't construct PS name prefix for font instances\n" )); + return NULL; + } + + /* prefer Windows entries over Apple */ + if ( win != -1 ) + result = get_win_string( face->root.memory, + face->name_table.stream, + face->name_table.names + win, + sfnt_is_alphanumeric, + 0 ); + if ( !result && apple != -1 ) + result = get_apple_string( face->root.memory, + face->name_table.stream, + face->name_table.names + apple, + sfnt_is_alphanumeric, + 0 ); + + if ( !result ) + { + FT_TRACE0(( "sfnt_get_var_ps_name:" + " No valid PS name prefix for font instances found\n" )); + /* XXX It probably makes sense to never let this fail */ + /* since an arbitrary prefix should work, too. */ + /* On the other hand, it is very unlikely that */ + /* we ever reach this code at all. */ + return NULL; + } + + len = ft_strlen( result ); + + /* sanitize if necessary; we reserve space for 36 bytes (a 128bit */ + /* checksum as a hex number, preceded by `-' and followed by three */ + /* ASCII dots, to be used if the constructed PS name would be too */ + /* long); this is also sufficient for a single instance */ + if ( len > MAX_PS_NAME_LEN - ( 1 + 32 + 3 ) ) + { + len = MAX_PS_NAME_LEN - ( 1 + 32 + 3 ); + result[len] = '\0'; + + FT_TRACE0(( "sfnt_get_var_ps_name:" + " Shortening variation PS name prefix\n" )); + FT_TRACE0(( " " + " to %d characters\n", len )); + } + + face->var_postscript_prefix = result; + face->var_postscript_prefix_len = len; + } + + mm->get_var_blend( FT_FACE( face ), + &num_coords, + &coords, + NULL, + &mm_var ); + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) && + !FT_IS_VARIATION( FT_FACE( face ) ) ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Long instance = ( ( face->root.face_index & 0x7FFF0000L ) >> 16 ) - 1; + FT_UInt psid = mm_var->namedstyle[instance].psid; + + char* ps_name = NULL; + + + /* try first to load the name string with index `postScriptNameID' */ + if ( psid == 6 || + ( psid > 255 && psid < 32768 ) ) + (void)sfnt->get_name( face, (FT_UShort)psid, &ps_name ); + + if ( ps_name ) + { + result = ps_name; + p = result + ft_strlen( result ) + 1; + + goto check_length; + } + else + { + /* otherwise construct a name using `subfamilyNameID' */ + FT_UInt strid = mm_var->namedstyle[instance].strid; + + char* subfamily_name; + char* s; + + + (void)sfnt->get_name( face, (FT_UShort)strid, &subfamily_name ); + + if ( !subfamily_name ) + { + FT_TRACE1(( "sfnt_get_var_ps_name:" + " can't construct named instance PS name;\n" )); + FT_TRACE1(( " " + " trying to construct normal instance PS name\n" )); + goto construct_instance_name; + } + + /* after the prefix we have character `-' followed by the */ + /* subfamily name (using only characters a-z, A-Z, and 0-9) */ + if ( FT_QALLOC( result, face->var_postscript_prefix_len + + 1 + ft_strlen( subfamily_name ) + 1 ) ) + return NULL; + + ft_strcpy( result, face->var_postscript_prefix ); + + p = result + face->var_postscript_prefix_len; + *p++ = '-'; + + s = subfamily_name; + while ( *s ) + { + if ( ft_isalnum( *s ) ) + *p++ = *s; + s++; + } + *p++ = '\0'; + + FT_FREE( subfamily_name ); + } + } + else + { + FT_Var_Axis* axis; + + + construct_instance_name: + axis = mm_var->axis; + + if ( FT_QALLOC( result, + face->var_postscript_prefix_len + + num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) + return NULL; + + p = result; + + ft_strcpy( p, face->var_postscript_prefix ); + p += face->var_postscript_prefix_len; + + for ( i = 0; i < num_coords; i++, coords++, axis++ ) + { + char t; + + + /* omit axis value descriptor if it is identical */ + /* to the default axis value */ + if ( *coords == axis->def ) + continue; + + *p++ = '_'; + p = fixed2float( *coords, p ); + + t = (char)( axis->tag >> 24 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)( axis->tag >> 16 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)( axis->tag >> 8 ); + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + t = (char)axis->tag; + if ( t != ' ' && ft_isalnum( t ) ) + *p++ = t; + } + *p++ = '\0'; + } + + check_length: + if ( p - result > MAX_PS_NAME_LEN ) + { + /* the PS name is too long; replace the part after the prefix with */ + /* a checksum; we use MurmurHash 3 with a hash length of 128 bit */ + + FT_UInt32 seed = 123456789; + + FT_UInt32 hash[4]; + FT_UInt32* h; + + + murmur_hash_3_128( result, p - result, seed, hash ); + + p = result + face->var_postscript_prefix_len; + *p++ = '-'; + + /* we convert the hash value to hex digits from back to front */ + p += 32 + 3; + h = hash + 3; + + *p-- = '\0'; + *p-- = '.'; + *p-- = '.'; + *p-- = '.'; + + for ( i = 0; i < 4; i++, h-- ) + { + FT_UInt32 v = *h; + + + for ( j = 0; j < 8; j++ ) + { + *p-- = hexdigits[v & 0xF]; + v >>= 4; + } + } + } + + return result; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + FT_CALLBACK_DEF( const char* ) + sfnt_get_ps_name( FT_Face face ) /* TT_Face */ + { + TT_Face ttface = (TT_Face)face; + + FT_Int found, win, apple; + const char* result = NULL; + + + if ( ttface->postscript_name ) + return ttface->postscript_name; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( ttface->blend && + ( FT_IS_NAMED_INSTANCE( face ) || + FT_IS_VARIATION( face ) ) ) + { + ttface->postscript_name = sfnt_get_var_ps_name( ttface ); + return ttface->postscript_name; + } +#endif + + /* scan the name table to see whether we have a Postscript name here, */ + /* either in Macintosh or Windows platform encodings */ + found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple ); + if ( !found ) + return NULL; + + /* prefer Windows entries over Apple */ + if ( win != -1 ) + result = get_win_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + win, + sfnt_is_postscript, + 1 ); + if ( !result && apple != -1 ) + result = get_apple_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + apple, + sfnt_is_postscript, + 1 ); + + ttface->postscript_name = result; + + return result; + } + + + FT_DEFINE_SERVICE_PSFONTNAMEREC( + sfnt_service_ps_name, + + sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ + ) + + + /* + * TT CMAP INFO + */ + FT_DEFINE_SERVICE_TTCMAPSREC( + tt_service_get_cmap_info, + + tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ + ) + + +#ifdef TT_CONFIG_OPTION_BDF + + static FT_Error + sfnt_get_charset_id( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_PropertyRec encoding, registry; + FT_Error error; + + + /* XXX: I don't know whether this is correct, since + * tt_face_find_bdf_prop only returns something correct if we have + * previously selected a size that is listed in the BDF table. + * Should we change the BDF table format to include single offsets + * for `CHARSET_REGISTRY' and `CHARSET_ENCODING'? + */ + error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry ); + if ( !error ) + { + error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding ); + if ( !error ) + { + if ( registry.type == BDF_PROPERTY_TYPE_ATOM && + encoding.type == BDF_PROPERTY_TYPE_ATOM ) + { + *acharset_encoding = encoding.u.atom; + *acharset_registry = registry.u.atom; + } + else + error = FT_THROW( Invalid_Argument ); + } + } + + return error; + } + + + FT_DEFINE_SERVICE_BDFRec( + sfnt_service_bdf, + + sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */ + tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */ + ) + + +#endif /* TT_CONFIG_OPTION_BDF */ + + + /* + * SERVICE LIST + */ + +#if defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES && defined TT_CONFIG_OPTION_BDF + FT_DEFINE_SERVICEDESCREC5( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &sfnt_service_glyph_dict, + FT_SERVICE_ID_BDF, &sfnt_service_bdf, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#elif defined TT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_DEFINE_SERVICEDESCREC4( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &sfnt_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#elif defined TT_CONFIG_OPTION_BDF + FT_DEFINE_SERVICEDESCREC4( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_BDF, &sfnt_service_bdf, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#else + FT_DEFINE_SERVICEDESCREC3( + sfnt_services, + + FT_SERVICE_ID_SFNT_TABLE, &sfnt_service_sfnt_table, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &sfnt_service_ps_name, + FT_SERVICE_ID_TT_CMAP, &tt_service_get_cmap_info ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + sfnt_get_interface( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sfnt_services, module_interface ); + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define PUT_EMBEDDED_BITMAPS( a ) a +#else +#define PUT_EMBEDDED_BITMAPS( a ) NULL +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define PUT_COLOR_LAYERS( a ) a +#else +#define PUT_COLOR_LAYERS( a ) NULL +#endif + +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_SUPPORT( a ) a +#else +#define PUT_SVG_SUPPORT( a ) NULL +#endif + +#define PUT_COLOR_LAYERS_V1( a ) PUT_COLOR_LAYERS( a ) + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#define PUT_PS_NAMES( a ) a +#else +#define PUT_PS_NAMES( a ) NULL +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#define PUT_GPOS_KERNING( a ) a +#else +#define PUT_GPOS_KERNING( a ) NULL +#endif + + FT_DEFINE_SFNT_INTERFACE( + sfnt_interface, + + tt_face_goto_table, /* TT_Loader_GotoTableFunc goto_table */ + + sfnt_init_face, /* TT_Init_Face_Func init_face */ + sfnt_load_face, /* TT_Load_Face_Func load_face */ + sfnt_done_face, /* TT_Done_Face_Func done_face */ + sfnt_get_interface, /* FT_Module_Requester get_interface */ + + tt_face_load_any, /* TT_Load_Any_Func load_any */ + + tt_face_load_head, /* TT_Load_Table_Func load_head */ + tt_face_load_hhea, /* TT_Load_Metrics_Func load_hhea */ + tt_face_load_cmap, /* TT_Load_Table_Func load_cmap */ + tt_face_load_maxp, /* TT_Load_Table_Func load_maxp */ + tt_face_load_os2, /* TT_Load_Table_Func load_os2 */ + tt_face_load_post, /* TT_Load_Table_Func load_post */ + + tt_face_load_name, /* TT_Load_Table_Func load_name */ + tt_face_free_name, /* TT_Free_Table_Func free_name */ + + tt_face_load_kern, /* TT_Load_Table_Func load_kern */ + PUT_GPOS_KERNING( tt_face_load_gpos ), + /* TT_Load_Table_Func load_gpos */ + tt_face_load_gasp, /* TT_Load_Table_Func load_gasp */ + tt_face_load_pclt, /* TT_Load_Table_Func load_init */ + + /* see `ttload.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ), + /* TT_Load_Table_Func load_bhed */ + PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ), + /* TT_Load_SBit_Image_Func load_sbit_image */ + + /* see `ttpost.h' */ + PUT_PS_NAMES( tt_face_get_ps_name ), + /* TT_Get_PS_Name_Func get_psname */ + PUT_PS_NAMES( tt_face_free_ps_names ), + /* TT_Free_Table_Func free_psnames */ + + /* since version 2.1.8 */ + tt_face_get_kerning, /* TT_Face_GetKerningFunc get_kerning */ + + PUT_GPOS_KERNING( tt_face_get_gpos_kerning ), + /* TT_Face_GetKerningFunc get_gpos_kerning */ + + /* since version 2.2 */ + tt_face_load_font_dir, /* TT_Load_Table_Func load_font_dir */ + tt_face_load_hmtx, /* TT_Load_Metrics_Func load_hmtx */ + + /* see `ttsbit.h' and `sfnt.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_sbit ), + /* TT_Load_Table_Func load_eblc */ + PUT_EMBEDDED_BITMAPS( tt_face_free_sbit ), + /* TT_Free_Table_Func free_eblc */ + + PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), + /* TT_Set_SBit_Strike_Func set_sbit_strike */ + PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), + /* TT_Load_Strike_Metrics_Func load_strike_metrics */ + + PUT_COLOR_LAYERS( tt_face_load_cpal ), + /* TT_Load_Table_Func load_cpal */ + PUT_COLOR_LAYERS( tt_face_load_colr ), + /* TT_Load_Table_Func load_colr */ + PUT_COLOR_LAYERS( tt_face_free_cpal ), + /* TT_Free_Table_Func free_cpal */ + PUT_COLOR_LAYERS( tt_face_free_colr ), + /* TT_Free_Table_Func free_colr */ + PUT_COLOR_LAYERS( tt_face_palette_set ), + /* TT_Set_Palette_Func set_palette */ + PUT_COLOR_LAYERS( tt_face_get_colr_layer ), + /* TT_Get_Colr_Layer_Func get_colr_layer */ + + PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ), + /* TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ), + /* TT_Get_Color_Glyph_ClipBox_Func get_clipbox */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ), + /* TT_Get_Paint_Layers_Func get_paint_layers */ + PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ), + /* TT_Get_Paint get_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint ), + /* TT_Get_Colorline_Stops_Func get_colorline_stops */ + + PUT_COLOR_LAYERS( tt_face_colr_blend_layer ), + /* TT_Blend_Colr_Func colr_blend */ + + tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ + + tt_face_get_name, /* TT_Get_Name_Func get_name */ + sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */ + + PUT_SVG_SUPPORT( tt_face_load_svg ), + /* TT_Load_Table_Func load_svg */ + PUT_SVG_SUPPORT( tt_face_free_svg ), + /* TT_Free_Table_Func free_svg */ + PUT_SVG_SUPPORT( tt_face_load_svg_doc ) + /* TT_Load_Svg_Doc_Func load_svg_doc */ + ) + + + FT_DEFINE_MODULE( + sfnt_module_class, + + 0, /* not a font driver or renderer */ + sizeof ( FT_ModuleRec ), + + "sfnt", /* driver name */ + 0x10000L, /* driver version 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or higher */ + + (const void*)&sfnt_interface, /* module specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + sfnt_get_interface /* FT_Module_Requester get_interface */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfdriver.h b/Dependencies/freetype/freetype/src/sfnt/sfdriver.h new file mode 100644 index 00000000..6f71489f --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfdriver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * sfdriver.h + * + * High-level SFNT driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFDRIVER_H_ +#define SFDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_MODULE( sfnt_module_class ) + +FT_END_HEADER + +#endif /* SFDRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sferrors.h b/Dependencies/freetype/freetype/src/sfnt/sferrors.h new file mode 100644 index 00000000..d3ca1d9a --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sferrors.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * sferrors.h + * + * SFNT error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the SFNT error enumeration constants. + * + */ + +#ifndef SFERRORS_H_ +#define SFERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX SFNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_SFNT + +#include + +#endif /* SFERRORS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfnt.c b/Dependencies/freetype/freetype/src/sfnt/sfnt.c new file mode 100644 index 00000000..52411feb --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfnt.c @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * sfnt.c + * + * Single object library component. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "pngshim.c" +#include "sfdriver.c" +#include "sfobjs.c" +#include "sfwoff.c" +#include "sfwoff2.c" +#include "ttbdf.c" +#include "ttcmap.c" +#include "ttcolr.c" +#include "ttcpal.c" +#include "ttsvg.c" + +#include "ttgpos.c" +#include "ttkern.c" +#include "ttload.c" +#include "ttmtx.c" +#include "ttpost.c" +#include "ttsbit.c" +#include "woff2tags.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfobjs.c b/Dependencies/freetype/freetype/src/sfnt/sfobjs.c new file mode 100644 index 00000000..6ee4e5e9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfobjs.c @@ -0,0 +1,1552 @@ +/**************************************************************************** + * + * sfobjs.c + * + * SFNT object management (base). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "sfobjs.h" +#include "ttload.h" +#include "ttcmap.h" +#include "ttkern.h" +#include "sfwoff.h" +#include "sfwoff2.h" +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#endif + +#include "sferrors.h" + +#ifdef TT_CONFIG_OPTION_BDF +#include "ttbdf.h" +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.h" +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfobjs + + + + /* convert a UTF-16 name entry to ASCII */ + static FT_String* + tt_name_ascii_from_utf16( TT_Name entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength / 2; + + if ( FT_QNEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = FT_NEXT_USHORT( read ); + + if ( code == 0 ) + break; + + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[n] = 0; + + return string; + } + + + /* convert an Apple Roman or symbol name entry to ASCII */ + static FT_String* + tt_name_ascii_from_other( TT_Name entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + + + len = (FT_UInt)entry->stringLength; + + if ( FT_QNEW_ARRAY( string, len + 1 ) ) + return NULL; + + for ( n = 0; n < len; n++ ) + { + code = *read++; + + if ( code == 0 ) + break; + + if ( code < 32 || code > 127 ) + code = '?'; + + string[n] = (char)code; + } + + string[n] = 0; + + return string; + } + + + typedef FT_String* (*TT_Name_ConvertFunc)( TT_Name entry, + FT_Memory memory ); + + + /* documentation is in sfnt.h */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ) + { + FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + FT_String* result = NULL; + FT_UShort n; + TT_Name rec; + + FT_Int found_apple = -1; + FT_Int found_apple_roman = -1; + FT_Int found_apple_english = -1; + FT_Int found_win = -1; + FT_Int found_unicode = -1; + + FT_Bool is_english = 0; + + TT_Name_ConvertFunc convert; + + + FT_ASSERT( name ); + + rec = face->name_table.names; + for ( n = 0; n < face->num_names; n++, rec++ ) + { + /* According to the OpenType 1.3 specification, only Microsoft or */ + /* Apple platform IDs might be used in the `name' table. The */ + /* `Unicode' platform is reserved for the `cmap' table, and the */ + /* `ISO' one is deprecated. */ + /* */ + /* However, the Apple TrueType specification doesn't say the same */ + /* thing and goes to suggest that all Unicode `name' table entries */ + /* should be coded in UTF-16 (in big-endian format I suppose). */ + /* */ + if ( rec->nameID == nameid && rec->stringLength > 0 ) + { + switch ( rec->platformID ) + { + case TT_PLATFORM_APPLE_UNICODE: + case TT_PLATFORM_ISO: + /* there is `languageID' to check there. We should use this */ + /* field only as a last solution when nothing else is */ + /* available. */ + /* */ + found_unicode = n; + break; + + case TT_PLATFORM_MACINTOSH: + /* This is a bit special because some fonts will use either */ + /* an English language id, or a Roman encoding id, to indicate */ + /* the English version of its font name. */ + /* */ + if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) + found_apple_english = n; + else if ( rec->encodingID == TT_MAC_ID_ROMAN ) + found_apple_roman = n; + break; + + case TT_PLATFORM_MICROSOFT: + /* we only take a non-English name when there is nothing */ + /* else available in the font */ + /* */ + if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) + { + switch ( rec->encodingID ) + { + case TT_MS_ID_SYMBOL_CS: + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_UCS_4: + is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); + found_win = n; + break; + + default: + ; + } + } + break; + + default: + ; + } + } + } + + found_apple = found_apple_roman; + if ( found_apple_english >= 0 ) + found_apple = found_apple_english; + + /* some fonts contain invalid Unicode or Macintosh formatted entries; */ + /* we will thus favor names encoded in Windows formats if available */ + /* (provided it is an English name) */ + /* */ + convert = NULL; + if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) + { + rec = face->name_table.names + found_win; + switch ( rec->encodingID ) + { + /* all Unicode strings are encoded using UTF-16BE */ + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_SYMBOL_CS: + convert = tt_name_ascii_from_utf16; + break; + + case TT_MS_ID_UCS_4: + /* Apparently, if this value is found in a name table entry, it is */ + /* documented as `full Unicode repertoire'. Experience with the */ + /* MsGothic font shipped with Windows Vista shows that this really */ + /* means UTF-16 encoded names (UCS-4 values are only used within */ + /* charmaps). */ + convert = tt_name_ascii_from_utf16; + break; + + default: + ; + } + } + else if ( found_apple >= 0 ) + { + rec = face->name_table.names + found_apple; + convert = tt_name_ascii_from_other; + } + else if ( found_unicode >= 0 ) + { + rec = face->name_table.names + found_unicode; + convert = tt_name_ascii_from_utf16; + } + + if ( rec && convert ) + { + if ( !rec->string ) + { + FT_Stream stream = face->name_table.stream; + + + if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || + FT_STREAM_SEEK( rec->stringOffset ) || + FT_STREAM_READ( rec->string, rec->stringLength ) ) + { + FT_FREE( rec->string ); + rec->stringLength = 0; + result = NULL; + goto Exit; + } + } + + result = convert( rec, memory ); + } + + Exit: + *name = result; + return error; + } + + + static FT_Encoding + sfnt_find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding_ + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + + } TEncoding; + + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, + + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, + + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_PRC, FT_ENCODING_PRC }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } + }; + + const TEncoding *cur, *limit; + + + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + + return FT_ENCODING_NONE; + } + + + /* Fill in face->ttc_header. If the font is not a TTC, it is */ + /* synthesized into a TTC with one offset table. */ + static FT_Error + sfnt_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_instance_index, + FT_Long* woff2_num_faces ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_ULong tag, offset; + + static const FT_Frame_Field ttc_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TTC_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_LONG( version ), + FT_FRAME_LONG( count ), /* this is ULong in the specs */ + FT_FRAME_END + }; + +#ifndef FT_CONFIG_OPTION_USE_BROTLI + FT_UNUSED( face_instance_index ); + FT_UNUSED( woff2_num_faces ); +#endif + + + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_BROTLI ) + retry: +#endif + + offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( tag ) ) + return error; + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + if ( tag == TTAG_wOFF ) + { + FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + error = woff_open_font( stream, face ); + if ( error ) + return error; + + /* Swap out stream and retry! */ + stream = face->root.stream; + goto retry; + } +#endif + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + if ( tag == TTAG_wOF2 ) + { + FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" )); + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + error = woff2_open_font( stream, + face, + face_instance_index, + woff2_num_faces ); + if ( error ) + return error; + + /* Swap out stream and retry! */ + stream = face->root.stream; + goto retry; + } +#endif + + if ( tag != 0x00010000UL && + tag != TTAG_ttcf && + tag != TTAG_OTTO && + tag != TTAG_true && + tag != TTAG_typ1 && + tag != TTAG_0xA5kbd && + tag != TTAG_0xA5lst && + tag != 0x00020000UL ) + { + FT_TRACE2(( " not a font using the SFNT container format\n" )); + return FT_THROW( Unknown_File_Format ); + } + + face->ttc_header.tag = TTAG_ttcf; + + if ( tag == TTAG_ttcf ) + { + FT_Int n; + + + FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); + + if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) + return error; + + FT_TRACE3(( " with %ld subfonts\n", + face->ttc_header.count )); + + if ( face->ttc_header.count == 0 ) + return FT_THROW( Invalid_Table ); + + /* a rough size estimate: let's conservatively assume that there */ + /* is just a single table info in each subfont header (12 + 16*1 = */ + /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ + /* size of the TTC header plus `28*count' bytes for all subfont */ + /* headers */ + if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) + return FT_THROW( Array_Too_Large ); + + /* now read the offsets of each font in the file */ + if ( FT_QNEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + return error; + + if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) + return error; + + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + } + else + { + FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); + + face->ttc_header.version = 1 << 16; + face->ttc_header.count = 1; + + if ( FT_QNEW( face->ttc_header.offsets ) ) + return error; + + face->ttc_header.offsets[0] = offset; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Service sfnt; + FT_Int face_index; + FT_Long woff2_num_faces = 0; + + + /* for now, parameters are unused */ + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + sfnt = (SFNT_Service)face->sfnt; + if ( !sfnt ) + { + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" )); + return FT_THROW( Missing_Module ); + } + + face->sfnt = sfnt; + face->goto_table = sfnt->goto_table; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( !face->mm ) + { + /* we want the MM interface from the `truetype' module only */ + FT_Module tt_module = FT_Get_Module( library, "truetype" ); + + + face->mm = ft_module_get_service( tt_module, + FT_SERVICE_ID_MULTI_MASTERS, + 0 ); + } + + if ( !face->tt_var ) + { + /* we want the metrics variations interface */ + /* from the `truetype' module only */ + FT_Module tt_module = FT_Get_Module( library, "truetype" ); + + + face->tt_var = ft_module_get_service( tt_module, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); + } + + if ( !face->face_var ) + face->face_var = ft_module_get_service( + &face->root.driver->root, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); +#endif + + FT_TRACE2(( "SFNT driver\n" )); + + error = sfnt_open_font( stream, + face, + &face_instance_index, + &woff2_num_faces ); + if ( error ) + return error; + + /* Stream may have changed in sfnt_open_font. */ + stream = face->root.stream; + + FT_TRACE2(( "sfnt_init_face: %p (index %d)\n", + (void *)face, + face_instance_index )); + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* value -(N+1) requests information on index N */ + if ( face_instance_index < 0 && face_index > 0 ) + face_index--; + + if ( face_index >= face->ttc_header.count ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + face_index = 0; + } + + if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) + return error; + + /* check whether we have a valid TrueType file */ + error = sfnt->load_font_dir( face, stream ); + if ( error ) + return error; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + FT_ULong fvar_len; + + FT_ULong version; + FT_ULong offset; + + FT_UShort num_axes; + FT_UShort axis_size; + FT_UShort num_instances; + FT_UShort instance_size; + + FT_Int instance_index; + + FT_Byte* default_values = NULL; + FT_Byte* instance_values = NULL; + + + instance_index = FT_ABS( face_instance_index ) >> 16; + + /* test whether current face is a GX font with named instances */ + if ( face->goto_table( face, TTAG_fvar, stream, &fvar_len ) || + fvar_len < 20 || + FT_READ_ULONG( version ) || + FT_READ_USHORT( offset ) || + FT_STREAM_SKIP( 2 ) /* reserved */ || + FT_READ_USHORT( num_axes ) || + FT_READ_USHORT( axis_size ) || + FT_READ_USHORT( num_instances ) || + FT_READ_USHORT( instance_size ) ) + { + version = 0; + offset = 0; + num_axes = 0; + axis_size = 0; + num_instances = 0; + instance_size = 0; + } + + /* check that the data is bound by the table length */ + if ( version != 0x00010000UL || + axis_size != 20 || + num_axes == 0 || + /* `num_axes' limit implied by 16-bit `instance_size' */ + num_axes > 0x3FFE || + !( instance_size == 4 + 4 * num_axes || + instance_size == 6 + 4 * num_axes ) || + /* `num_instances' limit implied by limited range of name IDs */ + num_instances > 0x7EFF || + offset + + axis_size * num_axes + + instance_size * num_instances > fvar_len ) + num_instances = 0; + else + face->variation_support |= TT_FACE_FLAG_VAR_FVAR; + + /* + * As documented in the OpenType specification, an entry for the + * default instance may be omitted in the named instance table. In + * particular this means that even if there is no named instance + * table in the font we actually do have a named instance, namely the + * default instance. + * + * For consistency, we always want the default instance in our list + * of named instances. If it is missing, we try to synthesize it + * later on. Here, we have to adjust `num_instances' accordingly. + */ + + if ( ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) && + !( FT_QALLOC( default_values, num_axes * 4 ) || + FT_QALLOC( instance_values, num_axes * 4 ) ) ) + { + /* the current stream position is 16 bytes after the table start */ + FT_ULong array_start = FT_STREAM_POS() - 16 + offset; + FT_ULong default_value_offset, instance_offset; + + FT_Byte* p; + FT_UInt i; + + + default_value_offset = array_start + 8; + p = default_values; + + for ( i = 0; i < num_axes; i++ ) + { + (void)FT_STREAM_READ_AT( default_value_offset, p, 4 ); + + default_value_offset += axis_size; + p += 4; + } + + instance_offset = array_start + axis_size * num_axes + 4; + + for ( i = 0; i < num_instances; i++ ) + { + (void)FT_STREAM_READ_AT( instance_offset, + instance_values, + num_axes * 4 ); + + if ( !ft_memcmp( default_values, instance_values, num_axes * 4 ) ) + break; + + instance_offset += instance_size; + } + + /* named instance indices start with value 1 */ + face->var_default_named_instance = i + 1; + + if ( i == num_instances ) + { + /* no default instance in named instance table; */ + /* we thus have to synthesize it */ + num_instances++; + } + } + + FT_FREE( default_values ); + FT_FREE( instance_values ); + + /* we don't support Multiple Master CFFs yet; */ + /* note that `glyf' or `CFF2' have precedence */ + if ( face->goto_table( face, TTAG_glyf, stream, 0 ) && + face->goto_table( face, TTAG_CFF2, stream, 0 ) && + !face->goto_table( face, TTAG_CFF, stream, 0 ) ) + num_instances = 0; + + /* instance indices in `face_instance_index' start with index 1, */ + /* thus `>' and not `>=' */ + if ( instance_index > num_instances ) + { + if ( face_instance_index >= 0 ) + return FT_THROW( Invalid_Argument ); + else + num_instances = 0; + } + + face->root.style_flags = (FT_Long)num_instances << 16; + } +#endif + + face->root.num_faces = face->ttc_header.count; + face->root.face_index = face_instance_index; + + /* `num_faces' for a WOFF2 needs to be handled separately. */ + if ( woff2_num_faces ) + face->root.num_faces = woff2_num_faces; + + return error; + } + + +#define LOAD_( x ) \ + do \ + { \ + FT_TRACE2(( "`" #x "' " )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : FT_ERR_EQ( error, Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + +#define LOADM_( x, vertical ) \ + do \ + { \ + FT_TRACE2(( "`%s" #x "' ", \ + vertical ? "vertical " : "" )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream, vertical ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : FT_ERR_EQ( error, Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) + +#define GET_NAME( id, field ) \ + do \ + { \ + error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ + if ( error ) \ + goto Exit; \ + } while ( 0 ) + + + FT_LOCAL_DEF( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Error psnames_error; +#endif + + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + FT_Bool has_CBLC; + FT_Bool has_CBDT; + FT_Bool has_EBLC; + FT_Bool has_bloc; + FT_Bool has_sbix; + + FT_Bool ignore_typographic_family = FALSE; + FT_Bool ignore_typographic_subfamily = FALSE; + FT_Bool ignore_sbix = FALSE; + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_UNUSED( face_instance_index ); + + + /* Check parameters */ + + { + FT_Int i; + + + for ( i = 0; i < num_params; i++ ) + { + if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_FAMILY ) + ignore_typographic_family = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY ) + ignore_typographic_subfamily = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_SBIX ) + ignore_sbix = TRUE; + } + } + + /* Load tables */ + + /* We now support two SFNT-based bitmapped font formats. They */ + /* are recognized easily as they do not include a `glyf' */ + /* table. */ + /* */ + /* The first format comes from Apple, and uses a table named */ + /* `bhed' instead of `head' to store the font header (using */ + /* the same format). It also doesn't include horizontal and */ + /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ + /* missing). */ + /* */ + /* The other format comes from Microsoft, and is used with */ + /* WinCE/PocketPC. It looks like a standard TTF, except that */ + /* it doesn't contain outlines. */ + /* */ + + FT_TRACE2(( "sfnt_load_face: %p\n", (void *)face )); + FT_TRACE2(( "\n" )); + + /* do we have outlines in there? */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + has_outline = FT_BOOL( face->root.internal->incremental_interface || + tt_face_lookup_table( face, TTAG_glyf ) || + tt_face_lookup_table( face, TTAG_CFF ) || + tt_face_lookup_table( face, TTAG_CFF2 ) ); +#else + has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) || + tt_face_lookup_table( face, TTAG_CFF ) || + tt_face_lookup_table( face, TTAG_CFF2 ) ); +#endif + + /* check which sbit formats are present */ + has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); + has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); + has_EBLC = !face->goto_table( face, TTAG_EBLC, stream, 0 ); + has_bloc = !face->goto_table( face, TTAG_bloc, stream, 0 ); + has_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); + + is_apple_sbit = FALSE; + + if ( ignore_sbix ) + has_sbix = FALSE; + + /* if this font doesn't contain outlines, we try to load */ + /* a `bhed' table */ + if ( !has_outline && sfnt->load_bhed ) + { + LOAD_( bhed ); + is_apple_sbit = FT_BOOL( !error ); + } + + /* load the font header (`head' table) if this isn't an Apple */ + /* sbit font file */ + if ( !is_apple_sbit || has_sbix ) + { + LOAD_( head ); + if ( error ) + goto Exit; + } + + /* Ignore outlines for CBLC/CBDT fonts. */ + if ( has_CBLC || has_CBDT ) + has_outline = FALSE; + + /* OpenType 1.8.2 introduced limits to this value; */ + /* however, they make sense for older SFNT fonts also */ + if ( face->header.Units_Per_EM < 16 || + face->header.Units_Per_EM > 16384 ) + { + error = FT_THROW( Invalid_Table ); + + goto Exit; + } + + /* the following tables are often not present in embedded TrueType */ + /* fonts within PDF documents, so don't check for them. */ + LOAD_( maxp ); + LOAD_( cmap ); + + /* the following tables are optional in PCL fonts -- */ + /* don't check for errors */ + LOAD_( name ); + LOAD_( post ); + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames_error = error; +#endif + + /* do not load the metrics headers and tables if this is an Apple */ + /* sbit font file */ + if ( !is_apple_sbit ) + { + /* load the `hhea' and `hmtx' tables */ + LOADM_( hhea, 0 ); + if ( !error ) + { + LOADM_( hmtx, 0 ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + { + error = FT_THROW( Hmtx_Table_Missing ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hmtx' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = FT_Err_Ok; + } +#endif + } + } + else if ( FT_ERR_EQ( error, Table_Missing ) ) + { + /* No `hhea' table necessary for SFNT Mac fonts. */ + if ( face->format_tag == TTAG_true ) + { + FT_TRACE2(( "This is an SFNT Mac font.\n" )); + + has_outline = 0; + error = FT_Err_Ok; + } + else + { + error = FT_THROW( Horiz_Header_Missing ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* If this is an incrementally loaded font and there are */ + /* overriding metrics, tolerate a missing `hhea' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = FT_Err_Ok; + } +#endif + + } + } + + if ( error ) + goto Exit; + + /* try to load the `vhea' and `vmtx' tables */ + LOADM_( hhea, 1 ); + if ( !error ) + { + LOADM_( hmtx, 1 ); + if ( !error ) + face->vertical_info = 1; + } + + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + LOAD_( os2 ); + if ( error ) + { + /* we treat the table as missing if there are any errors */ + face->os2.version = 0xFFFFU; + } + } + + /* the optional tables */ + + /* embedded bitmap support */ + /* TODO: Replace this clumsy check for all possible sbit tables */ + /* with something better (for example, by passing a parameter */ + /* to suppress 'sbix' loading). */ + if ( sfnt->load_eblc && + ( has_CBLC || has_EBLC || has_bloc || has_sbix ) ) + LOAD_( eblc ); + + /* colored glyph support */ + if ( sfnt->load_cpal ) + { + LOAD_( cpal ); + LOAD_( colr ); + } + + /* OpenType-SVG glyph support */ + if ( sfnt->load_svg ) + LOAD_( svg ); + + /* consider the pclt, kerning, and gasp tables as optional */ + LOAD_( pclt ); + LOAD_( gasp ); + LOAD_( kern ); + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + LOAD_( gpos ); +#endif + + face->root.num_glyphs = face->max_profile.numGlyphs; + + /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ + /* a WWS-only font face. `WWS' stands for `weight', width', and */ + /* `slope', a term used by Microsoft's Windows Presentation */ + /* Foundation (WPF). This flag has been introduced in version */ + /* 1.5 of the OpenType specification (May 2008). */ + + face->root.family_name = NULL; + face->root.style_name = NULL; + if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) + { + if ( !ignore_typographic_family ) + GET_NAME( TYPOGRAPHIC_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + + if ( !ignore_typographic_subfamily ) + GET_NAME( TYPOGRAPHIC_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } + else + { + GET_NAME( WWS_FAMILY, &face->root.family_name ); + if ( !face->root.family_name && !ignore_typographic_family ) + GET_NAME( TYPOGRAPHIC_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + + GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name && !ignore_typographic_subfamily ) + GET_NAME( TYPOGRAPHIC_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + + if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) ) + goto Exit; + } +#endif + + /* now set up root fields */ + { + FT_Face root = &face->root; + FT_Long flags = root->face_flags; + + + /********************************************************************** + * + * Compute face flags. + */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || + face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX || + face->colr || + face->svg ) + flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ + + if ( has_outline == TRUE ) + { + /* by default (and for backward compatibility) we handle */ + /* fonts with an 'sbix' table as bitmap-only */ + if ( has_sbix ) + flags |= FT_FACE_FLAG_SBIX; /* with 'sbix' bitmaps */ + else + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + } + + /* The sfnt driver only supports bitmap fonts natively, thus we */ + /* don't set FT_FACE_FLAG_HINTER. */ + flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ + FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + if ( !psnames_error && + face->postscript.FormatType != 0x00030000L ) + flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + + /* fixed width font? */ + if ( face->postscript.isFixedPitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* vertical information? */ + if ( face->vertical_info ) + flags |= FT_FACE_FLAG_VERTICAL; + + /* kerning available ? */ + if ( TT_FACE_HAS_KERNING( face ) +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + || face->gpos_kerning_available +#endif + ) + flags |= FT_FACE_FLAG_KERNING; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Don't bother to load the tables unless somebody asks for them. */ + /* No need to do work which will (probably) not be used. */ + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; +#endif + + root->face_flags = flags; + + /********************************************************************** + * + * Compute style flags. + */ + + flags = 0; + if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) + { + /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ + /* indicates an oblique font face. This flag has been */ + /* introduced in version 1.5 of the OpenType specification. */ + + if ( face->os2.fsSelection & 512 ) /* bit 9 */ + flags |= FT_STYLE_FLAG_ITALIC; + else if ( face->os2.fsSelection & 1 ) /* bit 0 */ + flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->os2.fsSelection & 32 ) /* bit 5 */ + flags |= FT_STYLE_FLAG_BOLD; + } + else + { + /* this is an old Mac font, use the header field */ + + if ( face->header.Mac_Style & 1 ) + flags |= FT_STYLE_FLAG_BOLD; + + if ( face->header.Mac_Style & 2 ) + flags |= FT_STYLE_FLAG_ITALIC; + } + + root->style_flags |= flags; + + /********************************************************************** + * + * Polish the charmaps. + * + * Try to set the charmap encoding according to the platform & + * encoding ID of each charmap. Emulate Unicode charmap if one + * is missing. + */ + + tt_face_build_cmaps( face ); /* ignore errors */ + + + /* set the encoding fields */ + { + FT_Int m; +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Bool has_unicode = FALSE; +#endif + + + for ( m = 0; m < root->num_charmaps; m++ ) + { + FT_CharMap charmap = root->charmaps[m]; + + + charmap->encoding = sfnt_find_encoding( charmap->platform_id, + charmap->encoding_id ); + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + if ( charmap->encoding == FT_ENCODING_UNICODE || + charmap->encoding == FT_ENCODING_MS_SYMBOL ) /* PUA */ + has_unicode = TRUE; + } + + /* synthesize Unicode charmap if one is missing */ + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + { + FT_CharMapRec cmaprec; + + + cmaprec.face = root; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; + + + error = FT_CMap_New( (FT_CMap_Class)&tt_cmap_unicode_class_rec, + NULL, &cmaprec, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + } + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* + * Now allocate the root array of FT_Bitmap_Size records and + * populate them. Unfortunately, it isn't possible to indicate bit + * depths in the FT_Bitmap_Size record. This is a design error. + */ + { + FT_UInt count; + + + count = face->sbit_num_strikes; + + if ( count > 0 ) + { + FT_Memory memory = face->root.memory; + FT_UShort em_size = face->header.Units_Per_EM; + FT_Short avgwidth = face->os2.xAvgCharWidth; + FT_Size_Metrics metrics; + + FT_UInt* sbit_strike_map = NULL; + FT_UInt strike_idx, bsize_idx; + + + if ( em_size == 0 || face->os2.version == 0xFFFFU ) + { + avgwidth = 1; + em_size = 1; + } + + /* to avoid invalid strike data in the `available_sizes' field */ + /* of `FT_Face', we map `available_sizes' indices to strike */ + /* indices */ + if ( FT_NEW_ARRAY( root->available_sizes, count ) || + FT_QNEW_ARRAY( sbit_strike_map, count ) ) + goto Exit; + + bsize_idx = 0; + for ( strike_idx = 0; strike_idx < count; strike_idx++ ) + { + FT_Bitmap_Size* bsize = root->available_sizes + bsize_idx; + + + error = sfnt->load_strike_metrics( face, strike_idx, &metrics ); + if ( error ) + continue; + + bsize->height = (FT_Short)( metrics.height >> 6 ); + bsize->width = (FT_Short)( + ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); + + bsize->x_ppem = metrics.x_ppem << 6; + bsize->y_ppem = metrics.y_ppem << 6; + + /* assume 72dpi */ + bsize->size = metrics.y_ppem << 6; + + /* only use strikes with valid PPEM values */ + if ( bsize->x_ppem && bsize->y_ppem ) + sbit_strike_map[bsize_idx++] = strike_idx; + } + + /* reduce array size to the actually used elements */ + FT_MEM_QRENEW_ARRAY( sbit_strike_map, count, bsize_idx ); + + /* from now on, all strike indices are mapped */ + /* using `sbit_strike_map' */ + if ( bsize_idx ) + { + face->sbit_strike_map = sbit_strike_map; + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + root->num_fixed_sizes = (FT_Int)bsize_idx; + } + } + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* a font with no bitmaps and no outlines is scalable; */ + /* it has only empty glyphs then */ + if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) + root->face_flags |= FT_FACE_FLAG_SCALABLE; + + + /********************************************************************** + * + * Set up metrics. + */ + if ( FT_IS_SCALABLE( root ) || + FT_HAS_SBIX( root ) ) + { + /* XXX What about if outline header is missing */ + /* (e.g. sfnt wrapped bitmap)? */ + root->bbox.xMin = face->header.xMin; + root->bbox.yMin = face->header.yMin; + root->bbox.xMax = face->header.xMax; + root->bbox.yMax = face->header.yMax; + root->units_per_EM = face->header.Units_Per_EM; + + + /* + * Computing the ascender/descender/height is tricky. + * + * The OpenType specification v1.8.3 says: + * + * [OS/2's] sTypoAscender, sTypoDescender and sTypoLineGap fields + * are intended to allow applications to lay out documents in a + * typographically-correct and portable fashion. + * + * This is somewhat at odds with the decades of backwards + * compatibility, operating systems and applications doing whatever + * they want, not to mention broken fonts. + * + * Not all fonts have an OS/2 table; in this case, we take the values + * in the horizontal header, although there is nothing stopping the + * values from being unreliable. Even with a OS/2 table, certain fonts + * set the sTypoAscender, sTypoDescender and sTypoLineGap fields to 0 + * and instead correctly set usWinAscent and usWinDescent. + * + * As an example, Arial Narrow is shipped as four files ARIALN.TTF, + * ARIALNI.TTF, ARIALNB.TTF and ARIALNBI.TTF. Strangely, all fonts have + * the same values in their sTypo* fields, except ARIALNB.ttf which + * sets them to 0. All of them have different usWinAscent/Descent + * values. The OS/2 table therefore cannot be trusted for computing the + * text height reliably. + * + * As a compromise, do the following: + * + * 1. If the OS/2 table exists and the fsSelection bit 7 is set + * (USE_TYPO_METRICS), trust the font and use the sTypo* metrics. + * 2. Otherwise, use the `hhea' table's metrics. + * 3. If they are zero and the OS/2 table exists, + * 1. use the OS/2 table's sTypo* metrics if they are non-zero. + * 2. Otherwise, use the OS/2 table's usWin* metrics. + */ + + if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 128 ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + root->height = root->ascender - root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = face->horizontal.Ascender; + root->descender = face->horizontal.Descender; + root->height = root->ascender - root->descender + + face->horizontal.Line_Gap; + + if ( !( root->ascender || root->descender ) ) + { + if ( face->os2.version != 0xFFFFU ) + { + if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + root->height = root->ascender - root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = (FT_Short)face->os2.usWinAscent; + root->descender = -(FT_Short)face->os2.usWinDescent; + root->height = root->ascender - root->descender; + } + } + } + } + + root->max_advance_width = + (FT_Short)face->horizontal.advance_Width_Max; + root->max_advance_height = + (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max + : root->height ); + + /* See https://www.microsoft.com/typography/otspec/post.htm -- */ + /* Adjust underline position from top edge to centre of */ + /* stroke to convert TrueType meaning to FreeType meaning. */ + root->underline_position = face->postscript.underlinePosition - + face->postscript.underlineThickness / 2; + root->underline_thickness = face->postscript.underlineThickness; + } + + } + + Exit: + FT_TRACE2(( "sfnt_load_face: done\n" )); + + return error; + } + + +#undef LOAD_ +#undef LOADM_ +#undef GET_NAME + + + FT_LOCAL_DEF( void ) + sfnt_done_face( TT_Face face ) + { + FT_Memory memory; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = face->root.memory; + sfnt = (SFNT_Service)face->sfnt; + + if ( sfnt ) + { + /* destroy the postscript names table if it is loaded */ + if ( sfnt->free_psnames ) + sfnt->free_psnames( face ); + + /* destroy the embedded bitmaps table if it is loaded */ + if ( sfnt->free_eblc ) + sfnt->free_eblc( face ); + + /* destroy color table data if it is loaded */ + if ( sfnt->free_cpal ) + { + sfnt->free_cpal( face ); + sfnt->free_colr( face ); + } + +#ifdef FT_CONFIG_OPTION_SVG + /* free SVG data */ + if ( sfnt->free_svg ) + sfnt->free_svg( face ); +#endif + } + +#ifdef TT_CONFIG_OPTION_BDF + /* freeing the embedded BDF properties */ + tt_face_free_bdf_props( face ); +#endif + + /* freeing the kerning table */ + tt_face_done_kern( face ); + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + /* freeing the GPOS table */ + tt_face_done_gpos( face ); +#endif + + /* freeing the collection table */ + FT_FREE( face->ttc_header.offsets ); + face->ttc_header.count = 0; + + /* freeing table directory */ + FT_FREE( face->dir_tables ); + face->num_tables = 0; + + { + FT_Stream stream = FT_FACE_STREAM( face ); + + + /* simply release the 'cmap' table frame */ + FT_FRAME_RELEASE( face->cmap_table ); + face->cmap_size = 0; + } + + face->horz_metrics_size = 0; + face->vert_metrics_size = 0; + + /* freeing vertical metrics, if any */ + if ( face->vertical_info ) + { + FT_FREE( face->vertical.long_metrics ); + FT_FREE( face->vertical.short_metrics ); + face->vertical_info = 0; + } + + /* freeing the gasp table */ + FT_FREE( face->gasp.gaspRanges ); + face->gasp.numRanges = 0; + + /* freeing the name table */ + if ( sfnt ) + sfnt->free_name( face ); + + /* freeing family and style name */ + FT_FREE( face->root.family_name ); + FT_FREE( face->root.style_name ); + + /* freeing sbit size table */ + FT_FREE( face->root.available_sizes ); + FT_FREE( face->sbit_strike_map ); + face->root.num_fixed_sizes = 0; + + FT_FREE( face->postscript_name ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_FREE( face->var_postscript_prefix ); + FT_FREE( face->non_var_style_name ); +#endif + + /* freeing glyph color palette data */ + FT_FREE( face->palette_data.palette_name_ids ); + FT_FREE( face->palette_data.palette_flags ); + FT_FREE( face->palette_data.palette_entry_name_ids ); + FT_FREE( face->palette ); + + face->sfnt = NULL; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfobjs.h b/Dependencies/freetype/freetype/src/sfnt/sfobjs.h new file mode 100644 index 00000000..90847d95 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfobjs.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * + * sfobjs.h + * + * SFNT object management (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFOBJS_H_ +#define SFOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + sfnt_done_face( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ); + + +FT_END_HEADER + +#endif /* SFOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfwoff.c b/Dependencies/freetype/freetype/src/sfnt/sfwoff.c new file mode 100644 index 00000000..14514bf9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfwoff.c @@ -0,0 +1,426 @@ +/**************************************************************************** + * + * sfwoff.c + * + * WOFF format management (base). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "sfwoff.h" +#include +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfwoff + + +#define WRITE_USHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_ULONG( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 24 ); \ + *(p)++ = (FT_Byte)( (v) >> 16 ); \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + + + static void + sfnt_stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->close = NULL; + } + + + FT_COMPARE_DEF( int ) + compare_offsets( const void* a, + const void* b ) + { + WOFF_Table table1 = *(WOFF_Table*)a; + WOFF_Table table2 = *(WOFF_Table*)b; + + FT_ULong offset1 = table1->Offset; + FT_ULong offset2 = table2->Offset; + + + if ( offset1 > offset2 ) + return 1; + else if ( offset1 < offset2 ) + return -1; + else + return 0; + } + + + /* Replace `face->root.stream' with a stream containing the extracted */ + /* SFNT of a WOFF font. */ + + FT_LOCAL_DEF( FT_Error ) + woff_open_font( FT_Stream stream, + TT_Face face ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + WOFF_HeaderRec woff; + WOFF_Table tables = NULL; + WOFF_Table* indices = NULL; + + FT_ULong woff_offset; + + FT_Byte* sfnt = NULL; + FT_Stream sfnt_stream = NULL; + + FT_Byte* sfnt_header; + FT_ULong sfnt_offset; + + FT_Int nn; + FT_Tag old_tag = 0; + + static const FT_Frame_Field woff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WOFF_HeaderRec + + FT_FRAME_START( 44 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_ULONG ( flavor ), + FT_FRAME_ULONG ( length ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( reserved ), + FT_FRAME_ULONG ( totalSfntSize ), + FT_FRAME_USHORT( majorVersion ), + FT_FRAME_USHORT( minorVersion ), + FT_FRAME_ULONG ( metaOffset ), + FT_FRAME_ULONG ( metaLength ), + FT_FRAME_ULONG ( metaOrigLength ), + FT_FRAME_ULONG ( privOffset ), + FT_FRAME_ULONG ( privLength ), + FT_FRAME_END + }; + + + FT_ASSERT( stream == face->root.stream ); + FT_ASSERT( FT_STREAM_POS() == 0 ); + + if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) ) + return error; + + /* Make sure we don't recurse back here or hit TTC code. */ + if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf ) + return FT_THROW( Invalid_Table ); + + /* Miscellaneous checks. */ + if ( woff.length != stream->size || + woff.num_tables == 0 || + woff.num_tables > 0xFFFU || + 44 + woff.num_tables * 20UL >= woff.length || + 12 + woff.num_tables * 16UL >= woff.totalSfntSize || + ( woff.totalSfntSize & 3 ) != 0 || + ( woff.metaOffset == 0 && ( woff.metaLength != 0 || + woff.metaOrigLength != 0 ) ) || + ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || + ( woff.privOffset == 0 && woff.privLength != 0 ) ) + { + FT_ERROR(( "woff_font_open: invalid WOFF header\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Don't trust `totalSfntSize' before thorough checks. */ + if ( FT_QALLOC( sfnt, 12 ) || FT_NEW( sfnt_stream ) ) + goto Exit; + + sfnt_header = sfnt; + + /* Write sfnt header. */ + { + FT_Int entrySelector = FT_MSB( woff.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff.num_tables * 16 - searchRange; + + + WRITE_ULONG ( sfnt_header, woff.flavor ); + WRITE_USHORT( sfnt_header, woff.num_tables ); + WRITE_USHORT( sfnt_header, searchRange ); + WRITE_USHORT( sfnt_header, entrySelector ); + WRITE_USHORT( sfnt_header, rangeShift ); + } + + /* While the entries in the sfnt header must be sorted by the */ + /* tag value, the tables themselves are not. We thus have to */ + /* sort them by offset and check that they don't overlap. */ + + if ( FT_QNEW_ARRAY( tables, woff.num_tables ) || + FT_QNEW_ARRAY( indices, woff.num_tables ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset compLen origLen checksum\n" )); + FT_TRACE2(( " -------------------------------------------\n" )); + + if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) + goto Exit; + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = tables + nn; + + table->Tag = FT_GET_TAG4(); + table->Offset = FT_GET_ULONG(); + table->CompLength = FT_GET_ULONG(); + table->OrigLength = FT_GET_ULONG(); + table->CheckSum = FT_GET_ULONG(); + + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n", + (FT_Char)( table->Tag >> 24 ), + (FT_Char)( table->Tag >> 16 ), + (FT_Char)( table->Tag >> 8 ), + (FT_Char)( table->Tag ), + table->Offset, + table->CompLength, + table->OrigLength, + table->CheckSum )); + + if ( table->Tag <= old_tag ) + { + FT_FRAME_EXIT(); + + FT_ERROR(( "woff_font_open: table tags are not sorted\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + old_tag = table->Tag; + indices[nn] = table; + } + + FT_FRAME_EXIT(); + + /* Sort by offset. */ + + ft_qsort( indices, + woff.num_tables, + sizeof ( WOFF_Table ), + compare_offsets ); + + /* Check offsets and lengths. */ + + woff_offset = 44 + woff.num_tables * 20L; + sfnt_offset = 12 + woff.num_tables * 16L; + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = indices[nn]; + + + if ( table->Offset != woff_offset || + table->CompLength > woff.length || + table->Offset > woff.length - table->CompLength || + table->OrigLength > woff.totalSfntSize || + sfnt_offset > woff.totalSfntSize - table->OrigLength || + table->CompLength > table->OrigLength ) + { + FT_ERROR(( "woff_font_open: invalid table offsets\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + table->OrigOffset = sfnt_offset; + + /* The offsets must be multiples of 4. */ + woff_offset += ( table->CompLength + 3 ) & ~3U; + sfnt_offset += ( table->OrigLength + 3 ) & ~3U; + } + + /* + * Final checks! + * + * We don't decode and check the metadata block. + * We don't check table checksums either. + * But other than those, I think we implement all + * `MUST' checks from the spec. + */ + + if ( woff.metaOffset ) + { + if ( woff.metaOffset != woff_offset || + woff.metaOffset + woff.metaLength > woff.length ) + { + FT_ERROR(( "woff_font_open:" + " invalid `metadata' offset or length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* We have padding only ... */ + woff_offset += woff.metaLength; + } + + if ( woff.privOffset ) + { + /* ... if it isn't the last block. */ + woff_offset = ( woff_offset + 3 ) & ~3U; + + if ( woff.privOffset != woff_offset || + woff.privOffset + woff.privLength > woff.length ) + { + FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* No padding for the last block. */ + woff_offset += woff.privLength; + } + + if ( sfnt_offset != woff.totalSfntSize || + woff_offset != woff.length ) + { + FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Now use `totalSfntSize'. */ + if ( FT_QREALLOC( sfnt, 12, woff.totalSfntSize ) ) + goto Exit; + + sfnt_header = sfnt + 12; + + /* Write the tables. */ + + for ( nn = 0; nn < woff.num_tables; nn++ ) + { + WOFF_Table table = tables + nn; + + + /* Write SFNT table entry. */ + WRITE_ULONG( sfnt_header, table->Tag ); + WRITE_ULONG( sfnt_header, table->CheckSum ); + WRITE_ULONG( sfnt_header, table->OrigOffset ); + WRITE_ULONG( sfnt_header, table->OrigLength ); + + /* Write table data. */ + if ( FT_STREAM_SEEK( table->Offset ) || + FT_FRAME_ENTER( table->CompLength ) ) + goto Exit; + + if ( table->CompLength == table->OrigLength ) + { + /* Uncompressed data; just copy. */ + ft_memcpy( sfnt + table->OrigOffset, + stream->cursor, + table->OrigLength ); + } + else + { + /* Uncompress with zlib. */ + FT_ULong output_len = table->OrigLength; + + + error = FT_Gzip_Uncompress( memory, + sfnt + table->OrigOffset, &output_len, + stream->cursor, table->CompLength ); + if ( error ) + goto Exit1; + if ( output_len != table->OrigLength ) + { + FT_ERROR(( "woff_font_open: compressed table length mismatch\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit1; + } + } + + FT_FRAME_EXIT(); + + /* We don't check whether the padding bytes in the WOFF file are */ + /* actually '\0'. For the output, however, we do set them properly. */ + sfnt_offset = table->OrigOffset + table->OrigLength; + while ( sfnt_offset & 3 ) + { + sfnt[sfnt_offset] = '\0'; + sfnt_offset++; + } + } + + /* Ok! Finally ready. Swap out stream and return. */ + FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize ); + sfnt_stream->memory = stream->memory; + sfnt_stream->close = sfnt_stream_close; + + FT_Stream_Free( + face->root.stream, + ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->root.stream = sfnt_stream; + + face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + + Exit: + FT_FREE( tables ); + FT_FREE( indices ); + + if ( error ) + { + FT_FREE( sfnt ); + FT_Stream_Close( sfnt_stream ); + FT_FREE( sfnt_stream ); + } + + return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; + } + + +#undef WRITE_USHORT +#undef WRITE_ULONG + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfwoff.h b/Dependencies/freetype/freetype/src/sfnt/sfwoff.h new file mode 100644 index 00000000..a04735ff --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfwoff.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * sfwoff.h + * + * WOFFF format management (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFWOFF_H_ +#define SFWOFF_H_ + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_LOCAL( FT_Error ) + woff_open_font( FT_Stream stream, + TT_Face face ); + + +#endif + +FT_END_HEADER + +#endif /* SFWOFF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfwoff2.c b/Dependencies/freetype/freetype/src/sfnt/sfwoff2.c new file mode 100644 index 00000000..589b3e0c --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfwoff2.c @@ -0,0 +1,2380 @@ +/**************************************************************************** + * + * sfwoff2.c + * + * WOFF2 format management (base). + * + * Copyright (C) 2019-2024 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include "sfwoff2.h" +#include "woff2tags.h" +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT sfwoff2 + + /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */ +#define MAX_SFNT_SIZE ( 1 << 26 ) + +#define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) ) + +#define READ_BASE128( var ) FT_SET_ERROR( ReadBase128( stream, &var ) ) + + /* `var' should be FT_ULong */ +#define ROUND4( var ) ( ( var + 3 ) & ~3UL ) + +#define WRITE_USHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_ULONG( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 24 ); \ + *(p)++ = (FT_Byte)( (v) >> 16 ); \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SFNT_BUF( buf, s ) \ + write_buf( &sfnt, sfnt_size, &dest_offset, buf, s, memory ) + +#define WRITE_SFNT_BUF_AT( offset, buf, s ) \ + write_buf( &sfnt, sfnt_size, &offset, buf, s, memory ) + +#define N_CONTOUR_STREAM 0 +#define N_POINTS_STREAM 1 +#define FLAG_STREAM 2 +#define GLYPH_STREAM 3 +#define COMPOSITE_STREAM 4 +#define BBOX_STREAM 5 +#define INSTRUCTION_STREAM 6 + +#define HAVE_OVERLAP_SIMPLE_BITMAP 0x1 + + + static void + stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->close = NULL; + } + + + FT_COMPARE_DEF( int ) + compare_tags( const void* a, + const void* b ) + { + WOFF2_Table table1 = *(WOFF2_Table*)a; + WOFF2_Table table2 = *(WOFF2_Table*)b; + + FT_Tag tag1 = table1->Tag; + FT_Tag tag2 = table2->Tag; + + + if ( tag1 > tag2 ) + return 1; + else if ( tag1 < tag2 ) + return -1; + else + return 0; + } + + + static FT_Error + Read255UShort( FT_Stream stream, + FT_UShort* value ) + { + const FT_Byte oneMoreByteCode1 = 255; + const FT_Byte oneMoreByteCode2 = 254; + const FT_Byte wordCode = 253; + const FT_UShort lowestUCode = 253; + + FT_Error error = FT_Err_Ok; + FT_Byte code; + FT_Byte result_byte = 0; + FT_UShort result_short = 0; + + + if ( FT_READ_BYTE( code ) ) + return error; + if ( code == wordCode ) + { + /* Read next two bytes and store `FT_UShort' value. */ + if ( FT_READ_USHORT( result_short ) ) + return error; + *value = result_short; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode1 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode2 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode * 2; + return FT_Err_Ok; + } + else + { + *value = code; + return FT_Err_Ok; + } + } + + + static FT_Error + ReadBase128( FT_Stream stream, + FT_ULong* value ) + { + FT_ULong result = 0; + FT_Int i; + FT_Byte code; + FT_Error error = FT_Err_Ok; + + + for ( i = 0; i < 5; ++i ) + { + code = 0; + if ( FT_READ_BYTE( code ) ) + return error; + + /* Leading zeros are invalid. */ + if ( i == 0 && code == 0x80 ) + return FT_THROW( Invalid_Table ); + + /* If any of top seven bits are set then we're about to overflow. */ + if ( result & 0xfe000000 ) + return FT_THROW( Invalid_Table ); + + result = ( result << 7 ) | ( code & 0x7f ); + + /* Spin until most significant bit of data byte is false. */ + if ( ( code & 0x80 ) == 0 ) + { + *value = result; + return FT_Err_Ok; + } + } + + /* Make sure not to exceed the size bound. */ + return FT_THROW( Invalid_Table ); + } + + + /* Extend memory of `dst_bytes' buffer and copy data from `src'. */ + static FT_Error + write_buf( FT_Byte** dst_bytes, + FT_ULong* dst_size, + FT_ULong* offset, + FT_Byte* src, + FT_ULong size, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + /* We are reallocating memory for `dst', so its pointer may change. */ + FT_Byte* dst = *dst_bytes; + + + /* Check whether we are within limits. */ + if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) + return FT_THROW( Array_Too_Large ); + + /* Reallocate `dst'. */ + if ( ( *offset + size ) > *dst_size ) + { + FT_TRACE6(( "Reallocating %lu to %lu.\n", + *dst_size, (*offset + size) )); + if ( FT_QREALLOC( dst, + (FT_ULong)( *dst_size ), + (FT_ULong)( *offset + size ) ) ) + goto Exit; + + *dst_size = *offset + size; + } + + /* Copy data. */ + ft_memcpy( dst + *offset, src, size ); + + *offset += size; + /* Set pointer of `dst' to its correct value. */ + *dst_bytes = dst; + + Exit: + return error; + } + + + /* Pad buffer to closest multiple of 4. */ + static FT_Error + pad4( FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte zeroes[] = { 0, 0, 0 }; + FT_ULong pad_bytes; + + + if ( dest_offset + 3 < dest_offset ) + return FT_THROW( Invalid_Table ); + + pad_bytes = ROUND4( dest_offset ) - dest_offset; + if ( pad_bytes > 0 ) + { + if ( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) ) + return FT_THROW( Invalid_Table ); + } + + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + return FT_Err_Ok; + } + + + /* Calculate table checksum of `buf'. */ + static FT_ULong + compute_ULong_sum( FT_Byte* buf, + FT_ULong size ) + { + FT_ULong checksum = 0; + FT_ULong aligned_size = size & ~3UL; + FT_ULong i; + FT_Int shift; + + + for ( i = 0; i < aligned_size; i += 4 ) + checksum += FT_NEXT_ULONG( buf ); + + /* remaining bytes can be shifted and added one at a time */ + for ( shift = 24; i < size; i++, shift -= 8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( buf ) << shift; + + return checksum; + } + + + static FT_Error + woff2_decompress( FT_Byte* dst, + FT_ULong dst_size, + const FT_Byte* src, + FT_ULong src_size ) + { + /* this cast is only of importance on 32bit systems; */ + /* we don't validate it */ + FT_Offset uncompressed_size = (FT_Offset)dst_size; + BrotliDecoderResult result; + + + result = BrotliDecoderDecompress( src_size, + src, + &uncompressed_size, + dst ); + + if ( result != BROTLI_DECODER_RESULT_SUCCESS || + uncompressed_size != dst_size ) + { + FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); + return FT_Err_Ok; + } + + + static WOFF2_Table + find_table( WOFF2_Table* tables, + FT_UShort num_tables, + FT_Tag tag ) + { + FT_Int i; + + + for ( i = 0; i < num_tables; i++ ) + { + if ( tables[i]->Tag == tag ) + return tables[i]; + } + return NULL; + } + + + /* Read `numberOfHMetrics' field from `hhea' table. */ + static FT_Error + read_num_hmetrics( FT_Stream stream, + FT_UShort* num_hmetrics ) + { + FT_Error error = FT_Err_Ok; + FT_UShort num_metrics; + + + if ( FT_STREAM_SKIP( 34 ) ) + return FT_THROW( Invalid_Table ); + + if ( FT_READ_USHORT( num_metrics ) ) + return FT_THROW( Invalid_Table ); + + *num_hmetrics = num_metrics; + + return error; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + with_sign( FT_Byte flag, + FT_Int base_val ) + { + /* Precondition: 0 <= base_val < 65536 (to avoid overflow). */ + return ( flag & 1 ) ? base_val : -base_val; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + safe_int_addition( FT_Int a, + FT_Int b, + FT_Int* result ) + { + if ( ( ( a > 0 ) && ( b > FT_INT_MAX - a ) ) || + ( ( a < 0 ) && ( b < FT_INT_MIN - a ) ) ) + return FT_THROW( Invalid_Table ); + + *result = a + b; + return FT_Err_Ok; + } + + + /* + * Decode variable-length (flag, xCoordinate, yCoordinate) triplet for a + * simple glyph. See + * + * https://www.w3.org/TR/WOFF2/#triplet_decoding + */ + static FT_Error + triplet_decode( const FT_Byte* flags_in, + const FT_Byte* in, + FT_ULong in_size, + FT_ULong n_points, + WOFF2_Point result, + FT_ULong* in_bytes_used ) + { + FT_Int x = 0; + FT_Int y = 0; + FT_Int dx; + FT_Int dy; + FT_Int b0, b1, b2; + + FT_ULong triplet_index = 0; + FT_ULong data_bytes; + + FT_UInt i; + + + if ( n_points > in_size ) + return FT_THROW( Invalid_Table ); + + for ( i = 0; i < n_points; ++i ) + { + FT_Byte flag = flags_in[i]; + FT_Bool on_curve = !( flag >> 7 ); + + + flag &= 0x7f; + if ( flag < 84 ) + data_bytes = 1; + else if ( flag < 120 ) + data_bytes = 2; + else if ( flag < 124 ) + data_bytes = 3; + else + data_bytes = 4; + + /* Overflow checks */ + if ( triplet_index + data_bytes > in_size || + triplet_index + data_bytes < triplet_index ) + return FT_THROW( Invalid_Table ); + + if ( flag < 10 ) + { + dx = 0; + dy = with_sign( flag, + ( ( flag & 14 ) << 7 ) + in[triplet_index] ); + } + else if ( flag < 20 ) + { + dx = with_sign( flag, + ( ( ( flag - 10 ) & 14 ) << 7 ) + + in[triplet_index] ); + dy = 0; + } + else if ( flag < 84 ) + { + b0 = flag - 20; + b1 = in[triplet_index]; + dx = with_sign( flag, + 1 + ( b0 & 0x30 ) + ( b1 >> 4 ) ); + dy = with_sign( flag >> 1, + 1 + ( ( b0 & 0x0c ) << 2 ) + ( b1 & 0x0f ) ); + } + else if ( flag < 120 ) + { + b0 = flag - 84; + dx = with_sign( flag, + 1 + ( ( b0 / 12 ) << 8 ) + in[triplet_index] ); + dy = with_sign( flag >> 1, + 1 + ( ( ( b0 % 12 ) >> 2 ) << 8 ) + + in[triplet_index + 1] ); + } + else if ( flag < 124 ) + { + b2 = in[triplet_index + 1]; + dx = with_sign( flag, + ( in[triplet_index] << 4 ) + ( b2 >> 4 ) ); + dy = with_sign( flag >> 1, + ( ( b2 & 0x0f ) << 8 ) + in[triplet_index + 2] ); + } + else + { + dx = with_sign( flag, + ( in[triplet_index] << 8 ) + + in[triplet_index + 1] ); + dy = with_sign( flag >> 1, + ( in[triplet_index + 2] << 8 ) + + in[triplet_index + 3] ); + } + + triplet_index += data_bytes; + + if ( safe_int_addition( x, dx, &x ) ) + return FT_THROW( Invalid_Table ); + + if ( safe_int_addition( y, dy, &y ) ) + return FT_THROW( Invalid_Table ); + + result[i].x = x; + result[i].y = y; + result[i].on_curve = on_curve; + } + + *in_bytes_used = triplet_index; + return FT_Err_Ok; + } + + + /* Store decoded points in glyph buffer. */ + static FT_Error + store_points( FT_ULong n_points, + const WOFF2_Point points, + FT_UShort n_contours, + FT_UShort instruction_len, + FT_Bool have_overlap, + FT_Byte* dst, + FT_ULong dst_size, + FT_ULong* glyph_size ) + { + FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; + FT_Byte last_flag = 0xFFU; + FT_Byte repeat_count = 0; + FT_Int last_x = 0; + FT_Int last_y = 0; + FT_UInt x_bytes = 0; + FT_UInt y_bytes = 0; + FT_UInt xy_bytes; + FT_UInt i; + FT_UInt x_offset; + FT_UInt y_offset; + FT_Byte* pointer; + + + for ( i = 0; i < n_points; ++i ) + { + const WOFF2_PointRec point = points[i]; + + FT_Byte flag = point.on_curve ? GLYF_ON_CURVE : 0; + FT_Int dx = point.x - last_x; + FT_Int dy = point.y - last_y; + + + if ( i == 0 && have_overlap ) + flag |= GLYF_OVERLAP_SIMPLE; + + if ( dx == 0 ) + flag |= GLYF_THIS_X_IS_SAME; + else if ( dx > -256 && dx < 256 ) + { + flag |= GLYF_X_SHORT | ( dx > 0 ? GLYF_THIS_X_IS_SAME : 0 ); + x_bytes += 1; + } + else + x_bytes += 2; + + if ( dy == 0 ) + flag |= GLYF_THIS_Y_IS_SAME; + else if ( dy > -256 && dy < 256 ) + { + flag |= GLYF_Y_SHORT | ( dy > 0 ? GLYF_THIS_Y_IS_SAME : 0 ); + y_bytes += 1; + } + else + y_bytes += 2; + + if ( flag == last_flag && repeat_count != 255 ) + { + dst[flag_offset - 1] |= GLYF_REPEAT; + repeat_count++; + } + else + { + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = flag; + repeat_count = 0; + } + + last_x = point.x; + last_y = point.y; + last_flag = flag; + } + + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + + xy_bytes = x_bytes + y_bytes; + if ( xy_bytes < x_bytes || + flag_offset + xy_bytes < flag_offset || + flag_offset + xy_bytes > dst_size ) + return FT_THROW( Invalid_Table ); + + x_offset = flag_offset; + y_offset = flag_offset + x_bytes; + last_x = 0; + last_y = 0; + + for ( i = 0; i < n_points; ++i ) + { + FT_Int dx = points[i].x - last_x; + FT_Int dy = points[i].y - last_y; + + + if ( dx == 0 ) + ; + else if ( dx > -256 && dx < 256 ) + dst[x_offset++] = (FT_Byte)FT_ABS( dx ); + else + { + pointer = dst + x_offset; + WRITE_SHORT( pointer, dx ); + x_offset += 2; + } + + last_x += dx; + + if ( dy == 0 ) + ; + else if ( dy > -256 && dy < 256 ) + dst[y_offset++] = (FT_Byte)FT_ABS( dy ); + else + { + pointer = dst + y_offset; + WRITE_SHORT( pointer, dy ); + y_offset += 2; + } + + last_y += dy; + } + + *glyph_size = y_offset; + return FT_Err_Ok; + } + + + static void + compute_bbox( FT_ULong n_points, + const WOFF2_Point points, + FT_Byte* dst, + FT_UShort* src_x_min ) + { + FT_Int x_min = 0; + FT_Int y_min = 0; + FT_Int x_max = 0; + FT_Int y_max = 0; + + FT_UInt i; + + FT_ULong offset; + FT_Byte* pointer; + + + if ( n_points > 0 ) + { + x_min = points[0].x; + y_min = points[0].y; + x_max = points[0].x; + y_max = points[0].y; + } + + for ( i = 1; i < n_points; ++i ) + { + FT_Int x = points[i].x; + FT_Int y = points[i].y; + + + x_min = FT_MIN( x, x_min ); + y_min = FT_MIN( y, y_min ); + x_max = FT_MAX( x, x_max ); + y_max = FT_MAX( y, y_max ); + } + + /* Write values to `glyf' record. */ + offset = 2; + pointer = dst + offset; + + WRITE_SHORT( pointer, x_min ); + WRITE_SHORT( pointer, y_min ); + WRITE_SHORT( pointer, x_max ); + WRITE_SHORT( pointer, y_max ); + + *src_x_min = (FT_UShort)x_min; + } + + + static FT_Error + compositeGlyph_size( FT_Stream stream, + FT_ULong offset, + FT_ULong* size, + FT_Bool* have_instructions ) + { + FT_Error error = FT_Err_Ok; + FT_ULong start_offset = offset; + FT_Bool we_have_inst = FALSE; + FT_UShort flags = FLAG_MORE_COMPONENTS; + + + if ( FT_STREAM_SEEK( start_offset ) ) + goto Exit; + while ( flags & FLAG_MORE_COMPONENTS ) + { + FT_ULong arg_size; + + + if ( FT_READ_USHORT( flags ) ) + goto Exit; + we_have_inst |= ( flags & FLAG_WE_HAVE_INSTRUCTIONS ) != 0; + /* glyph index */ + arg_size = 2; + if ( flags & FLAG_ARG_1_AND_2_ARE_WORDS ) + arg_size += 4; + else + arg_size += 2; + + if ( flags & FLAG_WE_HAVE_A_SCALE ) + arg_size += 2; + else if ( flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE ) + arg_size += 4; + else if ( flags & FLAG_WE_HAVE_A_TWO_BY_TWO ) + arg_size += 8; + + if ( FT_STREAM_SKIP( arg_size ) ) + goto Exit; + } + + *size = FT_STREAM_POS() - start_offset; + *have_instructions = we_have_inst; + + Exit: + return error; + } + + + /* Store loca values (provided by `reconstruct_glyf') to output stream. */ + static FT_Error + store_loca( FT_ULong* loca_values, + FT_ULong loca_values_size, + FT_UShort index_format, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte* loca_buf = NULL; + FT_Byte* dst = NULL; + + FT_UInt i = 0; + FT_ULong loca_buf_size; + + const FT_ULong offset_size = index_format ? 4 : 2; + + + if ( ( loca_values_size << 2 ) >> 2 != loca_values_size ) + goto Fail; + + loca_buf_size = loca_values_size * offset_size; + if ( FT_QALLOC( loca_buf, loca_buf_size ) ) + goto Fail; + + dst = loca_buf; + for ( i = 0; i < loca_values_size; i++ ) + { + FT_ULong value = loca_values[i]; + + + if ( index_format ) + WRITE_ULONG( dst, value ); + else + WRITE_USHORT( dst, ( value >> 1 ) ); + } + + *checksum = compute_ULong_sum( loca_buf, loca_buf_size ); + /* Write `loca' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( loca_buf ); + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + FT_FREE( loca_buf ); + + return error; + } + + + static FT_Error + reconstruct_glyf( FT_Stream stream, + FT_ULong* glyf_checksum, + FT_ULong* loca_checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + WOFF2_Info info, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + + /* current position in stream */ + const FT_ULong pos = FT_STREAM_POS(); + + FT_UInt num_substreams = 7; + + FT_UShort option_flags; + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong expected_loca_length; + FT_UInt offset; + FT_UInt i; + FT_ULong points_size; + FT_ULong glyph_buf_size; + FT_ULong bbox_bitmap_offset; + FT_ULong bbox_bitmap_length; + FT_ULong overlap_bitmap_offset = 0; + FT_ULong overlap_bitmap_length = 0; + + const FT_ULong glyf_start = *out_offset; + FT_ULong dest_offset = *out_offset; + + WOFF2_Substream substreams = NULL; + + FT_ULong* loca_values = NULL; + FT_UShort* n_points_arr = NULL; + FT_Byte* glyph_buf = NULL; + WOFF2_Point points = NULL; + + + if ( FT_QNEW_ARRAY( substreams, num_substreams ) ) + goto Fail; + + if ( FT_STREAM_SKIP( 2 ) ) + goto Fail; + if ( FT_READ_USHORT( option_flags ) ) + goto Fail; + if ( FT_READ_USHORT( num_glyphs ) ) + goto Fail; + if ( FT_READ_USHORT( index_format ) ) + goto Fail; + + FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n", + option_flags, num_glyphs, index_format )); + + info->num_glyphs = num_glyphs; + + /* Calculate expected length of loca and compare. */ + /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */ + /* index_format = 0 => Short version `loca'. */ + /* index_format = 1 => Long version `loca'. */ + expected_loca_length = ( index_format ? 4 : 2 ) * + ( (FT_ULong)num_glyphs + 1 ); + if ( info->loca_table->dst_length != expected_loca_length ) + goto Fail; + + offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 ); + if ( offset > info->glyf_table->TransformLength ) + goto Fail; + + for ( i = 0; i < num_substreams; ++i ) + { + FT_ULong substream_size; + + + if ( FT_READ_ULONG( substream_size ) ) + goto Fail; + if ( substream_size > info->glyf_table->TransformLength - offset ) + goto Fail; + + substreams[i].start = pos + offset; + substreams[i].offset = pos + offset; + substreams[i].size = substream_size; + + FT_TRACE5(( " Substream %d: offset = %lu; size = %lu;\n", + i, substreams[i].offset, substreams[i].size )); + offset += substream_size; + } + + if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP ) + { + /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */ + overlap_bitmap_length = ( num_glyphs + 7U ) >> 3; + if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset ) + goto Fail; + + overlap_bitmap_offset = pos + offset; + + FT_TRACE5(( " Overlap bitmap: offset = %lu; size = %lu;\n", + overlap_bitmap_offset, overlap_bitmap_length )); + offset += overlap_bitmap_length; + } + + if ( FT_QNEW_ARRAY( loca_values, num_glyphs + 1 ) ) + goto Fail; + + points_size = 0; + bbox_bitmap_offset = substreams[BBOX_STREAM].offset; + + /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ + bbox_bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; + /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */ + substreams[BBOX_STREAM].offset += bbox_bitmap_length; + + glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; + if ( FT_QALLOC( glyph_buf, glyph_buf_size ) ) + goto Fail; + + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + goto Fail; + + for ( i = 0; i < num_glyphs; ++i ) + { + FT_ULong glyph_size = 0; + FT_UShort n_contours = 0; + FT_Bool have_bbox = FALSE; + FT_Byte bbox_bitmap; + FT_ULong bbox_offset; + FT_UShort x_min = 0; + + + /* Set `have_bbox'. */ + bbox_offset = bbox_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( bbox_offset ) || + FT_READ_BYTE( bbox_bitmap ) ) + goto Fail; + if ( bbox_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_bbox = TRUE; + + /* Read value from `nContourStream'. */ + if ( FT_STREAM_SEEK( substreams[N_CONTOUR_STREAM].offset ) || + FT_READ_USHORT( n_contours ) ) + goto Fail; + substreams[N_CONTOUR_STREAM].offset += 2; + + if ( n_contours == 0xffff ) + { + /* composite glyph */ + FT_Bool have_instructions = FALSE; + FT_UShort instruction_size = 0; + FT_ULong composite_size = 0; + FT_ULong size_needed; + FT_Byte* pointer = NULL; + + + /* Composite glyphs must have explicit bbox. */ + if ( !have_bbox ) + goto Fail; + + if ( compositeGlyph_size( stream, + substreams[COMPOSITE_STREAM].offset, + &composite_size, + &have_instructions) ) + goto Fail; + + if ( have_instructions ) + { + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + } + + size_needed = 12 + composite_size + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + + substreams[BBOX_STREAM].offset += 8; + glyph_size += 8; + + if ( FT_STREAM_SEEK( substreams[COMPOSITE_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, composite_size ) ) + goto Fail; + + substreams[COMPOSITE_STREAM].offset += composite_size; + glyph_size += composite_size; + + if ( have_instructions ) + { + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + } + } + else if ( n_contours > 0 ) + { + /* simple glyph */ + FT_ULong total_n_points = 0; + FT_UShort n_points_contour; + FT_UInt j; + FT_ULong flag_size; + FT_ULong triplet_size; + FT_ULong triplet_bytes_used; + FT_Bool have_overlap = FALSE; + FT_Byte overlap_bitmap; + FT_ULong overlap_offset; + FT_Byte* flags_buf = NULL; + FT_Byte* triplet_buf = NULL; + FT_UShort instruction_size; + FT_ULong size_needed; + FT_Int end_point; + FT_UInt contour_ix; + + FT_Byte* pointer = NULL; + + + /* Set `have_overlap`. */ + if ( overlap_bitmap_offset ) + { + overlap_offset = overlap_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( overlap_offset ) || + FT_READ_BYTE( overlap_bitmap ) ) + goto Fail; + if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_overlap = TRUE; + } + + if ( FT_QNEW_ARRAY( n_points_arr, n_contours ) ) + goto Fail; + + if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) ) + goto Fail; + + for ( j = 0; j < n_contours; ++j ) + { + if ( READ_255USHORT( n_points_contour ) ) + goto Fail; + n_points_arr[j] = n_points_contour; + /* Prevent negative/overflow. */ + if ( total_n_points + n_points_contour < total_n_points ) + goto Fail; + total_n_points += n_points_contour; + } + substreams[N_POINTS_STREAM].offset = FT_STREAM_POS(); + + flag_size = total_n_points; + if ( flag_size > substreams[FLAG_STREAM].size ) + goto Fail; + + flags_buf = stream->base + substreams[FLAG_STREAM].offset; + triplet_buf = stream->base + substreams[GLYPH_STREAM].offset; + + if ( substreams[GLYPH_STREAM].size < + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ) ) + goto Fail; + + triplet_size = substreams[GLYPH_STREAM].size - + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ); + triplet_bytes_used = 0; + + /* Create array to store point information. */ + points_size = total_n_points; + if ( FT_QNEW_ARRAY( points, points_size ) ) + goto Fail; + + if ( triplet_decode( flags_buf, + triplet_buf, + triplet_size, + total_n_points, + points, + &triplet_bytes_used ) ) + goto Fail; + + substreams[FLAG_STREAM].offset += flag_size; + substreams[GLYPH_STREAM].offset += triplet_bytes_used; + + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + + if ( total_n_points >= ( 1 << 27 ) ) + goto Fail; + + size_needed = 12 + + ( 2 * n_contours ) + + ( 5 * total_n_points ) + + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + if ( have_bbox ) + { + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + substreams[BBOX_STREAM].offset += 8; + } + else + compute_bbox( total_n_points, points, glyph_buf, &x_min ); + + glyph_size = CONTOUR_OFFSET_END_POINT; + + pointer = glyph_buf + glyph_size; + end_point = -1; + + for ( contour_ix = 0; contour_ix < n_contours; ++contour_ix ) + { + end_point += n_points_arr[contour_ix]; + if ( end_point >= 65536 ) + goto Fail; + + WRITE_SHORT( pointer, end_point ); + glyph_size += 2; + } + + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + + if ( store_points( total_n_points, + points, + n_contours, + instruction_size, + have_overlap, + glyph_buf, + glyph_buf_size, + &glyph_size ) ) + goto Fail; + + FT_FREE( points ); + FT_FREE( n_points_arr ); + } + else + { + /* Empty glyph. */ + /* Must not have a bbox. */ + if ( have_bbox ) + { + FT_ERROR(( "Empty glyph has a bbox.\n" )); + goto Fail; + } + } + + loca_values[i] = dest_offset - glyf_start; + + if ( WRITE_SFNT_BUF( glyph_buf, glyph_size ) ) + goto Fail; + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size ); + + /* Store x_mins, may be required to reconstruct `hmtx'. */ + info->x_mins[i] = (FT_Short)x_min; + } + + info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset; + info->loca_table->dst_offset = dest_offset; + + /* `loca[n]' will be equal to the length of the `glyf' table. */ + loca_values[num_glyphs] = info->glyf_table->dst_length; + + if ( store_loca( loca_values, + num_glyphs + 1, + index_format, + loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + + info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset; + + FT_TRACE4(( " loca table info:\n" )); + FT_TRACE4(( " dst_offset = %lu\n", info->loca_table->dst_offset )); + FT_TRACE4(( " dst_length = %lu\n", info->loca_table->dst_length )); + FT_TRACE4(( " checksum = %09lx\n", *loca_checksum )); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + } + + + /* Get `x_mins' for untransformed `glyf' table. */ + static FT_Error + get_x_mins( FT_Stream stream, + WOFF2_Table* tables, + FT_UShort num_tables, + WOFF2_Info info, + FT_Memory memory ) + { + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong glyf_offset; + FT_UShort glyf_offset_short; + FT_ULong loca_offset; + FT_Int i; + FT_Error error = FT_Err_Ok; + FT_ULong offset_size; + + /* At this point of time those tables might not have been read yet. */ + const WOFF2_Table maxp_table = find_table( tables, num_tables, + TTAG_maxp ); + const WOFF2_Table head_table = find_table( tables, num_tables, + TTAG_head ); + + + if ( !maxp_table ) + { + FT_ERROR(( "`maxp' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !info->loca_table ) + { + FT_ERROR(( "`loca' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Read `numGlyphs' field from `maxp' table. */ + if ( FT_STREAM_SEEK( maxp_table->src_offset ) || FT_STREAM_SKIP( 8 ) ) + return error; + + if ( FT_READ_USHORT( num_glyphs ) ) + return error; + + info->num_glyphs = num_glyphs; + + /* Read `indexToLocFormat' field from `head' table. */ + if ( FT_STREAM_SEEK( head_table->src_offset ) || + FT_STREAM_SKIP( 50 ) ) + return error; + + if ( FT_READ_USHORT( index_format ) ) + return error; + + offset_size = index_format ? 4 : 2; + + /* Create `x_mins' array. */ + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + return error; + + loca_offset = info->loca_table->src_offset; + + for ( i = 0; i < num_glyphs; ++i ) + { + if ( FT_STREAM_SEEK( loca_offset ) ) + return error; + + loca_offset += offset_size; + + if ( index_format ) + { + if ( FT_READ_ULONG( glyf_offset ) ) + return error; + } + else + { + if ( FT_READ_USHORT( glyf_offset_short ) ) + return error; + + glyf_offset = (FT_ULong)( glyf_offset_short ); + glyf_offset = glyf_offset << 1; + } + + glyf_offset += info->glyf_table->src_offset; + + if ( FT_STREAM_SEEK( glyf_offset ) || FT_STREAM_SKIP( 2 ) ) + return error; + + if ( FT_READ_SHORT( info->x_mins[i] ) ) + return error; + } + + return error; + } + + + static FT_Error + reconstruct_hmtx( FT_Stream stream, + FT_UShort num_glyphs, + FT_UShort num_hmetrics, + FT_Short* x_mins, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte hmtx_flags; + FT_Bool has_proportional_lsbs, has_monospace_lsbs; + FT_ULong hmtx_table_size; + FT_Int i; + + FT_UShort* advance_widths = NULL; + FT_Short* lsbs = NULL; + FT_Byte* hmtx_table = NULL; + FT_Byte* dst = NULL; + + + if ( FT_READ_BYTE( hmtx_flags ) ) + goto Fail; + + has_proportional_lsbs = ( hmtx_flags & 1 ) == 0; + has_monospace_lsbs = ( hmtx_flags & 2 ) == 0; + + /* Bits 2-7 are reserved and MUST be zero. */ + if ( ( hmtx_flags & 0xFC ) != 0 ) + goto Fail; + + /* Are you REALLY transformed? */ + if ( has_proportional_lsbs && has_monospace_lsbs ) + goto Fail; + + /* Cannot have a transformed `hmtx' without `glyf'. */ + if ( ( num_hmetrics > num_glyphs ) || + ( num_hmetrics < 1 ) ) + goto Fail; + + /* Must have at least one entry. */ + if ( num_hmetrics < 1 ) + goto Fail; + + if ( FT_QNEW_ARRAY( advance_widths, num_hmetrics ) || + FT_QNEW_ARRAY( lsbs, num_glyphs ) ) + goto Fail; + + /* Read `advanceWidth' stream. Always present. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_UShort advance_width; + + + if ( FT_READ_USHORT( advance_width ) ) + goto Fail; + + advance_widths[i] = advance_width; + } + + /* lsb values for proportional glyphs. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_Short lsb; + + + if ( has_proportional_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* lsb values for monospaced glyphs. */ + for ( i = num_hmetrics; i < num_glyphs; i++ ) + { + FT_Short lsb; + + + if ( has_monospace_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* Build the hmtx table. */ + hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs; + if ( FT_QALLOC( hmtx_table, hmtx_table_size ) ) + goto Fail; + + dst = hmtx_table; + FT_TRACE6(( "hmtx values: \n" )); + for ( i = 0; i < num_glyphs; i++ ) + { + if ( i < num_hmetrics ) + { + WRITE_SHORT( dst, advance_widths[i] ); + FT_TRACE6(( "%d ", advance_widths[i] )); + } + + WRITE_SHORT( dst, lsbs[i] ); + FT_TRACE6(( "%d ", lsbs[i] )); + } + FT_TRACE6(( "\n" )); + + *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size ); + /* Write `hmtx' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + return error; + + Fail: + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + if ( !error ) + error = FT_THROW( Invalid_Table ); + + return error; + } + + + static FT_Error + reconstruct_font( FT_Byte* transformed_buf, + FT_ULong transformed_buf_size, + WOFF2_Table* indices, + WOFF2_Header woff2, + WOFF2_Info info, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_Memory memory ) + { + /* Memory management of `transformed_buf' is handled by the caller. */ + + FT_Error error = FT_Err_Ok; + FT_Stream stream = NULL; + FT_Byte* buf_cursor = NULL; + FT_Byte table_entry[16]; + + /* We are reallocating memory for `sfnt', so its pointer may change. */ + FT_Byte* sfnt = *sfnt_bytes; + + FT_UShort num_tables = woff2->num_tables; + FT_ULong dest_offset = 12 + num_tables * 16UL; + + FT_ULong checksum = 0; + FT_ULong loca_checksum = 0; + FT_Int nn = 0; + FT_UShort num_hmetrics = 0; + FT_ULong font_checksum = info->header_checksum; + FT_Bool is_glyf_xform = FALSE; + + FT_ULong table_entry_offset = 12; + + + /* A few table checks before reconstruction. */ + /* `glyf' must be present with `loca'. */ + info->glyf_table = find_table( indices, num_tables, TTAG_glyf ); + info->loca_table = find_table( indices, num_tables, TTAG_loca ); + + if ( ( info->glyf_table == NULL ) ^ ( info->loca_table == NULL ) ) + { + FT_ERROR(( "One of `glyf'/`loca' tables missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Both `glyf' and `loca' must have same transformation. */ + if ( info->glyf_table != NULL ) + { + if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) != + ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) ) + { + FT_ERROR(( "Transformation mismatch" + " between `glyf' and `loca' table." )); + return FT_THROW( Invalid_Table ); + } + } + + /* Create a stream for the uncompressed buffer. */ + if ( FT_NEW( stream ) ) + goto Fail; + FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); + + FT_ASSERT( FT_STREAM_POS() == 0 ); + + /* Reconstruct/copy tables to output stream. */ + for ( nn = 0; nn < num_tables; nn++ ) + { + WOFF2_TableRec table = *( indices[nn] ); + + + FT_TRACE3(( "Seeking to %ld with table size %ld.\n", + table.src_offset, table.src_length )); + FT_TRACE3(( "Table tag: %c%c%c%c.\n", + (FT_Char)( table.Tag >> 24 ), + (FT_Char)( table.Tag >> 16 ), + (FT_Char)( table.Tag >> 8 ), + (FT_Char)( table.Tag ) )); + + if ( FT_STREAM_SEEK( table.src_offset ) ) + goto Fail; + + if ( table.src_offset + table.src_length > transformed_buf_size ) + goto Fail; + + /* Get stream size for fields of `hmtx' table. */ + if ( table.Tag == TTAG_hhea ) + { + if ( read_num_hmetrics( stream, &num_hmetrics ) ) + goto Fail; + } + + info->num_hmetrics = num_hmetrics; + + checksum = 0; + if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) + { + /* Check whether `head' is at least 12 bytes. */ + if ( table.Tag == TTAG_head ) + { + if ( table.src_length < 12 ) + goto Fail; + + buf_cursor = transformed_buf + table.src_offset + 8; + /* Set checkSumAdjustment = 0 */ + WRITE_ULONG( buf_cursor, 0 ); + } + + table.dst_offset = dest_offset; + + checksum = compute_ULong_sum( transformed_buf + table.src_offset, + table.src_length ); + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + + if ( WRITE_SFNT_BUF( transformed_buf + table.src_offset, + table.src_length ) ) + goto Fail; + } + else + { + FT_TRACE3(( "This table is transformed.\n" )); + + if ( table.Tag == TTAG_glyf ) + { + is_glyf_xform = TRUE; + table.dst_offset = dest_offset; + + if ( reconstruct_glyf( stream, + &checksum, + &loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + info, + memory ) ) + goto Fail; + + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + } + + else if ( table.Tag == TTAG_loca ) + checksum = loca_checksum; + + else if ( table.Tag == TTAG_hmtx ) + { + /* If glyf is not transformed and hmtx is, handle separately. */ + if ( !is_glyf_xform ) + { + if ( get_x_mins( stream, indices, num_tables, info, memory ) ) + goto Fail; + } + + table.dst_offset = dest_offset; + + if ( reconstruct_hmtx( stream, + info->num_glyphs, + info->num_hmetrics, + info->x_mins, + &checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + } + else + { + /* Unknown transform. */ + FT_ERROR(( "Unknown table transform.\n" )); + goto Fail; + } + } + + font_checksum += checksum; + + buf_cursor = &table_entry[0]; + WRITE_ULONG( buf_cursor, table.Tag ); + WRITE_ULONG( buf_cursor, checksum ); + WRITE_ULONG( buf_cursor, table.dst_offset ); + WRITE_ULONG( buf_cursor, table.dst_length ); + + WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 ); + + /* Update checksum. */ + font_checksum += compute_ULong_sum( table_entry, 16 ); + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + /* Sanity check. */ + if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset ) + { + FT_ERROR(( "Table was partially written.\n" )); + goto Fail; + } + } + + /* Update `head' checkSumAdjustment. */ + info->head_table = find_table( indices, num_tables, TTAG_head ); + if ( !info->head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + goto Fail; + } + + if ( info->head_table->dst_length < 12 ) + goto Fail; + + buf_cursor = sfnt + info->head_table->dst_offset + 8; + font_checksum = 0xB1B0AFBA - font_checksum; + + WRITE_ULONG( buf_cursor, font_checksum ); + + FT_TRACE2(( "Final checksum = %09lx.\n", font_checksum )); + + woff2->actual_sfnt_size = dest_offset; + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + } + + + /* Replace `face->root.stream' with a stream containing the extracted */ + /* SFNT of a WOFF2 font. */ + + FT_LOCAL_DEF( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_instance_index, + FT_Long* num_faces ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + FT_Int face_index; + + WOFF2_HeaderRec woff2; + WOFF2_InfoRec info = { 0, 0, 0, NULL, NULL, NULL, NULL }; + WOFF2_Table tables = NULL; + WOFF2_Table* indices = NULL; + WOFF2_Table* temp_indices = NULL; + WOFF2_Table last_table; + + FT_Int nn; + FT_ULong j; + FT_ULong flags; + FT_UShort xform_version; + FT_ULong src_offset = 0; + + FT_UInt glyf_index; + FT_UInt loca_index; + FT_UInt32 file_offset; + + FT_Byte* sfnt = NULL; + FT_Stream sfnt_stream = NULL; + FT_ULong sfnt_size; + + FT_Byte* uncompressed_buf = NULL; + + static const FT_Frame_Field woff2_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WOFF2_HeaderRec + + FT_FRAME_START( 48 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_ULONG ( flavor ), + FT_FRAME_ULONG ( length ), + FT_FRAME_USHORT ( num_tables ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_ULONG ( totalSfntSize ), + FT_FRAME_ULONG ( totalCompressedSize ), + FT_FRAME_SKIP_BYTES( 2 * 2 ), + FT_FRAME_ULONG ( metaOffset ), + FT_FRAME_ULONG ( metaLength ), + FT_FRAME_ULONG ( metaOrigLength ), + FT_FRAME_ULONG ( privOffset ), + FT_FRAME_ULONG ( privLength ), + FT_FRAME_END + }; + + + FT_ASSERT( stream == face->root.stream ); + FT_ASSERT( FT_STREAM_POS() == 0 ); + + face_index = FT_ABS( *face_instance_index ) & 0xFFFF; + + /* Read WOFF2 Header. */ + if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) ) + return error; + + FT_TRACE4(( "signature -> 0x%lX\n", woff2.signature )); + FT_TRACE2(( "flavor -> 0x%08lx\n", woff2.flavor )); + FT_TRACE4(( "length -> %lu\n", woff2.length )); + FT_TRACE2(( "num_tables -> %hu\n", woff2.num_tables )); + FT_TRACE4(( "totalSfntSize -> %lu\n", woff2.totalSfntSize )); + FT_TRACE4(( "metaOffset -> %lu\n", woff2.metaOffset )); + FT_TRACE4(( "metaLength -> %lu\n", woff2.metaLength )); + FT_TRACE4(( "privOffset -> %lu\n", woff2.privOffset )); + FT_TRACE4(( "privLength -> %lu\n", woff2.privLength )); + + /* Make sure we don't recurse back here. */ + if ( woff2.flavor == TTAG_wOF2 ) + return FT_THROW( Invalid_Table ); + + /* Miscellaneous checks. */ + if ( woff2.length != stream->size || + woff2.num_tables == 0 || + woff2.num_tables > 0xFFFU || + 48 + woff2.num_tables * 20UL >= woff2.length || + ( woff2.metaOffset == 0 && ( woff2.metaLength != 0 || + woff2.metaOrigLength != 0 ) ) || + ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 ) || + ( woff2.metaOffset >= woff2.length ) || + ( woff2.length - woff2.metaOffset < woff2.metaLength ) || + ( woff2.privOffset == 0 && woff2.privLength != 0 ) || + ( woff2.privOffset >= woff2.length ) || + ( woff2.length - woff2.privOffset < woff2.privLength ) ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 header\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_open_font: WOFF2 Header is valid.\n" )); + + woff2.ttc_fonts = NULL; + + /* Read table directory. */ + if ( FT_QNEW_ARRAY( tables, woff2.num_tables ) || + FT_QNEW_ARRAY( indices, woff2.num_tables ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag flags transform origLen transformLen offset\n" )); + FT_TRACE2(( " -----------------------------------------------------------\n" )); + /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ + + for ( nn = 0; nn < woff2.num_tables; nn++ ) + { + WOFF2_Table table = tables + nn; + + + if ( FT_READ_BYTE( table->FlagByte ) ) + goto Exit; + + if ( ( table->FlagByte & 0x3f ) == 0x3f ) + { + if ( FT_READ_ULONG( table->Tag ) ) + goto Exit; + } + else + { + table->Tag = woff2_known_tags( table->FlagByte & 0x3f ); + if ( !table->Tag ) + { + FT_ERROR(( "woff2_open_font: Unknown table tag." )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + flags = 0; + xform_version = ( table->FlagByte >> 6 ) & 0x03; + + /* 0 means xform for glyph/loca, non-0 for others. */ + if ( table->Tag == TTAG_glyf || table->Tag == TTAG_loca ) + { + if ( xform_version == 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + } + else if ( xform_version != 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + + flags |= xform_version; + + if ( READ_BASE128( table->dst_length ) ) + goto Exit; + + table->TransformLength = table->dst_length; + + if ( ( flags & WOFF2_FLAGS_TRANSFORM ) != 0 ) + { + if ( READ_BASE128( table->TransformLength ) ) + goto Exit; + + if ( table->Tag == TTAG_loca && table->TransformLength ) + { + FT_ERROR(( "woff2_open_font: Invalid loca `transformLength'.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( src_offset + table->TransformLength < src_offset ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 table directory.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + table->flags = flags; + table->src_offset = src_offset; + table->src_length = table->TransformLength; + src_offset += table->TransformLength; + table->dst_offset = 0; + + FT_TRACE2(( " %c%c%c%c %08d %08d %08ld %08ld %08ld\n", + (FT_Char)( table->Tag >> 24 ), + (FT_Char)( table->Tag >> 16 ), + (FT_Char)( table->Tag >> 8 ), + (FT_Char)( table->Tag ), + table->FlagByte & 0x3f, + ( table->FlagByte >> 6 ) & 0x03, + table->dst_length, + table->TransformLength, + table->src_offset )); + + indices[nn] = table; + } + + /* End of last table is uncompressed size. */ + last_table = indices[woff2.num_tables - 1]; + + woff2.uncompressed_size = last_table->src_offset + + last_table->src_length; + if ( woff2.uncompressed_size < last_table->src_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "Table directory parsed.\n" )); + + /* Check for and read collection directory. */ + woff2.num_fonts = 1; + woff2.header_version = 0; + + if ( woff2.flavor == TTAG_ttcf ) + { + FT_TRACE2(( "Font is a TTC, reading collection directory.\n" )); + + if ( FT_READ_ULONG( woff2.header_version ) ) + goto Exit; + + if ( woff2.header_version != 0x00010000 && + woff2.header_version != 0x00020000 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( READ_255USHORT( woff2.num_fonts ) ) + goto Exit; + + if ( !woff2.num_fonts ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE4(( "Number of fonts in TTC: %d\n", woff2.num_fonts )); + + /* pre-zero pointers within in case of failure */ + if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) ) + goto Exit; + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + nn; + + + if ( READ_255USHORT( ttc_font->num_tables ) ) + goto Exit; + if ( FT_READ_ULONG( ttc_font->flavor ) ) + goto Exit; + + if ( FT_QNEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE5(( "Number of tables in font %d: %d\n", + nn, ttc_font->num_tables )); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( " Indices: " )); +#endif + + glyf_index = 0; + loca_index = 0; + + for ( j = 0; j < ttc_font->num_tables; j++ ) + { + FT_UShort table_index; + WOFF2_Table table; + + + if ( READ_255USHORT( table_index ) ) + goto Exit; + + FT_TRACE6(( "%hu ", table_index )); + if ( table_index >= woff2.num_tables ) + { + FT_ERROR(( "woff2_open_font: invalid table index\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + ttc_font->table_indices[j] = table_index; + + table = indices[table_index]; + if ( table->Tag == TTAG_loca ) + loca_index = table_index; + if ( table->Tag == TTAG_glyf ) + glyf_index = table_index; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( "\n" )); +#endif + + /* glyf and loca must be consecutive */ + if ( glyf_index > 0 || loca_index > 0 ) + { + if ( glyf_index > loca_index || + loca_index - glyf_index != 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + /* Collection directory reading complete. */ + FT_TRACE2(( "WOFF2 collection directory is valid.\n" )); + } + else + woff2.ttc_fonts = NULL; + + woff2.compressed_offset = FT_STREAM_POS(); + file_offset = ROUND4( woff2.compressed_offset + + woff2.totalCompressedSize ); + + /* Some more checks before we start reading the tables. */ + if ( file_offset > woff2.length ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( woff2.metaOffset ) + { + if ( file_offset != woff2.metaOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.metaOffset + woff2.metaLength ); + } + + if ( woff2.privOffset ) + { + if ( file_offset != woff2.privOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.privOffset + woff2.privLength ); + } + + if ( file_offset != ( ROUND4( woff2.length ) ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Validate requested face index. */ + *num_faces = woff2.num_fonts; + /* value -(N+1) requests information on index N */ + if ( *face_instance_index < 0 && face_index > 0 ) + face_index--; + + if ( face_index >= woff2.num_fonts ) + { + if ( *face_instance_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + else + face_index = 0; + } + + /* Only retain tables of the requested face in a TTC. */ + if ( woff2.header_version ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; + + + if ( ttc_font->num_tables == 0 || ttc_font->num_tables > 0xFFFU ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 CollectionFontEntry\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Create a temporary array. */ + if ( FT_QNEW_ARRAY( temp_indices, + ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + temp_indices[nn] = indices[ttc_font->table_indices[nn]]; + + /* Resize array to required size. */ + if ( FT_QRENEW_ARRAY( indices, + woff2.num_tables, + ttc_font->num_tables ) ) + goto Exit; + + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + indices[nn] = temp_indices[nn]; + + FT_FREE( temp_indices ); + + /* Change header values. */ + woff2.flavor = ttc_font->flavor; + woff2.num_tables = ttc_font->num_tables; + } + + /* We need to allocate this much at the minimum. */ + sfnt_size = 12 + woff2.num_tables * 16UL; + /* This is what we normally expect. */ + /* Initially trust `totalSfntSize' and change later as required. */ + if ( woff2.totalSfntSize > sfnt_size ) + { + /* However, adjust the value to something reasonable. */ + + /* Factor 64 is heuristic. */ + if ( ( woff2.totalSfntSize >> 6 ) > woff2.length ) + sfnt_size = woff2.length << 6; + else + sfnt_size = woff2.totalSfntSize; + + if ( sfnt_size >= MAX_SFNT_SIZE ) + sfnt_size = MAX_SFNT_SIZE; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( sfnt_size != woff2.totalSfntSize ) + FT_TRACE4(( "adjusting estimate of uncompressed font size" + " to %lu bytes\n", + sfnt_size )); +#endif + } + + /* Write sfnt header. */ + if ( FT_QALLOC( sfnt, sfnt_size ) || + FT_NEW( sfnt_stream ) ) + goto Exit; + + { + FT_Byte* sfnt_header = sfnt; + + FT_Int entrySelector = FT_MSB( woff2.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff2.num_tables * 16 - searchRange; + + + WRITE_ULONG ( sfnt_header, woff2.flavor ); + WRITE_USHORT( sfnt_header, woff2.num_tables ); + WRITE_USHORT( sfnt_header, searchRange ); + WRITE_USHORT( sfnt_header, entrySelector ); + WRITE_USHORT( sfnt_header, rangeShift ); + } + + info.header_checksum = compute_ULong_sum( sfnt, 12 ); + + /* Sort tables by tag. */ + ft_qsort( indices, + woff2.num_tables, + sizeof ( WOFF2_Table ), + compare_tags ); + + /* reject fonts that have multiple tables with the same tag */ + for ( nn = 1; nn < woff2.num_tables; nn++ ) + { + FT_Tag tag = indices[nn]->Tag; + + + if ( tag == indices[nn - 1]->Tag ) + { + FT_ERROR(( "woff2_open_font:" + " multiple tables with tag `%c%c%c%c'.\n", + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( woff2.uncompressed_size < 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* We must not blindly trust `uncompressed_size` since its */ + /* value might be corrupted. If it is too large, reject the */ + /* font. In other words, we don't accept a WOFF2 font that */ + /* expands to something larger than MAX_SFNT_SIZE. If ever */ + /* necessary, this limit can be easily adjusted. */ + if ( woff2.uncompressed_size > MAX_SFNT_SIZE ) + { + FT_ERROR(( "Uncompressed font too large.\n" )); + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + /* Allocate memory for uncompressed table data. */ + if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) || + FT_FRAME_ENTER( woff2.totalCompressedSize ) ) + goto Exit; + + /* Uncompress the stream. */ + error = woff2_decompress( uncompressed_buf, + woff2.uncompressed_size, + stream->cursor, + woff2.totalCompressedSize ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + error = reconstruct_font( uncompressed_buf, + woff2.uncompressed_size, + indices, + &woff2, + &info, + &sfnt, + &sfnt_size, + memory ); + + if ( error ) + goto Exit; + + /* Resize `sfnt' to actual size of sfnt stream. */ + if ( woff2.actual_sfnt_size < sfnt_size ) + { + FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n", + sfnt_size, woff2.actual_sfnt_size )); + if ( FT_QREALLOC( sfnt, + (FT_ULong)( sfnt_size ), + (FT_ULong)( woff2.actual_sfnt_size ) ) ) + goto Exit; + } + + /* `reconstruct_font' has done all the work. */ + /* Swap out stream and return. */ + FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.actual_sfnt_size ); + sfnt_stream->memory = stream->memory; + sfnt_stream->close = stream_close; + + FT_Stream_Free( + face->root.stream, + ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->root.stream = sfnt_stream; + face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + + /* Set face_index to 0 or -1. */ + if ( *face_instance_index >= 0 ) + *face_instance_index = 0; + else + *face_instance_index = -1; + + FT_TRACE2(( "woff2_open_font: SFNT synthesized.\n" )); + + Exit: + FT_FREE( tables ); + FT_FREE( indices ); + FT_FREE( uncompressed_buf ); + FT_FREE( info.x_mins ); + + if ( woff2.ttc_fonts ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts; + + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + FT_FREE( ttc_font->table_indices ); + ttc_font++; + } + + FT_FREE( woff2.ttc_fonts ); + } + + if ( error ) + { + FT_FREE( sfnt ); + if ( sfnt_stream ) + { + FT_Stream_Close( sfnt_stream ); + FT_FREE( sfnt_stream ); + } + } + + return error; + } + + +#undef READ_255USHORT +#undef READ_BASE128 +#undef ROUND4 +#undef WRITE_USHORT +#undef WRITE_ULONG +#undef WRITE_SHORT +#undef WRITE_SFNT_BUF +#undef WRITE_SFNT_BUF_AT + +#undef N_CONTOUR_STREAM +#undef N_POINTS_STREAM +#undef FLAG_STREAM +#undef GLYPH_STREAM +#undef COMPOSITE_STREAM +#undef BBOX_STREAM +#undef INSTRUCTION_STREAM + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff2_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/sfwoff2.h b/Dependencies/freetype/freetype/src/sfnt/sfwoff2.h new file mode 100644 index 00000000..f4114064 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/sfwoff2.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * + * sfwoff2.h + * + * WOFFF2 format management (specification). + * + * Copyright (C) 2019-2024 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SFWOFF2_H_ +#define SFWOFF2_H_ + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + /* Leave the first byte open to store `flag_byte'. */ +#define WOFF2_FLAGS_TRANSFORM 1 << 8 + +#define WOFF2_SFNT_HEADER_SIZE 12 +#define WOFF2_SFNT_ENTRY_SIZE 16 + + /* Suggested maximum size for output. */ +#define WOFF2_DEFAULT_MAX_SIZE 30 * 1024 * 1024 + + /* 98% of Google Fonts have no glyph above 5k bytes. */ +#define WOFF2_DEFAULT_GLYPH_BUF 5120 + + /* Composite glyph flags. */ + /* See `CompositeGlyph.java' in `sfntly' for full definitions. */ +#define FLAG_ARG_1_AND_2_ARE_WORDS 1 << 0 +#define FLAG_WE_HAVE_A_SCALE 1 << 3 +#define FLAG_MORE_COMPONENTS 1 << 5 +#define FLAG_WE_HAVE_AN_X_AND_Y_SCALE 1 << 6 +#define FLAG_WE_HAVE_A_TWO_BY_TWO 1 << 7 +#define FLAG_WE_HAVE_INSTRUCTIONS 1 << 8 + + /* Simple glyph flags */ +#define GLYF_ON_CURVE 1 << 0 +#define GLYF_X_SHORT 1 << 1 +#define GLYF_Y_SHORT 1 << 2 +#define GLYF_REPEAT 1 << 3 +#define GLYF_THIS_X_IS_SAME 1 << 4 +#define GLYF_THIS_Y_IS_SAME 1 << 5 +#define GLYF_OVERLAP_SIMPLE 1 << 6 + + /* Other constants */ +#define CONTOUR_OFFSET_END_POINT 10 + + + FT_LOCAL( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_index, + FT_Long* num_faces ); + +#endif /* FT_CONFIG_OPTION_USE_BROTLI */ + +FT_END_HEADER + +#endif /* SFWOFF2_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttbdf.c b/Dependencies/freetype/freetype/src/sfnt/ttbdf.c new file mode 100644 index 00000000..d9765f48 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttbdf.c @@ -0,0 +1,257 @@ +/**************************************************************************** + * + * ttbdf.c + * + * TrueType and OpenType embedded BDF properties (body). + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttbdf.h" + +#include "sferrors.h" + + +#ifdef TT_CONFIG_OPTION_BDF + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttbdf + + + FT_LOCAL_DEF( void ) + tt_face_free_bdf_props( TT_Face face ) + { + TT_BDF bdf = &face->bdf; + + + if ( bdf->loaded ) + { + FT_Stream stream = FT_FACE( face )->stream; + + + if ( bdf->table ) + FT_FRAME_RELEASE( bdf->table ); + + bdf->table_end = NULL; + bdf->strings = NULL; + bdf->strings_size = 0; + } + } + + + static FT_Error + tt_face_load_bdf_props( TT_Face face, + FT_Stream stream ) + { + TT_BDF bdf = &face->bdf; + FT_ULong length; + FT_Error error; + + + FT_ZERO( bdf ); + + error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); + if ( error || + length < 8 || + FT_FRAME_EXTRACT( length, bdf->table ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bdf->table_end = bdf->table + length; + + { + FT_Byte* p = bdf->table; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt num_strikes = FT_NEXT_USHORT( p ); + FT_ULong strings = FT_NEXT_ULONG ( p ); + FT_UInt count; + FT_Byte* strike; + + + if ( version != 0x0001 || + strings < 8 || + ( strings - 8 ) / 4 < num_strikes || + strings + 1 > length ) + { + goto BadTable; + } + + bdf->num_strikes = num_strikes; + bdf->strings = bdf->table + strings; + bdf->strings_size = length - strings; + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + count * 4; + + + for ( ; count > 0; count-- ) + { + FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); + + /* + * We don't need to check the value sets themselves, since this + * is done later. + */ + strike += 10 * num_items; + + p += 4; + } + + if ( strike > bdf->strings ) + goto BadTable; + } + + bdf->loaded = 1; + + Exit: + return error; + + BadTable: + FT_FRAME_RELEASE( bdf->table ); + FT_ZERO( bdf ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_find_bdf_prop( FT_Face face, /* TT_Face */ + const char* property_name, + BDF_PropertyRec *aprop ) + { + TT_Face ttface = (TT_Face)face; + TT_BDF bdf = &ttface->bdf; + FT_Size size = face->size; + FT_Error error = FT_Err_Ok; + FT_Byte* p; + FT_UInt count; + FT_Byte* strike; + FT_Offset property_len; + + + aprop->type = BDF_PROPERTY_TYPE_NONE; + + if ( bdf->loaded == 0 ) + { + error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) ); + if ( error ) + goto Exit; + } + + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + 4 * count; + + error = FT_ERR( Invalid_Argument ); + + if ( !size || !property_name ) + goto Exit; + + property_len = ft_strlen( property_name ); + if ( property_len == 0 ) + goto Exit; + + for ( ; count > 0; count-- ) + { + FT_UInt _ppem = FT_NEXT_USHORT( p ); + FT_UInt _count = FT_NEXT_USHORT( p ); + + + if ( _ppem == size->metrics.y_ppem ) + { + count = _count; + goto FoundStrike; + } + + strike += 10 * _count; + } + goto Exit; + + FoundStrike: + p = strike; + for ( ; count > 0; count-- ) + { + FT_UInt type = FT_PEEK_USHORT( p + 4 ); + + + if ( ( type & 0x10 ) != 0 ) + { + FT_UInt32 name_offset = FT_PEEK_ULONG( p ); + FT_UInt32 value = FT_PEEK_ULONG( p + 6 ); + + /* be a bit paranoid for invalid entries here */ + if ( name_offset < bdf->strings_size && + property_len < bdf->strings_size - name_offset && + ft_strncmp( property_name, + (const char*)bdf->strings + name_offset, + bdf->strings_size - name_offset ) == 0 ) + { + switch ( type & 0x0F ) + { + case 0x00: /* string */ + case 0x01: /* atoms */ + /* check that the content is really 0-terminated */ + if ( value < bdf->strings_size && + ft_memchr( bdf->strings + value, 0, bdf->strings_size ) ) + { + aprop->type = BDF_PROPERTY_TYPE_ATOM; + aprop->u.atom = (const char*)bdf->strings + value; + error = FT_Err_Ok; + goto Exit; + } + break; + + case 0x02: + aprop->type = BDF_PROPERTY_TYPE_INTEGER; + aprop->u.integer = (FT_Int32)value; + error = FT_Err_Ok; + goto Exit; + + case 0x03: + aprop->type = BDF_PROPERTY_TYPE_CARDINAL; + aprop->u.cardinal = value; + error = FT_Err_Ok; + goto Exit; + + default: + ; + } + } + } + p += 10; + } + + Exit: + return error; + } + +#else /* !TT_CONFIG_OPTION_BDF */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_bdf_dummy_; + +#endif /* !TT_CONFIG_OPTION_BDF */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttbdf.h b/Dependencies/freetype/freetype/src/sfnt/ttbdf.h new file mode 100644 index 00000000..d8d722b9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttbdf.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * ttbdf.h + * + * TrueType and OpenType embedded BDF properties (specification). + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTBDF_H_ +#define TTBDF_H_ + + +#include "ttload.h" +#include + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_BDF + + FT_LOCAL( void ) + tt_face_free_bdf_props( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_find_bdf_prop( FT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ); + +#endif /* TT_CONFIG_OPTION_BDF */ + + +FT_END_HEADER + +#endif /* TTBDF_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcmap.c b/Dependencies/freetype/freetype/src/sfnt/ttcmap.c new file mode 100644 index 00000000..28f4d117 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcmap.c @@ -0,0 +1,3902 @@ +/**************************************************************************** + * + * ttcmap.c + * + * TrueType character mapping table (cmap) support (body). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#include "sferrors.h" /* must come before `ftvalid.h' */ + +#include +#include +#include +#include "ttload.h" +#include "ttcmap.h" +#include "ttpost.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcmap + + +#define TT_PEEK_SHORT FT_PEEK_SHORT +#define TT_PEEK_USHORT FT_PEEK_USHORT +#define TT_PEEK_UINT24 FT_PEEK_UOFF3 +#define TT_PEEK_LONG FT_PEEK_LONG +#define TT_PEEK_ULONG FT_PEEK_ULONG + +#define TT_NEXT_SHORT FT_NEXT_SHORT +#define TT_NEXT_USHORT FT_NEXT_USHORT +#define TT_NEXT_UINT24 FT_NEXT_UOFF3 +#define TT_NEXT_LONG FT_NEXT_LONG +#define TT_NEXT_ULONG FT_NEXT_ULONG + + + /* Too large glyph index return values are caught in `FT_Get_Char_Index' */ + /* and `FT_Get_Next_Char' (the latter calls the internal `next' function */ + /* again in this case). To mark character code return values as invalid */ + /* it is sufficient to set the corresponding glyph index return value to */ + /* zero. */ + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_init( FT_CMap cmap, /* TT_CMap */ + void* table_ ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->data = table; + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 0 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 0 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * glyph_ids 6 BYTE[256] array of glyph indices + * 262 + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 262 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices whenever necessary */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt n, idx; + + + p = table + 6; + for ( n = 0; n < 256; n++ ) + { + idx = *p++; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + + + return char_code < 256 ? table[6 + char_code] : 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 charcode = *pchar_code; + FT_UInt32 result = 0; + FT_UInt gindex = 0; + + + table += 6; /* go to glyph IDs */ + while ( ++charcode < 256 ) + { + gindex = table[charcode]; + if ( gindex != 0 ) + { + result = charcode; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 0; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap0_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap0_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap0_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 0, + (TT_CMap_ValidateFunc)tt_cmap0_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap0_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 2 *****/ + /***** *****/ + /***** This is used for certain CJK encodings that encode text in a *****/ + /***** mixed 8/16 bits encoding along the following lines. *****/ + /***** *****/ + /***** * Certain byte values correspond to an 8-bit character code *****/ + /***** (typically in the range 0..127 for ASCII compatibility). *****/ + /***** *****/ + /***** * Certain byte values signal the first byte of a 2-byte *****/ + /***** character code (but these values are also valid as the *****/ + /***** second byte of a 2-byte character). *****/ + /***** *****/ + /***** The following charmap lookup and iteration functions all *****/ + /***** assume that the value `charcode' fulfills the following. *****/ + /***** *****/ + /***** - For one-byte characters, `charcode' is simply the *****/ + /***** character code. *****/ + /***** *****/ + /***** - For two-byte characters, `charcode' is the 2-byte *****/ + /***** character code in big endian format. More precisely: *****/ + /***** *****/ + /***** (charcode >> 8) is the first byte value *****/ + /***** (charcode & 0xFF) is the second byte value *****/ + /***** *****/ + /***** Note that not all values of `charcode' are valid according *****/ + /***** to these rules, and the function moderately checks the *****/ + /***** arguments. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 2 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * keys 6 USHORT[256] sub-header keys + * subs 518 SUBHEAD[NSUBS] sub-headers array + * glyph_ids 518+NSUB*8 USHORT[] glyph ID array + * + * The `keys' table is used to map charcode high bytes to sub-headers. + * The value of `NSUBS' is the number of sub-headers defined in the + * table and is computed by finding the maximum of the `keys' table. + * + * Note that for any `n', `keys[n]' is a byte offset within the `subs' + * table, i.e., it is the corresponding sub-header index multiplied + * by 8. + * + * Each sub-header has the following format. + * + * NAME OFFSET TYPE DESCRIPTION + * + * first 0 USHORT first valid low-byte + * count 2 USHORT number of valid low-bytes + * delta 4 SHORT see below + * offset 6 USHORT see below + * + * A sub-header defines, for each high byte, the range of valid + * low bytes within the charmap. Note that the range defined by `first' + * and `count' must be completely included in the interval [0..255] + * according to the specification. + * + * If a character code is contained within a given sub-header, then + * mapping it to a glyph index is done as follows. + * + * - The value of `offset' is read. This is a _byte_ distance from the + * location of the `offset' field itself into a slice of the + * `glyph_ids' table. Let's call it `slice' (it is a USHORT[], too). + * + * - The value `slice[char.lo - first]' is read. If it is 0, there is + * no glyph for the charcode. Otherwise, the value of `delta' is + * added to it (modulo 65536) to form a new glyph index. + * + * It is up to the validation routine to check that all offsets fall + * within the glyph IDs table (and not within the `subs' table itself or + * outside of the CMap). + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + FT_UInt n, max_subs; + FT_Byte* keys; /* keys table */ + FT_Byte* subs; /* sub-headers */ + FT_Byte* glyph_ids; /* glyph ID array */ + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 6 + 512 ) + FT_INVALID_TOO_SHORT; + + keys = table + 6; + + /* parse keys to compute sub-headers count */ + p = keys; + max_subs = 0; + for ( n = 0; n < 256; n++ ) + { + FT_UInt idx = TT_NEXT_USHORT( p ); + + + /* value must be multiple of 8 */ + if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) + FT_INVALID_DATA; + + idx >>= 3; + + if ( idx > max_subs ) + max_subs = idx; + } + + FT_ASSERT( p == table + 518 ); + + subs = p; + glyph_ids = subs + ( max_subs + 1 ) * 8; + if ( glyph_ids > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* parse sub-headers */ + for ( n = 0; n <= max_subs; n++ ) + { + FT_UInt first_code, code_count, offset; + FT_Int delta; + + + first_code = TT_NEXT_USHORT( p ); + code_count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT( p ); + offset = TT_NEXT_USHORT( p ); + + /* many Dynalab fonts have empty sub-headers */ + if ( code_count == 0 ) + continue; + + /* check range within 0..255 */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + if ( first_code >= 256 || code_count > 256 - first_code ) + FT_INVALID_DATA; + } + + /* check offset */ + if ( offset != 0 ) + { + FT_Byte* ids; + + + ids = p - 2 + offset; + if ( ids < glyph_ids || ids + code_count * 2 > table + length ) + FT_INVALID_OFFSET; + + /* check glyph IDs */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_Byte* limit = p + code_count * 2; + FT_UInt idx; + + + for ( ; p < limit; ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + } + + return FT_Err_Ok; + } + + + /* return sub header corresponding to a given character code */ + /* NULL on invalid charcode */ + static FT_Byte* + tt_cmap2_get_subheader( FT_Byte* table, + FT_UInt32 char_code ) + { + FT_Byte* result = NULL; + + + if ( char_code < 0x10000UL ) + { + FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); + FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); + FT_Byte* p = table + 6; /* keys table */ + FT_Byte* subs = table + 518; /* subheaders table */ + FT_Byte* sub; + + + if ( char_hi == 0 ) + { + /* an 8-bit character code -- we use subHeader 0 in this case */ + /* to test whether the character code is in the charmap */ + /* */ + sub = subs; /* jump to first sub-header */ + + /* check that the sub-header for this byte is 0, which */ + /* indicates that it is really a valid one-byte value; */ + /* otherwise, return 0 */ + /* */ + p += char_lo * 2; + if ( TT_PEEK_USHORT( p ) != 0 ) + goto Exit; + } + else + { + /* a 16-bit character code */ + + /* jump to key entry */ + p += char_hi * 2; + /* jump to sub-header */ + sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); + + /* check that the high byte isn't a valid one-byte value */ + if ( sub == subs ) + goto Exit; + } + + result = sub; + } + + Exit: + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* subheader; + + + subheader = tt_cmap2_get_subheader( table, char_code ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt idx = (FT_UInt)( char_code & 0xFF ); + FT_UInt start, count; + FT_Int delta; + FT_UInt offset; + + + start = TT_NEXT_USHORT( p ); + count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT ( p ); + offset = TT_PEEK_USHORT( p ); + + idx -= start; + if ( idx < count && offset != 0 ) + { + p += offset + 2 * idx; + idx = TT_PEEK_USHORT( p ); + + if ( idx != 0 ) + result = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + } + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pcharcode ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 charcode = *pcharcode + 1; + FT_Byte* subheader; + + + while ( charcode < 0x10000UL ) + { + subheader = tt_cmap2_get_subheader( table, charcode ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_Int delta = TT_NEXT_SHORT ( p ); + FT_UInt offset = TT_PEEK_USHORT( p ); + FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); + FT_UInt pos, idx; + + + if ( char_lo >= start + count && charcode <= 0xFF ) + { + /* this happens only for a malformed cmap */ + charcode = 0x100; + continue; + } + + if ( offset == 0 ) + { + if ( charcode == 0x100 ) + goto Exit; /* this happens only for a malformed cmap */ + goto Next_SubHeader; + } + + if ( char_lo < start ) + { + char_lo = start; + pos = 0; + } + else + pos = (FT_UInt)( char_lo - start ); + + p += offset + pos * 2; + charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; + + for ( ; pos < count; pos++, charcode++ ) + { + idx = TT_NEXT_USHORT( p ); + + if ( idx != 0 ) + { + gindex = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = charcode; + goto Exit; + } + } + } + + /* if unsuccessful, avoid `charcode' leaving */ + /* the current 256-character block */ + if ( count ) + charcode--; + } + + /* If `charcode' is <= 0xFF, retry with `charcode + 1'. */ + /* Otherwise jump to the next 256-character block and retry. */ + Next_SubHeader: + if ( charcode <= 0xFF ) + charcode++; + else + charcode = FT_PAD_FLOOR( charcode, 0x100 ) + 0x100; + } + + Exit: + *pcharcode = result; + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 2; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap2_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap2_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap2_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 2, + (TT_CMap_ValidateFunc)tt_cmap2_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap2_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_2 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 4 + * length 2 USHORT table length + * in bytes + * language 4 USHORT Mac language code + * + * segCountX2 6 USHORT 2*NUM_SEGS + * searchRange 8 USHORT 2*(1 << LOG_SEGS) + * entrySelector 10 USHORT LOG_SEGS + * rangeShift 12 USHORT segCountX2 - + * searchRange + * + * endCount 14 USHORT[NUM_SEGS] end charcode for + * each segment; last + * is 0xFFFF + * + * pad 14+NUM_SEGS*2 USHORT padding + * + * startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for + * each segment + * + * idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each + * segment + * idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for + * each segment; can be + * zero + * + * glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph ID + * ranges + * + * Character codes are modelled by a series of ordered (increasing) + * intervals called segments. Each segment has start and end codes, + * provided by the `startCount' and `endCount' arrays. Segments must + * not overlap, and the last segment should always contain the value + * 0xFFFF for `endCount'. + * + * The fields `searchRange', `entrySelector' and `rangeShift' are better + * ignored (they are traces of over-engineering in the TrueType + * specification). + * + * Each segment also has a signed `delta', as well as an optional offset + * within the `glyphIds' table. + * + * If a segment's idOffset is 0, the glyph index corresponding to any + * charcode within the segment is obtained by adding the value of + * `idDelta' directly to the charcode, modulo 65536. + * + * Otherwise, a glyph index is taken from the glyph IDs sub-array for + * the segment, and the value of `idDelta' is added to it. + * + * + * Finally, note that a lot of fonts contain an invalid last segment, + * where `start' and `end' are correctly set to 0xFFFF but both `delta' + * and `offset' are incorrect (e.g., `opens___.ttf' which comes with + * OpenOffice.org). We need special code to deal with them correctly. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + + typedef struct TT_CMap4Rec_ + { + TT_CMapRec cmap; + FT_UInt32 cur_charcode; /* current charcode */ + FT_UInt cur_gindex; /* current glyph index */ + + FT_UInt num_ranges; + FT_UInt cur_range; + FT_UInt cur_start; + FT_UInt cur_end; + FT_Int cur_delta; + FT_Byte* cur_values; + + } TT_CMap4Rec, *TT_CMap4; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */ + void* table_ ) + { + TT_CMap4 ttcmap = (TT_CMap4)cmap; + FT_Byte* table = (FT_Byte*)table_; + FT_Byte* p; + + + ttcmap->cmap.data = table; + + p = table + 6; + ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + ttcmap->cur_gindex = 0; + + return FT_Err_Ok; + } + + + static FT_Int + tt_cmap4_set_range( TT_CMap4 cmap, + FT_UInt range_index ) + { + FT_Byte* table = cmap->cmap.data; + FT_Byte* p; + FT_UInt num_ranges = cmap->num_ranges; + + + while ( range_index < num_ranges ) + { + FT_UInt offset; + + + p = table + 14 + range_index * 2; + cmap->cur_end = FT_PEEK_USHORT( p ); + + p += 2 + num_ranges * 2; + cmap->cur_start = FT_PEEK_USHORT( p ); + + p += num_ranges * 2; + cmap->cur_delta = FT_PEEK_SHORT( p ); + + p += num_ranges * 2; + offset = FT_PEEK_USHORT( p ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( range_index >= num_ranges - 1 && + cmap->cur_start == 0xFFFFU && + cmap->cur_end == 0xFFFFU ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + + if ( offset && p + offset + 2 > limit ) + { + cmap->cur_delta = 1; + offset = 0; + } + } + + if ( offset != 0xFFFFU ) + { + cmap->cur_values = offset ? p + offset : NULL; + cmap->cur_range = range_index; + return 0; + } + + /* we skip empty segments */ + range_index++; + } + + return -1; + } + + + /* search the index of the charcode next to cmap->cur_charcode; */ + /* caller should call tt_cmap4_set_range with proper range */ + /* before calling this function */ + /* */ + static void + tt_cmap4_next( TT_CMap4 cmap ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + FT_UInt charcode; + + + charcode = (FT_UInt)cmap->cur_charcode + 1; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + + for (;;) + { + FT_Byte* values = cmap->cur_values; + FT_UInt end = cmap->cur_end; + FT_Int delta = cmap->cur_delta; + + + if ( charcode <= end ) + { + if ( values ) + { + FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); + + + /* if p > limit, the whole segment is invalid */ + if ( p > limit ) + goto Next_Segment; + + do + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } + } while ( ++charcode <= end ); + } + else + { + do + { + FT_UInt gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + + else + goto Next_Segment; + } + + if ( gindex ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } while ( ++charcode <= end ); + } + } + + Next_Segment: + /* we need to find another range */ + if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) + break; + + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + } + + cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + cmap->cur_gindex = 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length; + + FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; + FT_UInt num_segs; + FT_Error error = FT_Err_Ok; + + + if ( table + 2 + 2 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; /* skip format */ + length = TT_NEXT_USHORT( p ); + + /* in certain fonts, the `length' field is invalid and goes */ + /* out of bound. We try to correct this here... */ + if ( table + length > valid->limit ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_TOO_SHORT; + + length = (FT_UInt)( valid->limit - table ); + } + + /* it also happens that the `length' field is too small; */ + /* this is easy to correct */ + if ( length < (FT_UInt)( valid->limit - table ) ) + { + if ( valid->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + + length = (FT_UInt)( valid->limit - table ); + } + + if ( length < 16 ) + FT_INVALID_TOO_SHORT; + + p = table + 6; + num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ + + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check that we have an even value here */ + if ( num_segs & 1 ) + FT_INVALID_DATA; + } + + num_segs /= 2; + + if ( length < 16 + num_segs * 2 * 4 ) + FT_INVALID_TOO_SHORT; + + /* check the search parameters - even though we never use them */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check the values of `searchRange', `entrySelector', `rangeShift' */ + FT_UInt search_range = TT_NEXT_USHORT( p ); + FT_UInt entry_selector = TT_NEXT_USHORT( p ); + FT_UInt range_shift = TT_NEXT_USHORT( p ); + + + if ( ( search_range | range_shift ) & 1 ) /* must be even values */ + FT_INVALID_DATA; + + search_range /= 2; + range_shift /= 2; + + /* `search range' is the greatest power of 2 that is <= num_segs */ + + if ( search_range > num_segs || + search_range * 2 < num_segs || + search_range + range_shift != num_segs || + search_range != ( 1U << entry_selector ) ) + FT_INVALID_DATA; + } + + ends = table + 14; + starts = table + 16 + num_segs * 2; + deltas = starts + num_segs * 2; + offsets = deltas + num_segs * 2; + glyph_ids = offsets + num_segs * 2; + + /* check last segment; its end count value must be 0xFFFF */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + p = ends + ( num_segs - 1 ) * 2; + if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) + FT_INVALID_DATA; + } + + { + FT_UInt start, end, offset, n; + FT_UInt last_start = 0, last_end = 0; + FT_Int delta; + FT_Byte* p_start = starts; + FT_Byte* p_end = ends; + FT_Byte* p_delta = deltas; + FT_Byte* p_offset = offsets; + + + for ( n = 0; n < num_segs; n++ ) + { + p = p_offset; + start = TT_NEXT_USHORT( p_start ); + end = TT_NEXT_USHORT( p_end ); + delta = TT_NEXT_SHORT( p_delta ); + offset = TT_NEXT_USHORT( p_offset ); + + if ( start > end ) + FT_INVALID_DATA; + + /* this test should be performed at default validation level; */ + /* unfortunately, some popular Asian fonts have overlapping */ + /* ranges in their charmaps */ + /* */ + if ( start <= last_end && n > 0 ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + else + { + /* allow overlapping segments, provided their start points */ + /* and end points, respectively, are in ascending order */ + /* */ + if ( last_start > start || last_end > end ) + error |= TT_CMAP_FLAG_UNSORTED; + else + error |= TT_CMAP_FLAG_OVERLAPPING; + } + } + + if ( offset && offset != 0xFFFFU ) + { + p += offset; /* start of glyph ID array */ + + /* check that we point within the glyph IDs table only */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > table + length ) + FT_INVALID_DATA; + } + /* Some fonts handle the last segment incorrectly. In */ + /* theory, 0xFFFF might point to an ordinary glyph -- */ + /* a cmap 4 is versatile and could be used for any */ + /* encoding, not only Unicode. However, reality shows */ + /* that far too many fonts are sloppy and incorrectly */ + /* set all fields but `start' and `end' for the last */ + /* segment if it contains only a single character. */ + /* */ + /* We thus omit the test here, delaying it to the */ + /* routines that actually access the cmap. */ + else if ( n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > valid->limit ) + FT_INVALID_DATA; + } + + /* check glyph indices within the segment range */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt i, idx; + + + for ( i = start; i < end; i++ ) + { + idx = FT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU; + + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + else if ( offset == 0xFFFFU ) + { + /* some fonts (erroneously?) use a range offset of 0xFFFF */ + /* to mean missing glyph in cmap table */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID || + n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + FT_INVALID_DATA; + } + + last_start = start; + last_end = end; + } + } + + return error; + } + + + static FT_UInt + tt_cmap4_char_map_linear( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt i, num_segs; + FT_UInt32 charcode = *pcharcode + next; + FT_UInt gindex = 0; + FT_Byte* p; + FT_Byte* q; + + + p = cmap->data + 6; + num_segs = TT_PEEK_USHORT( p ) >> 1; + + if ( !num_segs ) + return 0; + + num_segs2 = num_segs << 1; + + /* linear search */ + p = cmap->data + 14; /* ends table */ + q = cmap->data + 16 + num_segs2; /* starts table */ + + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); + + if ( charcode < start ) + { + if ( next ) + charcode = start; + else + break; + } + + Again: + if ( charcode <= end ) + { + FT_Byte* r; + + + r = q - 2 + num_segs2; + delta = TT_PEEK_SHORT( r ); + r += num_segs2; + offset = TT_PEEK_USHORT( r ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( i >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + if ( offset && r + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } + + if ( offset == 0xFFFFU ) + continue; + + if ( offset ) + { + r += offset + ( charcode - start ) * 2; + + /* if r > limit, the whole segment is invalid */ + if ( next && r > limit ) + continue; + + gindex = TT_PEEK_USHORT( r ); + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + gindex = 0; + } + } + else + { + gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + if ( next && gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + + else + continue; + } + } + + if ( next && !gindex ) + { + if ( charcode >= 0xFFFFU ) + break; + + charcode++; + goto Again; + } + + break; + } + } + + if ( next ) + *pcharcode = charcode; + + return gindex; + } + + + static FT_UInt + tt_cmap4_char_map_binary( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Byte* limit = face->cmap_table + face->cmap_size; + + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt max, min, mid, num_segs; + FT_UInt charcode = (FT_UInt)*pcharcode + next; + FT_UInt gindex = 0; + FT_Byte* p; + + + p = cmap->data + 6; + num_segs = TT_PEEK_USHORT( p ) >> 1; + + if ( !num_segs ) + return 0; + + num_segs2 = num_segs << 1; + + min = 0; + max = num_segs; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + + if ( charcode < start ) + max = mid; + else if ( charcode > end ) + min = mid + 1; + else + { + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + /* some fonts have an incorrect last segment; */ + /* we have to catch it */ + if ( mid >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + if ( offset && p + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } + + /* search the first segment containing `charcode' */ + if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING ) + { + FT_UInt i; + + + /* call the current segment `max' */ + max = mid; + + if ( offset == 0xFFFFU ) + mid = max + 1; + + /* search in segments before the current segment */ + for ( i = max; i > 0; i-- ) + { + FT_UInt prev_end; + FT_Byte* old_p; + + + old_p = p; + p = cmap->data + 14 + ( i - 1 ) * 2; + prev_end = TT_PEEK_USHORT( p ); + + if ( charcode > prev_end ) + { + p = old_p; + break; + } + + end = prev_end; + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i - 1; + } + + /* no luck */ + if ( mid == max + 1 ) + { + if ( i != max ) + { + p = cmap->data + 14 + max * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + + mid = max; + + /* search in segments after the current segment */ + for ( i = max + 1; i < num_segs; i++ ) + { + FT_UInt next_end, next_start; + + + p = cmap->data + 14 + i * 2; + next_end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + next_start = TT_PEEK_USHORT( p ); + + if ( charcode < next_start ) + break; + + end = next_end; + start = next_start; + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + mid = i; + } + i--; + + /* still no luck */ + if ( mid == max ) + { + mid = i; + + break; + } + } + + /* end, start, delta, and offset are for the i'th segment */ + if ( mid != i ) + { + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + } + else + { + if ( offset == 0xFFFFU ) + break; + } + + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + + /* if p > limit, the whole segment is invalid */ + if ( next && p > limit ) + break; + + gindex = TT_PEEK_USHORT( p ); + if ( gindex ) + { + gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU; + if ( gindex >= (FT_UInt)face->root.num_glyphs ) + gindex = 0; + } + } + else + { + gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU; + + if ( next && gindex >= (FT_UInt)face->root.num_glyphs ) + { + /* we have an invalid glyph index; if there is an overflow, */ + /* we can adjust `charcode', otherwise the whole segment is */ + /* invalid */ + gindex = 0; + + if ( (FT_Int)charcode + delta < 0 && + (FT_Int)end + delta >= 0 ) + charcode = (FT_UInt)( -delta ); + + else if ( (FT_Int)charcode + delta < 0x10000L && + (FT_Int)end + delta >= 0x10000L ) + charcode = (FT_UInt)( 0x10000L - delta ); + } + } + + break; + } + } + while ( min < max ); + + if ( next ) + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* if `charcode' is not in any segment, then `mid' is */ + /* the segment nearest to `charcode' */ + + if ( charcode > end && ++mid == num_segs ) + return 0; + + if ( tt_cmap4_set_range( cmap4, mid ) ) + { + if ( gindex ) + *pcharcode = charcode; + } + else + { + cmap4->cur_charcode = charcode; + + if ( gindex ) + cmap4->cur_gindex = gindex; + else + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + } + + if ( gindex ) + *pcharcode = cmap4->cur_charcode; + } + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + + if ( char_code >= 0x10000UL ) + return 0; + + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 ); + else + return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFU ) + return 0; + + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 ); + else + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + /* no need to search */ + if ( *pchar_code == cmap4->cur_charcode ) + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + if ( gindex ) + *pchar_code = cmap4->cur_charcode; + } + else + gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 ); + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 4; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap4_class_rec, + + sizeof ( TT_CMap4Rec ), + + (FT_CMap_InitFunc) tt_cmap4_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap4_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap4_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 4, + (TT_CMap_ValidateFunc)tt_cmap4_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap4_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_4 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 6 + * length 2 USHORT table length in bytes + * language 4 USHORT Mac language code + * + * first 6 USHORT first segment code + * count 8 USHORT segment size in chars + * glyphIds 10 USHORT[count] glyph IDs + * + * A very simplified segment mapping. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length, count; + + + if ( table + 10 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_USHORT( p ); + + p = table + 8; /* skip language and start index */ + count = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 10 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx = (FT_UInt)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx; + + + if ( char_code >= 0x10000UL ) + return 0; + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + result = char_code; + break; + } + + if ( char_code >= 0xFFFFU ) + return 0; + + char_code++; + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; + + + cmap_info->format = 6; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap6_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap6_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap6_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 6, + (TT_CMap_ValidateFunc)tt_cmap6_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap6_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_6 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 8 *****/ + /***** *****/ + /***** It is hard to completely understand what the OpenType spec *****/ + /***** says about this format, but here is my conclusion. *****/ + /***** *****/ + /***** The purpose of this format is to easily map UTF-16 text to *****/ + /***** glyph indices. Basically, the `char_code' must be in one of *****/ + /***** the following formats. *****/ + /***** *****/ + /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ + /***** Area (i.e. U+D800-U+DFFF). *****/ + /***** *****/ + /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ + /***** `char_code = (char_hi << 16) | char_lo', then both *****/ + /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ + /***** Area. *****/ + /***** *****/ + /***** The `is32' table embedded in the charmap indicates whether a *****/ + /***** given 16-bit value is in the surrogates area or not. *****/ + /***** *****/ + /***** So, for any given `char_code', we can assert the following. *****/ + /***** *****/ + /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ + /***** *****/ + /***** If `char_hi != 0' then we must have both *****/ + /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 8 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * is32 12 BYTE[8192] 32-bitness bitmap + * count 8204 ULONG number of groups + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * startId 8 ULONG start glyph ID for the group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_Byte* is32; + FT_UInt32 length; + FT_UInt32 num_groups; + + + if ( table + 16 + 8192 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + if ( length > (FT_UInt32)( valid->limit - table ) || length < 8192 + 16 ) + FT_INVALID_TOO_SHORT; + + is32 = table + 12; + p = is32 + 8192; /* skip `is32' array */ + num_groups = TT_NEXT_ULONG( p ); + + /* p + num_groups * 12 > valid->limit ? */ + if ( num_groups > (FT_UInt32)( valid->limit - p ) / 12 ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_UInt32 n, start, end, start_id, count, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + FT_UInt hi, lo; + + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt32 d = end - start; + + + /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */ + if ( d > TT_VALID_GLYPH_COUNT( valid ) || + start_id >= TT_VALID_GLYPH_COUNT( valid ) - d ) + FT_INVALID_GLYPH_ID; + + count = (FT_UInt32)( end - start + 1 ); + + if ( start & ~0xFFFFU ) + { + /* start_hi != 0; check that is32[i] is 1 for each i in */ + /* the `hi' and `lo' of the range [start..end] */ + for ( ; count > 0; count--, start++ ) + { + hi = (FT_UInt)( start >> 16 ); + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + } + } + else + { + /* start_hi == 0; check that is32[i] is 0 for each i in */ + /* the range [start..end] */ + + /* end_hi cannot be != 0! */ + if ( end & ~0xFFFFU ) + FT_INVALID_DATA; + + for ( ; count > 0; count--, start++ ) + { + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) + FT_INVALID_DATA; + } + } + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + break; + + if ( char_code <= end ) + { + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + return 0; + + result = (FT_UInt)( start_id + ( char_code - start ) ); + break; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_UInt32 result = 0; + FT_UInt32 char_code; + FT_UInt gindex = 0; + FT_Byte* table = ttcmap->data; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + + p = table + 8208; + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + Again: + if ( char_code <= end ) + { + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; + + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) + { + if ( char_code >= 0xFFFFFFFFUL ) + break; + + char_code++; + goto Again; + } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + { + gindex = 0; + continue; + } + + result = char_code; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 8; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap8_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap8_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap8_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 8, + (TT_CMap_ValidateFunc)tt_cmap8_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap8_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_8 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 10 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 10 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * + * start 12 ULONG first char in range + * count 16 ULONG number of chars in range + * glyphIds 20 USHORT[count] glyph indices covered + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_ULong length, count; + + + if ( table + 20 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + p = table + 16; + count = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 20 + count * 2 ? */ + length < 20 || + ( length - 20 ) / 2 < count ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( char_code < start ) + return 0; + + idx = char_code - start; + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 *pchar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; + FT_UInt32 char_code; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + char_code = *pchar_code + 1; + + if ( char_code < start ) + char_code = start; + + idx = char_code - start; + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + break; + + if ( char_code >= 0xFFFFFFFFUL ) + return 0; + + char_code++; + } + + *pchar_code = char_code; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 10; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap10_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap10_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap10_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 10, + (TT_CMap_ValidateFunc)tt_cmap10_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap10_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_10 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 12 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 12 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * count 12 ULONG number of groups + * 16 + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * startId 8 ULONG start glyph ID for the group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + + typedef struct TT_CMap12Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + + } TT_CMap12Rec, *TT_CMap12; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */ + void* table_ ) + { + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 16 + 12 * num_groups ? */ + length < 16 || + ( length - 16 ) / 12 < num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, start_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt32 d = end - start; + + + /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */ + if ( d > TT_VALID_GLYPH_COUNT( valid ) || + start_id >= TT_VALID_GLYPH_COUNT( valid ) - d ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + /* search the index of the charcode next to cmap->cur_charcode */ + /* cmap->cur_group should be set up properly by caller */ + /* */ + static void + tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */ + { + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, start_id, char_code; + FT_ULong n; + FT_UInt gindex; + + + char_code = ttcmap->cur_charcode + 1; + + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) + { + p = ttcmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_PEEK_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + Again: + if ( char_code <= end ) + { + /* ignore invalid group */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + continue; + + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + + /* does first element of group point to `.notdef' glyph? */ + if ( gindex == 0 ) + { + if ( char_code >= 0xFFFFFFFFUL ) + goto Fail; + + char_code++; + goto Again; + } + + /* if `gindex' is invalid, the remaining values */ + /* in this group are invalid, too */ + if ( gindex >= (FT_UInt)face->num_glyphs ) + continue; + + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; + + return; + } + } + + Fail: + ttcmap->valid = 0; + } + + + static FT_UInt + tt_cmap12_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code + next; + FT_UInt32 start, end, start_id; + FT_UInt32 max, min, mid; + + + if ( !num_groups ) + return 0; + + min = 0; + max = num_groups; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + start_id = TT_PEEK_ULONG( p ); + + /* reject invalid glyph index */ + if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) ) + gindex = 0; + else + gindex = (FT_UInt)( start_id + ( char_code - start ) ); + break; + } + } + while ( min < max ); + + if ( next ) + { + FT_Face face = FT_CMAP_FACE( cmap ); + TT_CMap12 cmap12 = (TT_CMap12)cmap; + + + /* if `char_code' is not in any group, then `mid' is */ + /* the group nearest to `char_code' */ + + if ( char_code > end && ++mid == num_groups ) + return 0; + + cmap12->valid = 1; + cmap12->cur_charcode = char_code; + cmap12->cur_group = mid; + + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + + if ( !gindex ) + { + tt_cmap12_next( FT_CMAP( cmap12 ) ); + + if ( cmap12->valid ) + gindex = cmap12->cur_gindex; + } + else + cmap12->cur_gindex = gindex; + + *pchar_code = cmap12->cur_charcode; + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */ + FT_UInt32 *pchar_code ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + /* no need to search */ + if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) + { + tt_cmap12_next( FT_CMAP( cmap12 ) ); + if ( cmap12->valid ) + { + gindex = cmap12->cur_gindex; + *pchar_code = (FT_UInt32)cmap12->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 12; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap12_class_rec, + + sizeof ( TT_CMap12Rec ), + + (FT_CMap_InitFunc) tt_cmap12_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap12_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap12_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 12, + (TT_CMap_ValidateFunc)tt_cmap12_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap12_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_12 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 13 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 13 + * reserved 2 USHORT reserved + * length 4 ULONG length in bytes + * language 8 ULONG Mac language code + * count 12 ULONG number of groups + * 16 + * + * This header is followed by `count' groups of the following format: + * + * start 0 ULONG first charcode + * end 4 ULONG last charcode + * glyphId 8 ULONG glyph ID for the whole group + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_13 + + typedef struct TT_CMap13Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + + } TT_CMap13Rec, *TT_CMap13; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */ + void* table_ ) + { + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 16 + 12 * num_groups ? */ + length < 16 || + ( length - 16 ) / 12 < num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, glyph_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( glyph_id >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return FT_Err_Ok; + } + + + /* search the index of the charcode next to cmap->cur_charcode */ + /* cmap->cur_group should be set up properly by caller */ + /* */ + static void + tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */ + { + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, glyph_id, char_code; + FT_ULong n; + FT_UInt gindex; + + + char_code = ttcmap->cur_charcode + 1; + + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) + { + p = ttcmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_PEEK_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + if ( char_code <= end ) + { + gindex = (FT_UInt)glyph_id; + + if ( gindex && gindex < (FT_UInt)face->num_glyphs ) + { + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; + + return; + } + } + } + + ttcmap->valid = 0; + } + + + static FT_UInt + tt_cmap13_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code + next; + FT_UInt32 start, end; + FT_UInt32 max, min, mid; + + + if ( !num_groups ) + return 0; + + min = 0; + max = num_groups; + + /* binary search */ + do + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + gindex = (FT_UInt)TT_PEEK_ULONG( p ); + + break; + } + } + while ( min < max ); + + if ( next ) + { + FT_Face face = cmap->cmap.charmap.face; + TT_CMap13 cmap13 = (TT_CMap13)cmap; + + + /* if `char_code' is not in any group, then `mid' is */ + /* the group nearest to `char_code' */ + + if ( char_code > end && ++mid == num_groups ) + return 0; + + cmap13->valid = 1; + cmap13->cur_charcode = char_code; + cmap13->cur_group = mid; + + if ( gindex >= (FT_UInt)face->num_glyphs ) + gindex = 0; + + if ( !gindex ) + { + tt_cmap13_next( FT_CMAP( cmap13 ) ); + + if ( cmap13->valid ) + gindex = cmap13->cur_gindex; + } + else + cmap13->cur_gindex = gindex; + + *pchar_code = cmap13->cur_charcode; + } + + return gindex; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 char_code ) + { + return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */ + FT_UInt32 *pchar_code ) + { + TT_CMap13 cmap13 = (TT_CMap13)cmap; + FT_UInt gindex; + + + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + + /* no need to search */ + if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) + { + tt_cmap13_next( FT_CMAP( cmap13 ) ); + if ( cmap13->valid ) + { + gindex = cmap13->cur_gindex; + *pchar_code = cmap13->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */ + TT_CMapInfo *cmap_info ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; + + + cmap_info->format = 13; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return FT_Err_Ok; + } + + + FT_DEFINE_TT_CMAP( + tt_cmap13_class_rec, + + sizeof ( TT_CMap13Rec ), + + (FT_CMap_InitFunc) tt_cmap13_init, /* init */ + (FT_CMap_DoneFunc) NULL, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap13_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap13_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + 13, + (TT_CMap_ValidateFunc)tt_cmap13_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap13_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_13 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 14 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * TABLE OVERVIEW + * -------------- + * + * NAME OFFSET TYPE DESCRIPTION + * + * format 0 USHORT must be 14 + * length 2 ULONG table length in bytes + * numSelector 6 ULONG number of variation sel. records + * + * Followed by numSelector records, each of which looks like + * + * varSelector 0 UINT24 Unicode codepoint of sel. + * defaultOff 3 ULONG offset to a default UVS table + * describing any variants to be found in + * the normal Unicode subtable. + * nonDefOff 7 ULONG offset to a non-default UVS table + * describing any variants not in the + * standard cmap, with GIDs here + * (either offset may be 0 NULL) + * + * Selectors are sorted by code point. + * + * A default Unicode Variation Selector (UVS) subtable is just a list of + * ranges of code points which are to be found in the standard cmap. No + * glyph IDs (GIDs) here. + * + * numRanges 0 ULONG number of ranges following + * + * A range looks like + * + * uniStart 0 UINT24 code point of the first character in + * this range + * additionalCnt 3 UBYTE count of additional characters in this + * range (zero means a range of a single + * character) + * + * Ranges are sorted by `uniStart'. + * + * A non-default Unicode Variation Selector (UVS) subtable is a list of + * mappings from codepoint to GID. + * + * numMappings 0 ULONG number of mappings + * + * A range looks like + * + * uniStart 0 UINT24 code point of the first character in + * this range + * GID 3 USHORT and its GID + * + * Ranges are sorted by `uniStart'. + */ + +#ifdef TT_CONFIG_CMAP_FORMAT_14 + + typedef struct TT_CMap14Rec_ + { + TT_CMapRec cmap; + FT_ULong num_selectors; + + /* This array is used to store the results of various + * cmap 14 query functions. The data is overwritten + * on each call to these functions. + */ + FT_UInt32 max_results; + FT_UInt32* results; + FT_Memory memory; + + } TT_CMap14Rec, *TT_CMap14; + + + FT_CALLBACK_DEF( void ) + tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */ + { + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Memory memory = ttcmap->memory; + + + ttcmap->max_results = 0; + if ( memory && ttcmap->results ) + FT_FREE( ttcmap->results ); + } + + + static FT_Error + tt_cmap14_ensure( TT_CMap14 cmap, + FT_UInt32 num_results, + FT_Memory memory ) + { + FT_UInt32 old_max = cmap->max_results; + FT_Error error = FT_Err_Ok; + + + if ( num_results > cmap->max_results ) + { + cmap->memory = memory; + + if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) ) + return error; + + cmap->max_results = num_results; + } + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */ + void* table_ ) + { + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; + + table += 6; + ttcmap->num_selectors = FT_PEEK_ULONG( table ); + ttcmap->max_results = 0; + ttcmap->results = NULL; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_selectors; + + + if ( table + 2 + 4 + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_ULONG( p ); + num_selectors = TT_NEXT_ULONG( p ); + + if ( length > (FT_ULong)( valid->limit - table ) || + /* length < 10 + 11 * num_selectors ? */ + length < 10 || + ( length - 10 ) / 11 < num_selectors ) + FT_INVALID_TOO_SHORT; + + /* check selectors, they must be in increasing order */ + { + /* we start lastVarSel at 1 because a variant selector value of 0 + * isn't valid. + */ + FT_ULong n, lastVarSel = 1; + + + for ( n = 0; n < num_selectors; n++ ) + { + FT_ULong varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + + + if ( defOff >= length || nondefOff >= length ) + FT_INVALID_TOO_SHORT; + + if ( varSel < lastVarSel ) + FT_INVALID_DATA; + + lastVarSel = varSel + 1; + + /* check the default table (these glyphs should be reached */ + /* through the normal Unicode cmap, no GIDs, just check order) */ + if ( defOff != 0 ) + { + FT_Byte* defp = table + defOff; + FT_ULong numRanges; + FT_ULong i; + FT_ULong lastBase = 0; + + + if ( defp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + numRanges = TT_NEXT_ULONG( defp ); + + /* defp + numRanges * 4 > valid->limit ? */ + if ( numRanges > (FT_ULong)( valid->limit - defp ) / 4 ) + FT_INVALID_TOO_SHORT; + + for ( i = 0; i < numRanges; i++ ) + { + FT_ULong base = TT_NEXT_UINT24( defp ); + FT_ULong cnt = FT_NEXT_BYTE( defp ); + + + if ( base + cnt >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( base < lastBase ) + FT_INVALID_DATA; + + lastBase = base + cnt + 1U; + } + } + + /* and the non-default table (these glyphs are specified here) */ + if ( nondefOff != 0 ) + { + FT_Byte* ndp = table + nondefOff; + FT_ULong numMappings; + FT_ULong i, lastUni = 0; + + + if ( ndp + 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + + numMappings = TT_NEXT_ULONG( ndp ); + + /* numMappings * 5 > (FT_ULong)( valid->limit - ndp ) ? */ + if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 5 ) + FT_INVALID_TOO_SHORT; + + for ( i = 0; i < numMappings; i++ ) + { + FT_ULong uni = TT_NEXT_UINT24( ndp ); + FT_ULong gid = TT_NEXT_USHORT( ndp ); + + + if ( uni >= 0x110000UL ) /* end of Unicode */ + FT_INVALID_DATA; + + if ( uni < lastUni ) + FT_INVALID_DATA; + + lastUni = uni + 1U; + + if ( valid->level >= FT_VALIDATE_TIGHT && + gid >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_index( FT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UNUSED( cmap ); + FT_UNUSED( char_code ); + + /* This can't happen */ + return 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UNUSED( cmap ); + + /* This can't happen */ + *pchar_code = 0; + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_get_info( FT_CharMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_UNUSED( cmap ); + + cmap_info->format = 14; + /* subtable 14 does not define a language field */ + cmap_info->language = 0xFFFFFFFFUL; + + return FT_Err_Ok; + } + + + static FT_UInt + tt_cmap14_char_map_def_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numRanges = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numRanges; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 4 * mid; + FT_ULong start = TT_NEXT_UINT24( p ); + FT_UInt cnt = FT_NEXT_BYTE( p ); + + + if ( char_code < start ) + max = mid; + else if ( char_code > start + cnt ) + min = mid + 1; + else + return TRUE; + } + + return FALSE; + } + + + static FT_UInt + tt_cmap14_char_map_nondef_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numMappings = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numMappings; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 5 * mid; + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + + + if ( char_code < uni ) + max = mid; + else if ( char_code > uni ) + min = mid + 1; + else + return TT_PEEK_USHORT( p ); + } + + return 0; + } + + + static FT_Byte* + tt_cmap14_find_variant( FT_Byte *base, + FT_UInt32 variantCode ) + { + FT_UInt32 numVar = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + + + min = 0; + max = numVar; + + base += 4; + + /* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 11 * mid; + FT_ULong varSel = TT_NEXT_UINT24( p ); + + + if ( variantCode < varSel ) + max = mid; + else if ( variantCode > varSel ) + min = mid + 1; + else + return p; + } + + return NULL; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */ + FT_CMap ucmap, /* TT_CMap */ + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap ttucmap = (TT_CMap)ucmap; + + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return 0; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_PEEK_ULONG( p ); + + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) + { + /* This is the default variant of this charcode. GID not stored */ + /* here; stored in the normal Unicode charmap instead. */ + return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode ); + } + + if ( nondefOff != 0 ) + return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ); + + return 0; + } + + + FT_CALLBACK_DEF( FT_Int ) + tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */ + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return -1; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) + return 1; + + if ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ) != 0 ) + return 0; + + return -1; + } + + + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */ + FT_Memory memory ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = ttcmap->data + 10; + FT_UInt32* result; + FT_UInt32 i; + + + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + + result = cmap14->results; + for ( i = 0; i < count; i++ ) + { + result[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 8; + } + result[i] = 0; + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */ + FT_Memory memory, + FT_UInt32 charCode ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = ttcmap->data + 10; + FT_UInt32* q; + + + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + + for ( q = cmap14->results; count > 0; count-- ) + { + FT_UInt32 varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + + + if ( ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, + charCode ) ) || + ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charCode ) != 0 ) ) + { + q[0] = varSel; + q++; + } + } + q[0] = 0; + + return cmap14->results; + } + + + static FT_UInt + tt_cmap14_def_char_count( FT_Byte *p ) + { + FT_UInt32 numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + FT_UInt tot = 0; + + + p += 3; /* point to the first `cnt' field */ + for ( ; numRanges > 0; numRanges-- ) + { + tot += 1 + p[0]; + p += 4; + } + + return tot; + } + + + static FT_UInt32* + tt_cmap14_get_def_chars( TT_CMap cmap, + FT_Byte* p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numRanges; + FT_UInt cnt; + FT_UInt32* q; + + + cnt = tt_cmap14_def_char_count( p ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + + if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) ) + return NULL; + + for ( q = cmap14->results; numRanges > 0; numRanges-- ) + { + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + + + cnt = FT_NEXT_BYTE( p ) + 1; + do + { + q[0] = uni; + uni += 1; + q += 1; + + } while ( --cnt != 0 ); + } + q[0] = 0; + + return cmap14->results; + } + + + static FT_UInt32* + tt_cmap14_get_nondef_chars( TT_CMap cmap, + FT_Byte *p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numMappings; + FT_UInt i; + FT_UInt32 *ret; + + + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + + if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) ) + return NULL; + + ret = cmap14->results; + for ( i = 0; i < numMappings; i++ ) + { + ret[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + ret[i] = 0; + + return ret; + } + + + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */ + FT_Memory memory, + FT_UInt32 variantSelector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_Int i; + FT_ULong defOff; + FT_ULong nondefOff; + + + if ( !p ) + return NULL; + + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + + if ( defOff == 0 && nondefOff == 0 ) + return NULL; + + if ( defOff == 0 ) + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, + memory ); + else if ( nondefOff == 0 ) + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, + memory ); + else + { + /* Both a default and a non-default glyph set? That's probably not */ + /* good font design, but the spec allows for it... */ + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 numRanges; + FT_UInt32 numMappings; + FT_UInt32 duni; + FT_UInt32 dcnt; + FT_UInt32 nuni; + FT_Byte* dp; + FT_UInt di, ni, k; + + FT_UInt32 *ret; + + + p = ttcmap->data + nondefOff; + dp = ttcmap->data + defOff; + + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + dcnt = tt_cmap14_def_char_count( dp ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); + + if ( numMappings == 0 ) + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, + memory ); + if ( dcnt == 0 ) + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, + memory ); + + if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) + return NULL; + + ret = cmap14->results; + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + di = 1; + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ni = 1; + i = 0; + + for (;;) + { + if ( nuni > duni + dcnt ) + { + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + + di++; + + if ( di > numRanges ) + break; + + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + } + else + { + if ( nuni < duni ) + ret[i++] = nuni; + /* If it is within the default range then ignore it -- */ + /* that should not have happened */ + ni++; + if ( ni > numMappings ) + break; + + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + } + + if ( ni <= numMappings ) + { + /* If we get here then we have run out of all default ranges. */ + /* We have read one non-default mapping which we haven't stored */ + /* and there may be others that need to be read. */ + ret[i++] = nuni; + while ( ni < numMappings ) + { + ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ni++; + } + } + else if ( di <= numRanges ) + { + /* If we get here then we have run out of all non-default */ + /* mappings. We have read one default range which we haven't */ + /* stored and there may be others that need to be read. */ + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + + while ( di < numRanges ) + { + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + + for ( k = 0; k <= dcnt; k++ ) + ret[i++] = duni + k; + di++; + } + } + + ret[i] = 0; + + return ret; + } + } + + + FT_DEFINE_TT_CMAP( + tt_cmap14_class_rec, + + sizeof ( TT_CMap14Rec ), + + (FT_CMap_InitFunc) tt_cmap14_init, /* init */ + (FT_CMap_DoneFunc) tt_cmap14_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap14_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap14_char_next, /* char_next */ + + /* Format 14 extension functions */ + (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index, + (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault, + (FT_CMap_VariantListFunc) tt_cmap14_variants, + (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants, + (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars, + + 14, + (TT_CMap_ValidateFunc)tt_cmap14_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap14_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_14 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SYNTHETIC UNICODE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* This charmap is generated using postscript glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + FT_CALLBACK_DEF( const char * ) + tt_get_glyph_name( void* face_, /* TT_Face */ + FT_UInt idx ) + { + TT_Face face = (TT_Face)face_; + FT_String* PSname = NULL; + + + tt_face_get_ps_name( face, idx, &PSname ); + + return PSname; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + FT_UNUSED( pointer ); + + + if ( !psnames->unicodes_init ) + return FT_THROW( Unimplemented_Feature ); + + return psnames->unicodes_init( memory, + unicodes, + face->root.num_glyphs, + &tt_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + + + FT_CALLBACK_DEF( void ) + tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_index( unicodes, char_code ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) + { + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + + + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + + + FT_DEFINE_TT_CMAP( + tt_cmap_unicode_class_rec, + + sizeof ( PS_UnicodesRec ), + + (FT_CMap_InitFunc) tt_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) tt_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap_unicode_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL, /* variantchar_list */ + + ~0U, + (TT_CMap_ValidateFunc)NULL, /* validate */ + (TT_CMap_Info_GetFunc)NULL /* get_cmap_info */ + ) + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static const TT_CMap_Class tt_cmap_classes[] = + { +#undef TTCMAPCITEM +#define TTCMAPCITEM( a ) &a, +#include "ttcmapc.h" + NULL, + }; + + + /* parse the `cmap' table and build the corresponding TT_CMap objects */ + /* in the current face */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Byte* const table = face->cmap_table; + FT_Byte* limit; + FT_UInt volatile num_cmaps; + FT_Byte* volatile p = table; + FT_Library library = FT_FACE_LIBRARY( face ); + + FT_UNUSED( library ); + + + if ( !p || face->cmap_size < 4 ) + return FT_THROW( Invalid_Table ); + + /* Version 1.8.3 of the OpenType specification contains the following */ + /* (https://docs.microsoft.com/en-us/typography/opentype/spec/cmap): */ + /* */ + /* The 'cmap' table version number remains at 0x0000 for fonts that */ + /* make use of the newer subtable formats. */ + /* */ + /* This essentially means that a version format test is useless. */ + + /* ignore format */ + p += 2; + + num_cmaps = TT_NEXT_USHORT( p ); + FT_TRACE4(( "tt_face_build_cmaps: %d cmaps\n", num_cmaps )); + + limit = table + face->cmap_size; + for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) + { + FT_CharMapRec charmap; + FT_UInt32 offset; + + + charmap.platform_id = TT_NEXT_USHORT( p ); + charmap.encoding_id = TT_NEXT_USHORT( p ); + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ + offset = TT_NEXT_ULONG( p ); + + if ( offset && offset <= face->cmap_size - 2 ) + { + FT_Byte* volatile cmap = table + offset; + volatile FT_UInt format = TT_PEEK_USHORT( cmap ); + const TT_CMap_Class* volatile pclazz = tt_cmap_classes; + TT_CMap_Class volatile clazz; + + + for ( ; *pclazz; pclazz++ ) + { + clazz = *pclazz; + if ( clazz->format == format ) + { + volatile TT_ValidatorRec valid; + volatile FT_Error error = FT_Err_Ok; + + + ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, + FT_VALIDATE_DEFAULT ); + + valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; + + if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 ) + { + /* validate this cmap sub-table */ + error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); + } + + if ( !valid.validator.error ) + { + FT_CMap ttcmap; + + + /* It might make sense to store the single variation */ + /* selector cmap somewhere special. But it would have to be */ + /* in the public FT_FaceRec, and we can't change that. */ + + if ( !FT_CMap_New( (FT_CMap_Class)clazz, + cmap, &charmap, &ttcmap ) ) + { + /* it is simpler to directly set `flags' than adding */ + /* a parameter to FT_CMap_New */ + ((TT_CMap)ttcmap)->flags = (FT_Int)error; + } + } + else + { + FT_TRACE0(( "tt_face_build_cmaps:" + " broken cmap sub-table ignored\n" )); + } + break; + } + } + + if ( !*pclazz ) + { + FT_TRACE0(( "tt_face_build_cmaps:" + " unsupported cmap sub-table ignored\n" )); + } + } + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + + + if ( clazz->get_cmap_info ) + return clazz->get_cmap_info( charmap, cmap_info ); + else + return FT_THROW( Invalid_CharMap_Format ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcmap.h b/Dependencies/freetype/freetype/src/sfnt/ttcmap.h new file mode 100644 index 00000000..e2c5e72b --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcmap.h @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * ttcmap.h + * + * TrueType character mapping table (cmap) support (specification). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTCMAP_H_ +#define TTCMAP_H_ + + +#include +#include +#include + +FT_BEGIN_HEADER + + +#define TT_CMAP_FLAG_UNSORTED 1 +#define TT_CMAP_FLAG_OVERLAPPING 2 + + typedef struct TT_CMapRec_ + { + FT_CMapRec cmap; + FT_Byte* data; /* pointer to in-memory cmap table */ + FT_Int flags; /* for format 4 only */ + + } TT_CMapRec, *TT_CMap; + + typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; + + + typedef FT_Error + (*TT_CMap_ValidateFunc)( FT_Byte* data, + FT_Validator valid ); + + typedef struct TT_CMap_ClassRec_ + { + FT_CMap_ClassRec clazz; + FT_UInt format; + TT_CMap_ValidateFunc validate; + TT_CMap_Info_GetFunc get_cmap_info; + + } TT_CMap_ClassRec; + + +#define FT_DEFINE_TT_CMAP( class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_, \ + format_, \ + validate_, \ + get_cmap_info_ ) \ + FT_CALLBACK_TABLE_DEF \ + const TT_CMap_ClassRec class_ = \ + { \ + { size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }, \ + \ + format_, \ + validate_, \ + get_cmap_info_ \ + }; + + +#undef TTCMAPCITEM +#define TTCMAPCITEM( a ) FT_CALLBACK_TABLE const TT_CMap_ClassRec a; +#include "ttcmapc.h" + + + typedef struct TT_ValidatorRec_ + { + FT_ValidatorRec validator; + FT_UInt num_glyphs; + + } TT_ValidatorRec, *TT_Validator; + + +#define TT_VALIDATOR( x ) ( (TT_Validator)( x ) ) +#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs + + + FT_CALLBACK_TABLE const TT_CMap_ClassRec tt_cmap_unicode_class_rec; + + FT_LOCAL( FT_Error ) + tt_face_build_cmaps( TT_Face face ); + + /* used in tt-cmaps service */ + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + +FT_END_HEADER + +#endif /* TTCMAP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcmapc.h b/Dependencies/freetype/freetype/src/sfnt/ttcmapc.h new file mode 100644 index 00000000..37089836 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcmapc.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * ttcmapc.h + * + * TT CMAP classes definitions (specification only). + * + * Copyright (C) 2009-2024 by + * Oran Agra and Mickey Gabel. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + TTCMAPCITEM( tt_cmap0_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + TTCMAPCITEM( tt_cmap2_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + TTCMAPCITEM( tt_cmap4_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + TTCMAPCITEM( tt_cmap6_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + TTCMAPCITEM( tt_cmap8_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + TTCMAPCITEM( tt_cmap10_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + TTCMAPCITEM( tt_cmap12_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_13 + TTCMAPCITEM( tt_cmap13_class_rec ) +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_14 + TTCMAPCITEM( tt_cmap14_class_rec ) +#endif + + + /* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcolr.c b/Dependencies/freetype/freetype/src/sfnt/ttcolr.c new file mode 100644 index 00000000..b37658dd --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcolr.c @@ -0,0 +1,1923 @@ +/**************************************************************************** + * + * ttcolr.c + * + * TrueType and OpenType colored glyph layer support (body). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * `COLR' table specification: + * + * https://www.microsoft.com/typography/otspec/colr.htm + * + */ + + +#include +#include +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + +#include "ttcolr.h" + + + /* NOTE: These are the table sizes calculated through the specs. */ +#define BASE_GLYPH_SIZE 6U +#define BASE_GLYPH_PAINT_RECORD_SIZE 6U +#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U +#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U +#define COLOR_STOP_SIZE 6U +#define VAR_IDX_BASE_SIZE 4U +#define LAYER_SIZE 4U +/* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#colr-header */ +/* 3 * uint16 + 2 * Offset32 */ +#define COLRV0_HEADER_SIZE 14U +/* COLRV0_HEADER_SIZE + 5 * Offset32 */ +#define COLRV1_HEADER_SIZE 34U + + +#define ENSURE_READ_BYTES( byte_size ) \ + if ( p < colr->paints_start_v1 || \ + p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \ + return 0 + + + typedef enum FT_PaintFormat_Internal_ + { + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM = 13, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE = 15, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE = 17, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER = 19, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM = 21, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER = 23, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE = 25, + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER = 27, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29, + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31, + + } FT_PaintFormat_Internal; + + + typedef struct BaseGlyphRecord_ + { + FT_UShort gid; + FT_UShort first_layer_index; + FT_UShort num_layers; + + } BaseGlyphRecord; + + + typedef struct BaseGlyphV1Record_ + { + FT_UShort gid; + /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */ + FT_ULong paint_offset; + + } BaseGlyphV1Record; + + + typedef struct Colr_ + { + FT_UShort version; + FT_UShort num_base_glyphs; + FT_UShort num_layers; + + FT_Byte* base_glyphs; + FT_Byte* layers; + + FT_ULong num_base_glyphs_v1; + /* Points at beginning of BaseGlyphV1List. */ + FT_Byte* base_glyphs_v1; + + FT_ULong num_layers_v1; + FT_Byte* layers_v1; + + FT_Byte* clip_list; + + /* + * Paint tables start at the minimum of the end of the LayerList and the + * end of the BaseGlyphList. Record this location in a field here for + * safety checks when accessing paint tables. + */ + FT_Byte* paints_start_v1; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Item Variation Store for variable 'COLR' v1. */ + GX_ItemVarStoreRec var_store; + GX_DeltaSetIdxMapRec delta_set_idx_map; +#endif + + /* The memory that backs up the `COLR' table. */ + void* table; + FT_ULong table_size; + + } Colr; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcolr + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_colr( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Byte* table = NULL; + FT_Byte* p = NULL; + /* Needed for reading array lengths in referenced tables. */ + FT_Byte* p1 = NULL; + + Colr* colr = NULL; + + FT_ULong base_glyph_offset, layer_offset; + FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1; + FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset; + FT_ULong table_size; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong colr_offset_in_stream; +#endif + + + /* `COLR' always needs `CPAL' */ + if ( !face->cpal ) + return FT_THROW( Invalid_File_Format ); + + error = face->goto_table( face, TTAG_COLR, stream, &table_size ); + if ( error ) + goto NoColr; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr_offset_in_stream = FT_STREAM_POS(); +#endif + + if ( table_size < COLRV0_HEADER_SIZE ) + goto NoColr; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoColr; + + p = table; + + if ( FT_NEW( colr ) ) + goto NoColr; + + colr->version = FT_NEXT_USHORT( p ); + if ( colr->version != 0 && colr->version != 1 ) + goto InvalidTable; + + colr->num_base_glyphs = FT_NEXT_USHORT( p ); + base_glyph_offset = FT_NEXT_ULONG( p ); + + if ( table_size <= base_glyph_offset ) + goto InvalidTable; + if ( ( table_size - base_glyph_offset ) / BASE_GLYPH_SIZE + < colr->num_base_glyphs ) + goto InvalidTable; + + layer_offset = FT_NEXT_ULONG( p ); + colr->num_layers = FT_NEXT_USHORT( p ); + + if ( table_size <= layer_offset ) + goto InvalidTable; + if ( ( table_size - layer_offset ) / LAYER_SIZE + < colr->num_layers ) + goto InvalidTable; + + if ( colr->version == 1 ) + { + if ( table_size < COLRV1_HEADER_SIZE ) + goto InvalidTable; + + base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); + + if ( table_size - 4 <= base_glyphs_offset_v1 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); + num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); + + if ( ( table_size - base_glyphs_offset_v1 ) / BASE_GLYPH_PAINT_RECORD_SIZE + < num_base_glyphs_v1 ) + goto InvalidTable; + + colr->num_base_glyphs_v1 = num_base_glyphs_v1; + colr->base_glyphs_v1 = p1; + + layer_offset_v1 = FT_NEXT_ULONG( p ); + + if ( table_size <= layer_offset_v1 ) + goto InvalidTable; + + if ( layer_offset_v1 ) + { + if ( table_size - 4 <= layer_offset_v1 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + layer_offset_v1 ); + num_layers_v1 = FT_PEEK_ULONG( p1 ); + + if ( ( table_size - layer_offset_v1 ) / LAYER_V1_LIST_PAINT_OFFSET_SIZE + < num_layers_v1 ) + goto InvalidTable; + + colr->num_layers_v1 = num_layers_v1; + colr->layers_v1 = p1; + + colr->paints_start_v1 = + FT_MIN( colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE, + colr->layers_v1 + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ); + } + else + { + colr->num_layers_v1 = 0; + colr->layers_v1 = 0; + colr->paints_start_v1 = + colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE; + } + + clip_list_offset = FT_NEXT_ULONG( p ); + + if ( table_size <= clip_list_offset ) + goto InvalidTable; + + if ( clip_list_offset ) + colr->clip_list = (FT_Byte*)( table + clip_list_offset ); + else + colr->clip_list = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr->var_store.dataCount = 0; + colr->var_store.varData = NULL; + colr->var_store.axisCount = 0; + colr->var_store.regionCount = 0; + colr->var_store.varRegionList = 0; + + colr->delta_set_idx_map.mapCount = 0; + colr->delta_set_idx_map.outerIndex = NULL; + colr->delta_set_idx_map.innerIndex = NULL; + + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) + { + FT_ULong var_idx_map_offset, var_store_offset; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + var_idx_map_offset = FT_NEXT_ULONG( p ); + + if ( var_idx_map_offset >= table_size ) + goto InvalidTable; + + var_store_offset = FT_NEXT_ULONG( p ); + if ( table_size <= var_store_offset ) + goto InvalidTable; + + if ( var_store_offset ) + { + /* If variation info has not been initialized yet, try doing so, */ + /* otherwise loading the variation store will fail as it */ + /* requires access to `blend` for checking the number of axes. */ + if ( !face->blend ) + if ( mm->get_mm_var( FT_FACE( face ), NULL ) ) + goto InvalidTable; + + /* Try loading `VarIdxMap` and `VarStore`. */ + error = mm->load_item_var_store( + FT_FACE( face ), + colr_offset_in_stream + var_store_offset, + &colr->var_store ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + + if ( colr->var_store.axisCount && var_idx_map_offset ) + { + error = mm->load_delta_set_idx_map( + FT_FACE( face ), + colr_offset_in_stream + var_idx_map_offset, + &colr->delta_set_idx_map, + &colr->var_store, + table_size ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + } + + colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); + colr->layers = (FT_Byte*)( table + layer_offset ); + colr->table = table; + colr->table_size = table_size; + + face->colr = colr; + + return FT_Err_Ok; + + InvalidTable: +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + + error = FT_THROW( Invalid_Table ); + + NoColr: + FT_FRAME_RELEASE( table ); + FT_FREE( colr ); + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_colr( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + + Colr* colr = (Colr*)face->colr; + + + if ( colr ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + FT_FRAME_RELEASE( colr->table ); + FT_FREE( colr ); + } + } + + + static FT_Bool + find_base_glyph_record( FT_Byte* base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphRecord* record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE; + + FT_UShort gid = FT_NEXT_USHORT( p ); + + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->first_layer_index = FT_NEXT_USHORT( p ); + record->num_layers = FT_NEXT_USHORT( p ); + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_layer( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphRecord glyph_record; + + + if ( !colr ) + return 0; + + if ( !iterator->p ) + { + FT_ULong offset; + + + /* first call to function */ + iterator->layer = 0; + + if ( !find_base_glyph_record( colr->base_glyphs, + colr->num_base_glyphs, + base_glyph, + &glyph_record ) ) + return 0; + + if ( glyph_record.num_layers ) + iterator->num_layers = glyph_record.num_layers; + else + return 0; + + offset = LAYER_SIZE * glyph_record.first_layer_index; + if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size ) + return 0; + + iterator->p = colr->layers + offset; + } + + if ( iterator->layer >= iterator->num_layers || + iterator->p < colr->layers || + iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *aglyph_index = FT_NEXT_USHORT( iterator->p ); + *acolor_index = FT_NEXT_USHORT( iterator->p ); + + if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) || + ( *acolor_index != 0xFFFF && + *acolor_index >= face->palette_data.num_palette_entries ) ) + return 0; + + iterator->layer++; + + return 1; + } + + + static FT_Bool + read_color_line( Colr* colr, + FT_Byte* color_line_p, + FT_ColorLine* colorline, + FT_Bool read_variable ) + { + FT_Byte* p = color_line_p; + FT_PaintExtend paint_extend; + + + ENSURE_READ_BYTES( 3 ); + + paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p ); + if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT ) + return 0; + + colorline->extend = paint_extend; + + colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p ); + colorline->color_stop_iterator.p = p; + colorline->color_stop_iterator.current_color_stop = 0; + colorline->color_stop_iterator.read_variable = read_variable; + + return 1; + } + + + /* + * Read a paint offset for `FT_Paint*` objects that have them and check + * whether it is within reasonable limits within the font and the COLR + * table. + * + * Return 1 on success, 0 on failure. + */ + static FT_Bool + get_child_table_pointer ( Colr* colr, + FT_Byte* paint_base, + FT_Byte** p, + FT_Byte** child_table_pointer ) + { + FT_UInt32 paint_offset; + FT_Byte* child_table_p; + + + if ( !child_table_pointer ) + return 0; + + if ( *p < colr->paints_start_v1 || + *p > (FT_Byte*)colr->table + colr->table_size - 1 - 3 ) + return 0; + + paint_offset = FT_NEXT_UOFF3( *p ); + if ( !paint_offset ) + return 0; + + child_table_p = (FT_Byte*)( paint_base + paint_offset ); + + if ( child_table_p < colr->paints_start_v1 || + child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *child_table_pointer = child_table_p; + return 1; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + static FT_Bool + get_deltas_for_var_index_base ( TT_Face face, + Colr* colr, + FT_ULong var_index_base, + FT_UInt num_deltas, + FT_ItemVarDelta* deltas ) + { + FT_UInt outer_index = 0; + FT_UInt inner_index = 0; + FT_ULong loop_var_index = var_index_base; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt i = 0; + + + if ( var_index_base == 0xFFFFFFFF ) + { + for ( i = 0; i < num_deltas; ++i ) + deltas[i] = 0; + return 1; + } + + for ( i = 0; i < num_deltas; ++i ) + { + loop_var_index = var_index_base + i; + + if ( colr->delta_set_idx_map.innerIndex ) + { + if ( loop_var_index >= colr->delta_set_idx_map.mapCount ) + loop_var_index = colr->delta_set_idx_map.mapCount - 1; + + outer_index = colr->delta_set_idx_map.outerIndex[loop_var_index]; + inner_index = colr->delta_set_idx_map.innerIndex[loop_var_index]; + } + else + { + outer_index = 0; + inner_index = loop_var_index; + } + + deltas[i] = mm->get_item_delta( FT_FACE( face ), &colr->var_store, + outer_index, inner_index ); + } + + return 1; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static FT_Bool + read_paint( TT_Face face, + Colr* colr, + FT_Byte* p, + FT_COLR_Paint* apaint ) + { + FT_Byte* paint_base = p; + FT_Byte* child_table_p = NULL; + FT_Bool do_read_var = FALSE; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong var_index_base = 0; + /* Longest varIndexBase offset is 5 in the spec. */ + FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 }; +#else + FT_UNUSED( face ); +#endif + + + if ( !p || !colr || !colr->table ) + return 0; + + /* The last byte of the 'COLR' table is at 'size-1'; subtract 1 of */ + /* that to account for the expected format byte we are going to read. */ + if ( p < colr->paints_start_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 2 ) + return 0; + + apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); + + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) + { + /* Initialize layer iterator/ */ + FT_Byte num_layers; + FT_UInt32 first_layer_index; + + + ENSURE_READ_BYTES( 5 ); + num_layers = FT_NEXT_BYTE( p ); + if ( num_layers > colr->num_layers_v1 ) + return 0; + + first_layer_index = FT_NEXT_ULONG( p ); + if ( first_layer_index + num_layers > colr->num_layers_v1 ) + return 0; + + apaint->u.colr_layers.layer_iterator.num_layers = num_layers; + apaint->u.colr_layers.layer_iterator.layer = 0; + /* TODO: Check whether pointer is outside colr? */ + apaint->u.colr_layers.layer_iterator.p = + colr->layers_v1 + + LAYER_V1_LIST_NUM_LAYERS_SIZE + + LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); + apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SOLID; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) + { + ENSURE_READ_BYTES(2); + apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + /* + * Grouped below here are all paint formats that have an offset to a + * child paint table as the first entry (for example, a color line or a + * child paint table). Retrieve that and determine whether that paint + * offset is valid first. + */ + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.linear_gradient.colorline, + do_read_var ) ) + return 0; + + /* + * In order to support variations expose these as FT_Fixed 16.16 + * values so that we can support fractional values after + * interpolation. + */ + ENSURE_READ_BYTES( 12 ); + apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.linear_gradient.p0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.linear_gradient.p0.y += INT_TO_FIXED( item_deltas[1] ); + apaint->u.linear_gradient.p1.x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.linear_gradient.p1.y += INT_TO_FIXED( item_deltas[3] ); + apaint->u.linear_gradient.p2.x += INT_TO_FIXED( item_deltas[4] ); + apaint->u.linear_gradient.p2.y += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) ) + { + FT_Pos tmp; + + + if ( !read_color_line( colr, + child_table_p, + &apaint->u.radial_gradient.colorline, + do_read_var ) ) + return 0; + + + /* In the OpenType specification, `r0` and `r1` are defined as */ + /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ + /* format we convert to `FWORD` and replace negative values with */ + /* (32bit) `FT_INT_MAX`. */ + + ENSURE_READ_BYTES( 12 ); + + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp; + + apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.radial_gradient.c0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.radial_gradient.c0.y += INT_TO_FIXED( item_deltas[1] ); + + // TODO: Anything to be done about UFWORD deltas here? + apaint->u.radial_gradient.r0 += INT_TO_FIXED( item_deltas[2] ); + + apaint->u.radial_gradient.c1.x += INT_TO_FIXED( item_deltas[3] ); + apaint->u.radial_gradient.c1.y += INT_TO_FIXED( item_deltas[4] ); + + apaint->u.radial_gradient.r1 += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.sweep_gradient.colorline, + do_read_var) ) + return 0; + + ENSURE_READ_BYTES( 8 ); + + apaint->u.sweep_gradient.center.x = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.center.y = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + apaint->u.sweep_gradient.start_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.end_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + // TODO: Handle overflow? + apaint->u.sweep_gradient.center.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.sweep_gradient.center.y += INT_TO_FIXED( item_deltas[1] ); + + apaint->u.sweep_gradient.start_angle += + F2DOT14_TO_FIXED( item_deltas[2] ); + apaint->u.sweep_gradient.end_angle += + F2DOT14_TO_FIXED( item_deltas[3] ); + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT; + + return 1; + } + + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.glyph.paint.p = child_table_p; + apaint->u.glyph.paint.insert_root_transform = 0; + apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + apaint->u.transform.paint.p = child_table_p; + apaint->u.transform.paint.insert_root_transform = 0; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + p = child_table_p; + + /* + * The following matrix coefficients are encoded as + * OpenType 16.16 fixed-point values. + */ + ENSURE_READ_BYTES( 24 ); + apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dy = FT_NEXT_LONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.transform.affine.xx += (FT_Fixed)item_deltas[0]; + apaint->u.transform.affine.yx += (FT_Fixed)item_deltas[1]; + apaint->u.transform.affine.xy += (FT_Fixed)item_deltas[2]; + apaint->u.transform.affine.yy += (FT_Fixed)item_deltas[3]; + apaint->u.transform.affine.dx += (FT_Fixed)item_deltas[4]; + apaint->u.transform.affine.dy += (FT_Fixed)item_deltas[5]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + apaint->u.translate.paint.p = child_table_p; + apaint->u.translate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.translate.dx += INT_TO_FIXED( item_deltas[0] ); + apaint->u.translate.dy += INT_TO_FIXED( item_deltas[1] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSLATE; + + return 1; + } + + else if ( apaint->format >= FT_COLR_PAINTFORMAT_SCALE && + (FT_PaintFormat_Internal)apaint->format <= + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.paint.p = child_table_p; + apaint->u.scale.paint.insert_root_transform = 0; + + /* All scale paints get at least one scale value. */ + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + /* Non-uniform ones read an extra y value. */ + if ( apaint->format == FT_COLR_PAINTFORMAT_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + apaint->u.scale.scale_y = apaint->u.scale.scale_x; + + /* Scale paints that have a center read center coordinates, */ + /* otherwise the center is (0,0). */ + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + } + else + { + apaint->u.scale.center_x = 0; + apaint->u.scale.center_y = 0; + } + + /* Base values set, now handle variations. */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[3] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 3, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } +#endif + + /* FT 'COLR' v1 API output format always returns fully defined */ + /* structs; we thus set the format to the public API value. */ + apaint->format = FT_COLR_PAINTFORMAT_SCALE; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + apaint->u.rotate.paint.p = child_table_p; + apaint->u.rotate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 2 ); + apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.rotate.center_x = 0; + apaint->u.rotate.center_y = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + FT_UInt num_deltas = 0; + + + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + num_deltas = 3; + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ) + num_deltas = 1; + + if ( num_deltas > 0 ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, + num_deltas, item_deltas ) ) + return 0; + + apaint->u.rotate.angle += F2DOT14_TO_FIXED( item_deltas[0] ); + + if ( num_deltas == 3 ) + { + apaint->u.rotate.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.rotate.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_ROTATE; + + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + apaint->u.skew.paint.p = child_table_p; + apaint->u.skew.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.skew.center_x = 0; + apaint->u.skew.center_y = 0; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.skew.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.skew.center_y += INT_TO_FIXED( item_deltas[3] ); + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SKEW; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE ) + { + FT_UInt composite_mode; + + + apaint->u.composite.source_paint.p = child_table_p; + apaint->u.composite.source_paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 1 ); + composite_mode = FT_NEXT_BYTE( p ); + if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) + return 0; + + apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + apaint->u.composite.backdrop_paint.p = + child_table_p; + apaint->u.composite.backdrop_paint.insert_root_transform = + 0; + + return 1; + } + + return 0; + } + + + static FT_Bool + find_base_glyph_v1_record( FT_Byte * base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphV1Record *record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UShort gid; + + /* + * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; + * skip `numBaseGlyphV1Records` by adding 4 to start binary search + * in the array of `BaseGlyphV1Record`. + */ + FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; + + gid = FT_NEXT_USHORT( p ); + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->paint_offset = FT_NEXT_ULONG ( p ); + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* opaque_paint ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphV1Record base_glyph_v1_record; + FT_Byte* p; + + if ( !colr || !colr->table ) + return 0; + + if ( colr->version < 1 || !colr->num_base_glyphs_v1 || + !colr->base_glyphs_v1 ) + return 0; + + if ( opaque_paint->p ) + return 0; + + if ( !find_base_glyph_v1_record( colr->base_glyphs_v1, + colr->num_base_glyphs_v1, + base_glyph, + &base_glyph_v1_record ) ) + return 0; + + if ( !base_glyph_v1_record.paint_offset || + base_glyph_v1_record.paint_offset > colr->table_size ) + return 0; + + p = (FT_Byte*)( colr->base_glyphs_v1 + + base_glyph_v1_record.paint_offset ); + if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p; + + if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM ) + opaque_paint->insert_root_transform = 1; + else + opaque_paint->insert_root_transform = 0; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + Colr* colr; + + FT_Byte *p, *p1, *clip_base, *limit; + + FT_Byte clip_list_format; + FT_ULong num_clip_boxes, i; + FT_UShort gid_start, gid_end; + FT_UInt32 clip_box_offset; + FT_Byte format; + + const FT_Byte num_corners = 4; + FT_Vector corners[4]; + FT_Byte j; + FT_BBox font_clip_box; + + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + if ( !colr->clip_list ) + return 0; + + p = colr->clip_list; + + /* Limit points to the first byte after the end of the color table. */ + /* Thus, in subsequent limit checks below we need to check whether the */ + /* read pointer is strictly greater than a position offset by certain */ + /* field sizes to the left of that position. */ + limit = (FT_Byte*)colr->table + colr->table_size; + + /* Check whether we can extract one `uint8` and one `uint32`. */ + if ( p > limit - ( 1 + 4 ) ) + return 0; + + clip_base = p; + clip_list_format = FT_NEXT_BYTE ( p ); + + /* Format byte used here to be able to upgrade ClipList for >16bit */ + /* glyph ids; for now we can expect it to be 1. */ + if ( !( clip_list_format == 1 ) ) + return 0; + + num_clip_boxes = FT_NEXT_ULONG( p ); + + /* Check whether we can extract two `uint16` and one `Offset24`, */ + /* `num_clip_boxes` times. */ + if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes || + p > limit - ( 2 + 2 + 3 ) * num_clip_boxes ) + return 0; + + for ( i = 0; i < num_clip_boxes; ++i ) + { + gid_start = FT_NEXT_USHORT( p ); + gid_end = FT_NEXT_USHORT( p ); + clip_box_offset = FT_NEXT_UOFF3( p ); + + if ( base_glyph >= gid_start && base_glyph <= gid_end ) + { + p1 = (FT_Byte*)( clip_base + clip_box_offset ); + + /* Check whether we can extract one `uint8`. */ + if ( p1 > limit - 1 ) + return 0; + + format = FT_NEXT_BYTE( p1 ); + + if ( format > 2 ) + return 0; + + /* Check whether we can extract four `FWORD`. */ + if ( p1 > limit - ( 2 + 2 + 2 + 2 ) ) + return 0; + + /* `face->root.size->metrics.x_scale` and `y_scale` are factors */ + /* that scale a font unit value in integers to a 26.6 fixed value */ + /* according to the requested size, see for example */ + /* `ft_recompute_scaled_metrics`. */ + font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( format == 2 ) + { + FT_ULong var_index_base = 0; + /* varIndexBase offset for clipbox is 3 at most. */ + FT_ItemVarDelta item_deltas[4] = { 0, 0, 0, 0 }; + + + /* Check whether we can extract a 32-bit varIndexBase now. */ + if ( p1 > limit - 4 ) + return 0; + + var_index_base = FT_NEXT_ULONG( p1 ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + font_clip_box.xMin += + FT_MulFix( item_deltas[0], face->root.size->metrics.x_scale ); + font_clip_box.yMin += + FT_MulFix( item_deltas[1], face->root.size->metrics.y_scale ); + font_clip_box.xMax += + FT_MulFix( item_deltas[2], face->root.size->metrics.x_scale ); + font_clip_box.yMax += + FT_MulFix( item_deltas[3], face->root.size->metrics.y_scale ); + } +#endif + + /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */ + /* them. If we we would only transform two corner points and */ + /* span a rectangle based on those, the rectangle may become too */ + /* small to cover the glyph. */ + corners[0].x = font_clip_box.xMin; + corners[1].x = font_clip_box.xMin; + corners[2].x = font_clip_box.xMax; + corners[3].x = font_clip_box.xMax; + + corners[0].y = font_clip_box.yMin; + corners[1].y = font_clip_box.yMax; + corners[2].y = font_clip_box.yMax; + corners[3].y = font_clip_box.yMin; + + for ( j = 0; j < num_corners; ++j ) + { + if ( face->root.internal->transform_flags & 1 ) + FT_Vector_Transform( &corners[j], + &face->root.internal->transform_matrix ); + + if ( face->root.internal->transform_flags & 2 ) + { + corners[j].x += face->root.internal->transform_delta.x; + corners[j].y += face->root.internal->transform_delta.y; + } + } + + clip_box->bottom_left = corners[0]; + clip_box->top_left = corners[1]; + clip_box->top_right = corners[2]; + clip_box->bottom_right = corners[3]; + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* opaque_paint ) + { + FT_Byte* p = NULL; + FT_Byte* p_first_layer = NULL; + FT_Byte* p_paint = NULL; + FT_UInt32 paint_offset; + + Colr* colr; + + + if ( iterator->layer == iterator->num_layers ) + return 0; + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + /* + * We have an iterator pointing at a paint offset as part of the + * `paintOffset` array in `LayerV1List`. + */ + p = iterator->p; + + /* + * Do a cursor sanity check of the iterator. Counting backwards from + * where it stands, we need to end up at a position after the beginning + * of the `LayerV1List` table and not after the end of the + * `LayerV1List`. + */ + p_first_layer = p - + iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE - + LAYER_V1_LIST_NUM_LAYERS_SIZE; + if ( p_first_layer < (FT_Byte*)colr->layers_v1 ) + return 0; + if ( p_first_layer >= (FT_Byte*)( + colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) ) + return 0; + + /* + * Before reading, ensure that `p` is within 'COLR' v1 and we can read a + * 4-byte ULONG. + */ + if ( p < colr->layers_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 4 ) + return 0; + + paint_offset = + FT_NEXT_ULONG( p ); + opaque_paint->insert_root_transform = + 0; + + p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset ); + + if ( p_paint < colr->paints_start_v1 || + p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p_paint; + + iterator->p = p; + + iterator->layer++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator *iterator ) + { + Colr* colr = (Colr*)face->colr; + + FT_Byte* p; + FT_ULong var_index_base; + FT_Byte* last_entry_p = NULL; + FT_UInt entry_size = COLOR_STOP_SIZE; + + + if ( !colr || !colr->table || !iterator ) + return 0; + + if ( iterator->current_color_stop >= iterator->num_color_stops ) + return 0; + + if ( iterator->read_variable ) + entry_size += VAR_IDX_BASE_SIZE; + + /* Calculate the start pointer for the last to-be-read (Var)ColorStop */ + /* and check whether we can read a full (Var)ColorStop at that */ + /* position by comparing it to the position that is the size of one */ + /* (Var)ColorStop before the end of the 'COLR' table. */ + last_entry_p = + iterator->p + ( iterator->num_color_stops - 1 - + iterator->current_color_stop ) * entry_size; + if ( iterator->p < colr->paints_start_v1 || + last_entry_p > (FT_Byte*)colr->table + + colr->table_size - entry_size ) + return 0; + + /* Iterator points at first `ColorStop` of `ColorLine`. */ + p = iterator->p; + + color_stop->stop_offset = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + color_stop->color.palette_index = FT_NEXT_USHORT( p ); + + color_stop->color.alpha = FT_NEXT_SHORT( p ); + + if ( iterator->read_variable ) + { + /* Pointer p needs to be advanced independently of whether we intend */ + /* to take variable deltas into account or not. Otherwise iteration */ + /* would fail due to wrong offsets. */ + var_index_base = FT_NEXT_ULONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Int item_deltas[2]; + + + if ( !get_deltas_for_var_index_base( face, colr, + var_index_base, + 2, + item_deltas ) ) + return 0; + + color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] ); + color_stop->color.alpha += (FT_F2Dot14)item_deltas[1]; + } +#else + FT_UNUSED( var_index_base ); +#endif + } + + iterator->p = p; + iterator->current_color_stop++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + Colr* colr = (Colr*)face->colr; + FT_OpaquePaint next_paint; + FT_Matrix ft_root_scale; + + if ( !colr || !colr->base_glyphs_v1 || !colr->table ) + return 0; + + if ( opaque_paint.insert_root_transform ) + { + /* 'COLR' v1 glyph information is returned in unscaled coordinates, + * i.e., `FT_Size` is not applied or multiplied into the values. When + * client applications draw color glyphs, they can request to include + * a top-level transform, which includes the active `x_scale` and + * `y_scale` information for scaling the glyph, as well the additional + * transform and translate configured through `FT_Set_Transform`. + * This allows client applications to apply this top-level transform + * to the graphics context first and only once, then have gradient and + * contour scaling applied correctly when performing the additional + * drawing operations for subsequenct paints. Prepare this initial + * transform here. + */ + paint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + next_paint.p = opaque_paint.p; + next_paint.insert_root_transform = 0; + paint->u.transform.paint = next_paint; + + /* `x_scale` and `y_scale` are in 26.6 format, representing the scale + * factor to get from font units to requested size. However, expected + * return values are in 16.16, so we shift accordingly with rounding. + */ + ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6; + ft_root_scale.xy = 0; + ft_root_scale.yx = 0; + ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6; + + if ( face->root.internal->transform_flags & 1 ) + FT_Matrix_Multiply( &face->root.internal->transform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.xx = ft_root_scale.xx; + paint->u.transform.affine.xy = ft_root_scale.xy; + paint->u.transform.affine.yx = ft_root_scale.yx; + paint->u.transform.affine.yy = ft_root_scale.yy; + + /* The translation is specified in 26.6 format and, according to the + * documentation of `FT_Set_Translate`, is performed on the character + * size given in the last call to `FT_Set_Char_Size`. The + * 'PaintTransform' paint table's `FT_Affine23` format expects + * values in 16.16 format, thus we need to shift by 10 bits. + */ + if ( face->root.internal->transform_flags & 2 ) + { + paint->u.transform.affine.dx = + face->root.internal->transform_delta.x * ( 1 << 10 ); + paint->u.transform.affine.dy = + face->root.internal->transform_delta.y * ( 1 << 10 ); + } + else + { + paint->u.transform.affine.dx = 0; + paint->u.transform.affine.dy = 0; + } + + return 1; + } + + return read_paint( face, colr, opaque_paint.p, paint ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_colr_blend_layer( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot dstSlot, + FT_GlyphSlot srcSlot ) + { + FT_Error error; + + FT_UInt x, y; + FT_Byte b, g, r, alpha; + + FT_ULong size; + FT_Byte* src; + FT_Byte* dst; + + + if ( !dstSlot->bitmap.buffer ) + { + /* Initialize destination of color bitmap */ + /* with the size of first component. */ + dstSlot->bitmap_left = srcSlot->bitmap_left; + dstSlot->bitmap_top = srcSlot->bitmap_top; + + dstSlot->bitmap.width = srcSlot->bitmap.width; + dstSlot->bitmap.rows = srcSlot->bitmap.rows; + dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4; + dstSlot->bitmap.num_grays = 256; + + size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch; + + error = ft_glyphslot_alloc_bitmap( dstSlot, size ); + if ( error ) + return error; + + FT_MEM_ZERO( dstSlot->bitmap.buffer, size ); + } + else + { + /* Resize destination if needed such that new component fits. */ + FT_Int x_min, x_max, y_min, y_max; + + + x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left ); + x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width, + srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width ); + + y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows, + srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows ); + y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top ); + + if ( x_min != dstSlot->bitmap_left || + x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width || + y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows || + y_max != dstSlot->bitmap_top ) + { + FT_Memory memory = face->root.memory; + + FT_UInt width = (FT_UInt)( x_max - x_min ); + FT_UInt rows = (FT_UInt)( y_max - y_min ); + FT_UInt pitch = width * 4; + + FT_Byte* buf = NULL; + FT_Byte* p; + FT_Byte* q; + + + size = rows * pitch; + if ( FT_ALLOC( buf, size ) ) + return error; + + p = dstSlot->bitmap.buffer; + q = buf + + (int)pitch * ( y_max - dstSlot->bitmap_top ) + + 4 * ( dstSlot->bitmap_left - x_min ); + + for ( y = 0; y < dstSlot->bitmap.rows; y++ ) + { + FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 ); + + p += dstSlot->bitmap.pitch; + q += pitch; + } + + ft_glyphslot_set_bitmap( dstSlot, buf ); + + dstSlot->bitmap_top = y_max; + dstSlot->bitmap_left = x_min; + + dstSlot->bitmap.width = width; + dstSlot->bitmap.rows = rows; + dstSlot->bitmap.pitch = (int)pitch; + + dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP; + dstSlot->format = FT_GLYPH_FORMAT_BITMAP; + } + } + + if ( color_index == 0xFFFF ) + { + if ( face->have_foreground_color ) + { + b = face->foreground_color.blue; + g = face->foreground_color.green; + r = face->foreground_color.red; + alpha = face->foreground_color.alpha; + } + else + { + if ( face->palette_data.palette_flags && + ( face->palette_data.palette_flags[face->palette_index] & + FT_PALETTE_FOR_DARK_BACKGROUND ) ) + { + /* white opaque */ + b = 0xFF; + g = 0xFF; + r = 0xFF; + alpha = 0xFF; + } + else + { + /* black opaque */ + b = 0x00; + g = 0x00; + r = 0x00; + alpha = 0xFF; + } + } + } + else + { + b = face->palette[color_index].blue; + g = face->palette[color_index].green; + r = face->palette[color_index].red; + alpha = face->palette[color_index].alpha; + } + + /* XXX Convert if srcSlot.bitmap is not grey? */ + src = srcSlot->bitmap.buffer; + dst = dstSlot->bitmap.buffer + + dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) + + 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left ); + + for ( y = 0; y < srcSlot->bitmap.rows; y++ ) + { + for ( x = 0; x < srcSlot->bitmap.width; x++ ) + { + int aa = src[x]; + int fa = alpha * aa / 255; + + int fb = b * fa / 255; + int fg = g * fa / 255; + int fr = r * fa / 255; + + int ba2 = 255 - fa; + + int bb = dst[4 * x + 0]; + int bg = dst[4 * x + 1]; + int br = dst[4 * x + 2]; + int ba = dst[4 * x + 3]; + + + dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); + dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); + dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); + dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa ); + } + + src += srcSlot->bitmap.pitch; + dst += dstSlot->bitmap.pitch; + } + + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_colr_dummy_; + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + +/* EOF */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcolr.h b/Dependencies/freetype/freetype/src/sfnt/ttcolr.h new file mode 100644 index 00000000..30031464 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcolr.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * + * ttcolr.h + * + * TrueType and OpenType colored glyph layer support (specification). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef __TTCOLR_H__ +#define __TTCOLR_H__ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_colr( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_colr( TT_Face face ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colr_layer( TT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + + FT_LOCAL( FT_Error ) + tt_face_colr_blend_layer( TT_Face face, + FT_UInt color_index, + FT_GlyphSlot dstSlot, + FT_GlyphSlot srcSlot ); + + +FT_END_HEADER + + +#endif /* __TTCOLR_H__ */ + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcpal.c b/Dependencies/freetype/freetype/src/sfnt/ttcpal.c new file mode 100644 index 00000000..997eb869 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcpal.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * + * ttcpal.c + * + * TrueType and OpenType color palette support (body). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * `CPAL' table specification: + * + * https://www.microsoft.com/typography/otspec/cpal.htm + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS + +#include "ttcpal.h" + + + /* NOTE: These are the table sizes calculated through the specs. */ +#define CPAL_V0_HEADER_BASE_SIZE 12U +#define COLOR_SIZE 4U + + + /* all data from `CPAL' not covered in FT_Palette_Data */ + typedef struct Cpal_ + { + FT_UShort version; /* Table version number (0 or 1 supported). */ + FT_UShort num_colors; /* Total number of color records, */ + /* combined for all palettes. */ + FT_Byte* colors; /* RGBA array of colors */ + FT_Byte* color_indices; /* Index of each palette's first color record */ + /* in the combined color record array. */ + + /* The memory which backs up the `CPAL' table. */ + void* table; + FT_ULong table_size; + + } Cpal; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttcpal + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cpal( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_Byte* table = NULL; + FT_Byte* p = NULL; + + Cpal* cpal = NULL; + + FT_ULong colors_offset; + FT_ULong table_size; + + + error = face->goto_table( face, TTAG_CPAL, stream, &table_size ); + if ( error ) + goto NoCpal; + + if ( table_size < CPAL_V0_HEADER_BASE_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoCpal; + + p = table; + + if ( FT_NEW( cpal ) ) + goto NoCpal; + + cpal->version = FT_NEXT_USHORT( p ); + if ( cpal->version > 1 ) + goto InvalidTable; + + face->palette_data.num_palette_entries = FT_NEXT_USHORT( p ); + face->palette_data.num_palettes = FT_NEXT_USHORT( p ); + + cpal->num_colors = FT_NEXT_USHORT( p ); + colors_offset = FT_NEXT_ULONG( p ); + + if ( CPAL_V0_HEADER_BASE_SIZE + + face->palette_data.num_palettes * 2U > table_size ) + goto InvalidTable; + + if ( colors_offset >= table_size ) + goto InvalidTable; + if ( cpal->num_colors * COLOR_SIZE > table_size - colors_offset ) + goto InvalidTable; + + if ( face->palette_data.num_palette_entries > cpal->num_colors ) + goto InvalidTable; + + cpal->color_indices = p; + cpal->colors = (FT_Byte*)( table + colors_offset ); + + if ( cpal->version == 1 ) + { + FT_ULong type_offset, label_offset, entry_label_offset; + FT_UShort* array = NULL; + FT_UShort* limit; + FT_UShort* q; + + + if ( CPAL_V0_HEADER_BASE_SIZE + + face->palette_data.num_palettes * 2U + + 3U * 4 > table_size ) + goto InvalidTable; + + p += face->palette_data.num_palettes * 2U; + + type_offset = FT_NEXT_ULONG( p ); + label_offset = FT_NEXT_ULONG( p ); + entry_label_offset = FT_NEXT_ULONG( p ); + + if ( type_offset ) + { + if ( type_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palettes * 2U > + table_size - type_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) ) + goto NoCpal; + + p = table + type_offset; + q = array; + limit = q + face->palette_data.num_palettes; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_flags = array; + } + + if ( label_offset ) + { + if ( label_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palettes * 2U > + table_size - label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) ) + goto NoCpal; + + p = table + label_offset; + q = array; + limit = q + face->palette_data.num_palettes; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_name_ids = array; + } + + if ( entry_label_offset ) + { + if ( entry_label_offset >= table_size ) + goto InvalidTable; + if ( face->palette_data.num_palette_entries * 2U > + table_size - entry_label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette_data.num_palette_entries ) ) + goto NoCpal; + + p = table + entry_label_offset; + q = array; + limit = q + face->palette_data.num_palette_entries; + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette_data.palette_entry_name_ids = array; + } + } + + cpal->table = table; + cpal->table_size = table_size; + + face->cpal = cpal; + + /* set up default palette */ + if ( FT_NEW_ARRAY( face->palette, + face->palette_data.num_palette_entries ) ) + goto NoCpal; + + if ( tt_face_palette_set( face, 0 ) ) + goto InvalidTable; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoCpal: + FT_FRAME_RELEASE( table ); + FT_FREE( cpal ); + + face->cpal = NULL; + + /* arrays in `face->palette_data' and `face->palette' */ + /* are freed in `sfnt_done_face' */ + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_cpal( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + + Cpal* cpal = (Cpal*)face->cpal; + + + if ( cpal ) + { + FT_FRAME_RELEASE( cpal->table ); + FT_FREE( cpal ); + } + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_palette_set( TT_Face face, + FT_UInt palette_index ) + { + Cpal* cpal = (Cpal*)face->cpal; + + FT_Byte* offset; + FT_Byte* p; + + FT_Color* q; + FT_Color* limit; + + FT_UShort color_index; + + + if ( !cpal || palette_index >= face->palette_data.num_palettes ) + return FT_THROW( Invalid_Argument ); + + offset = cpal->color_indices + 2 * palette_index; + color_index = FT_PEEK_USHORT( offset ); + + if ( color_index + face->palette_data.num_palette_entries > + cpal->num_colors ) + return FT_THROW( Invalid_Table ); + + p = cpal->colors + COLOR_SIZE * color_index; + q = face->palette; + limit = q + face->palette_data.num_palette_entries; + + while ( q < limit ) + { + q->blue = FT_NEXT_BYTE( p ); + q->green = FT_NEXT_BYTE( p ); + q->red = FT_NEXT_BYTE( p ); + q->alpha = FT_NEXT_BYTE( p ); + + q++; + } + + return FT_Err_Ok; + } + + +#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_cpal_dummy_; + +#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ + +/* EOF */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttcpal.h b/Dependencies/freetype/freetype/src/sfnt/ttcpal.h new file mode 100644 index 00000000..bb301ae8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttcpal.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * + * ttcpal.h + * + * TrueType and OpenType color palette support (specification). + * + * Copyright (C) 2018-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Originally written by Shao Yu Zhang . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef __TTCPAL_H__ +#define __TTCPAL_H__ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_cpal( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_cpal( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_palette_set( TT_Face face, + FT_UInt palette_index ); + + +FT_END_HEADER + + +#endif /* __TTCPAL_H__ */ + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttgpos.c b/Dependencies/freetype/freetype/src/sfnt/ttgpos.c new file mode 100644 index 00000000..b6cd8bf8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttgpos.c @@ -0,0 +1,598 @@ +/**************************************************************************** + * + * ttgpos.c + * + * Load the TrueType GPOS table. The only GPOS layout feature this + * currently supports is kerning, from x advances in the pair adjustment + * layout feature. + * + * Parts of the implementation were adapted from: + * https://github.com/nothings/stb/blob/master/stb_truetype.h + * + * GPOS spec reference available at: + * https://learn.microsoft.com/en-us/typography/opentype/spec/gpos + * + * Copyright (C) 2024 by + * David Saltzman + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + */ + +#include +#include +#include +#include "freetype/fttypes.h" +#include "freetype/internal/ftobjs.h" +#include "ttgpos.h" + + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttgpos + + + typedef enum coverage_table_format_type_ + { + COVERAGE_TABLE_FORMAT_LIST = 1, + COVERAGE_TABLE_FORMAT_RANGE = 2 + + } coverage_table_format_type; + + typedef enum class_def_table_format_type_ + { + CLASS_DEF_TABLE_FORMAT_ARRAY = 1, + CLASS_DEF_TABLE_FORMAT_RANGE_GROUPS = 2 + + } class_def_table_format_type; + + typedef enum gpos_lookup_type_ + { + GPOS_LOOKUP_TYPE_NONE = 0, + GPOS_LOOKUP_TYPE_SINGLE_ADJUSTMENT = 1, + GPOS_LOOKUP_TYPE_PAIR_ADJUSTMENT = 2, + GPOS_LOOKUP_TYPE_CURSIVE_ATTACHMENT = 3, + GPOS_LOOKUP_TYPE_MARK_TO_BASE_ATTACHMENT = 4, + GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE_ATTACHMENT = 5, + GPOS_LOOKUP_TYPE_MARK_TO_MARK_ATTACHMENT = 6, + GPOS_LOOKUP_TYPE_CONTEXT_POSITIONING = 7, + GPOS_LOOKUP_TYPE_CHAINED_CONTEXT_POSITIONING = 8, + GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING = 9 + + } gpos_lookup_type; + + typedef enum gpos_pair_adjustment_format_ + { + GPOS_PAIR_ADJUSTMENT_FORMAT_GLYPH_PAIR = 1, + GPOS_PAIR_ADJUSTMENT_FORMAT_CLASS_PAIR = 2 + + } gpos_pair_adjustment_format; + + typedef enum gpos_value_format_bitmask_ + { + GPOS_VALUE_FORMAT_NONE = 0x0000, + GPOS_VALUE_FORMAT_X_PLACEMENT = 0x0001, + GPOS_VALUE_FORMAT_Y_PLACEMENT = 0x0002, + GPOS_VALUE_FORMAT_X_ADVANCE = 0x0004, + GPOS_VALUE_FORMAT_Y_ADVANCE = 0x0008, + GPOS_VALUE_FORMAT_X_PLACEMENT_DEVICE = 0x0010, + GPOS_VALUE_FORMAT_Y_PLACEMENT_DEVICE = 0x0020, + GPOS_VALUE_FORMAT_X_ADVANCE_DEVICE = 0x0040, + GPOS_VALUE_FORMAT_Y_ADVANCE_DEVICE = 0x0080 + + } gpos_value_format_bitmask; + + + typedef struct TT_GPOS_Subtable_Iterator_Context_ + { + /* Iteration state. */ + FT_Byte* current_lookup_table; + gpos_lookup_type current_lookup_type; + FT_UShort subtable_count; + FT_Byte* subtable_offsets; + FT_UInt subtable_idx; + + /* Element for the current iteration. */ + FT_Byte* subtable; + gpos_lookup_type subtable_type; + + } TT_GPOS_Subtable_Iterator_Context; + + + /* Initialize a subtable iterator for a given lookup list index. */ + static void + tt_gpos_subtable_iterator_init( + TT_GPOS_Subtable_Iterator_Context* context, + FT_Byte* gpos_table, + FT_ULong lookup_list_idx ) + { + FT_Byte* lookup_list = gpos_table + FT_PEEK_USHORT( gpos_table + 8 ); + FT_UInt16 lookup_count = FT_PEEK_USHORT( lookup_list ); + + + if ( lookup_list_idx < lookup_count ) + { + context->current_lookup_table = + lookup_list + FT_PEEK_USHORT( lookup_list + 2 + 2 * lookup_list_idx ); + context->current_lookup_type = + (gpos_lookup_type)FT_PEEK_USHORT( context->current_lookup_table ); + context->subtable_count = + FT_PEEK_USHORT( context->current_lookup_table + 4 ); + context->subtable_offsets = context->current_lookup_table + 6; + } + else + { + context->current_lookup_table = NULL; + context->current_lookup_type = GPOS_LOOKUP_TYPE_NONE; + context->subtable_count = 0; + context->subtable_offsets = NULL; + } + + context->subtable_idx = 0; + context->subtable = NULL; + context->subtable_type = GPOS_LOOKUP_TYPE_NONE; + } + + + /* Get the next subtable. Return whether there was a next one. */ + static FT_Bool + tt_gpos_subtable_iterator_next( + TT_GPOS_Subtable_Iterator_Context* context ) + { + if ( context->subtable_idx < context->subtable_count ) + { + FT_UShort subtable_offset = + FT_PEEK_USHORT( context->subtable_offsets + + 2 * context->subtable_idx ); + + + context->subtable = context->current_lookup_table + subtable_offset; + + if ( context->current_lookup_type == + GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING ) + { + /* Update type and subtable based on extension positioning header. */ + context->subtable_type = + (gpos_lookup_type)FT_PEEK_USHORT( context->subtable + 2 ); + context->subtable += FT_PEEK_ULONG( context->subtable + 4 ); + } + else + context->subtable_type = context->current_lookup_type; + + context->subtable_idx++; + return TRUE; + } + + return FALSE; + } + + + static FT_Int + tt_gpos_get_coverage_index( FT_Byte *coverage_table, + FT_UInt glyph ) + { + coverage_table_format_type coverage_format = + (coverage_table_format_type)FT_PEEK_USHORT( coverage_table ); + + + switch ( coverage_format ) + { + case COVERAGE_TABLE_FORMAT_LIST: + { + FT_UShort glyph_count = FT_PEEK_USHORT( coverage_table + 2 ); + + FT_Int l = 0; + FT_Int r = glyph_count - 1; + FT_Int m; + + FT_Int straw; + FT_Int needle = (FT_Int)glyph; + + + /* Binary search. */ + while ( l <= r ) + { + FT_Byte *glyph_array = coverage_table + 4; + FT_UShort glyph_id; + + + m = ( l + r ) >> 1; + glyph_id = FT_PEEK_USHORT( glyph_array + 2 * m ); + straw = glyph_id; + + if ( needle < straw ) + r = m - 1; + else if ( needle > straw ) + l = m + 1; + else + return m; + } + break; + } + + case COVERAGE_TABLE_FORMAT_RANGE: + { + FT_UShort range_count = FT_PEEK_USHORT( coverage_table + 2 ); + FT_Byte *range_array = coverage_table + 4; + + FT_Int l = 0; + FT_Int r = range_count - 1; + FT_Int m; + + FT_Int straw_start; + FT_Int straw_end; + FT_Int needle = (FT_Int)glyph; + + + /* Binary search. */ + while ( l <= r ) + { + FT_Byte *range_record; + + + m = ( l + r ) >> 1; + range_record = range_array + 6 * m; + straw_start = FT_PEEK_USHORT( range_record ); + straw_end = FT_PEEK_USHORT( range_record + 2 ); + + if ( needle < straw_start ) + r = m - 1; + else if ( needle > straw_end ) + l = m + 1; + else + { + FT_UShort start_coverage_index = + FT_PEEK_USHORT( range_record + 4 ); + + + return (FT_Int)start_coverage_index + (FT_Int)glyph - straw_start; + } + } + break; + } + } + + return -1; + } + + + static FT_Int + tt_gpos_get_glyph_class( FT_Byte *class_def_table, + FT_UInt glyph ) + { + class_def_table_format_type class_def_format = + (class_def_table_format_type)FT_PEEK_USHORT( class_def_table ); + + + switch ( class_def_format ) + { + case CLASS_DEF_TABLE_FORMAT_ARRAY: + { + FT_UInt start_glyph_id = FT_PEEK_USHORT( class_def_table + 2 ); + FT_UInt glyph_count = FT_PEEK_USHORT( class_def_table + 4 ); + FT_Byte *class_value_array = class_def_table + 6; + + + if ( glyph >= start_glyph_id && + glyph < start_glyph_id + glyph_count ) + return (FT_Int)FT_PEEK_USHORT( class_value_array + + 2 * ( glyph - start_glyph_id ) ); + break; + } + + case CLASS_DEF_TABLE_FORMAT_RANGE_GROUPS: + { + FT_UShort class_range_count = FT_PEEK_USHORT( class_def_table + 2 ); + FT_Byte *class_range_records = class_def_table + 4; + + FT_Int l = 0; + FT_Int r = class_range_count - 1; + FT_Int m; + + FT_Int straw_start; + FT_Int straw_end; + FT_Int needle = (FT_Int)glyph; + + + while ( l <= r ) + { + FT_Byte *class_range_record; + + + m = ( l + r ) >> 1; + class_range_record = class_range_records + 6 * m; + straw_start = FT_PEEK_USHORT( class_range_record ); + straw_end = FT_PEEK_USHORT( class_range_record + 2 ); + + if ( needle < straw_start ) + r = m - 1; + else if ( needle > straw_end ) + l = m + 1; + else + return (FT_Int)FT_PEEK_USHORT( class_range_record + 4 ); + } + break; + } + } + + /* "All glyphs not assigned to a class fall into class 0." */ + /* (OpenType spec) */ + return 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gpos( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + + + /* The GPOS table is optional; exit silently if it is missing. */ + error = face->goto_table( face, TTAG_GPOS, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 4 ) /* the case of a malformed table */ + { + FT_ERROR(( "tt_face_load_gpos:" + " GPOS table is too small - ignored\n" )); + error = FT_THROW( Table_Missing ); + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->gpos_table ) ) + { + FT_ERROR(( "tt_face_load_gpos:" + " could not extract GPOS table\n" )); + goto Exit; + } + + face->gpos_kerning_available = FALSE; + + if ( face->gpos_table ) + { + FT_Byte* feature_list = face->gpos_table + + FT_PEEK_USHORT( face->gpos_table + 6 ); + FT_UInt16 feature_count = FT_PEEK_USHORT( feature_list ); + FT_Byte* feature_records = feature_list + 2; + + FT_UInt idx; + + + for ( idx = 0; idx < feature_count; idx++, feature_records += 6 ) + { + FT_ULong feature_tag = FT_PEEK_ULONG( feature_records ); + + + if ( feature_tag == TTAG_kern ) + { + face->gpos_kerning_available = TRUE; + break; + } + } + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_gpos( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->gpos_table ); + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_gpos_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Byte* feature_list; + FT_UInt16 feature_count; + FT_Byte* feature_records; + FT_UInt feature_idx; + + + if ( !face->gpos_kerning_available ) + return 0; + + feature_list = face->gpos_table + + FT_PEEK_USHORT( face->gpos_table + 6 ); + feature_count = FT_PEEK_USHORT( feature_list ); + feature_records = feature_list + 2; + + for ( feature_idx = 0; + feature_idx < feature_count; + feature_idx++, feature_records += 6 ) + { + FT_ULong feature_tag = FT_PEEK_ULONG( feature_records ); + FT_Byte* feature_table; + FT_UInt16 lookup_idx_count; + FT_UInt16 lookup_idx; + + + if ( feature_tag != TTAG_kern ) + continue; + + feature_table = feature_list + FT_PEEK_USHORT( feature_records + 4 ); + lookup_idx_count = FT_PEEK_USHORT( feature_table + 2 ); + + for ( lookup_idx = 0; lookup_idx < lookup_idx_count; lookup_idx++ ) + { + FT_UInt16 lookup_list_idx = + FT_PEEK_USHORT( feature_table + 4 + 2 * lookup_idx ); + TT_GPOS_Subtable_Iterator_Context subtable_iter; + + + tt_gpos_subtable_iterator_init( &subtable_iter, + face->gpos_table, + lookup_list_idx ); + + while ( tt_gpos_subtable_iterator_next( &subtable_iter ) ) + { + FT_Byte* subtable; + + gpos_value_format_bitmask value_format_1; + gpos_value_format_bitmask value_format_2; + gpos_pair_adjustment_format format; + + FT_UShort coverage_offset; + FT_Int coverage_index; + + + if ( subtable_iter.subtable_type != + GPOS_LOOKUP_TYPE_PAIR_ADJUSTMENT ) + continue; + + subtable = subtable_iter.subtable; + + value_format_1 = + (gpos_value_format_bitmask)FT_PEEK_USHORT( subtable + 4 ); + value_format_2 = + (gpos_value_format_bitmask)FT_PEEK_USHORT( subtable + 6 ); + + if ( !( value_format_1 == GPOS_VALUE_FORMAT_X_ADVANCE && + value_format_2 == GPOS_VALUE_FORMAT_NONE ) ) + continue; + + format = (gpos_pair_adjustment_format)FT_PEEK_USHORT( subtable ); + + coverage_offset = FT_PEEK_USHORT( subtable + 2 ); + coverage_index = + tt_gpos_get_coverage_index( subtable + coverage_offset, + left_glyph ); + + if ( coverage_index == -1 ) + continue; + + switch ( format ) + { + case GPOS_PAIR_ADJUSTMENT_FORMAT_GLYPH_PAIR: + { + FT_Int l, r, m; + FT_Int straw, needle; + + FT_Int value_record_pair_size_in_bytes = 2; + + FT_UShort pair_set_count = FT_PEEK_USHORT( subtable + 8 ); + FT_UShort pair_pos_offset; + + FT_Byte* pair_value_table; + FT_UShort pair_value_count; + FT_Byte* pair_value_array; + + + if ( coverage_index >= pair_set_count ) + return 0; + + pair_pos_offset = + FT_PEEK_USHORT( subtable + 10 + 2 * coverage_index ); + + pair_value_table = subtable + pair_pos_offset; + pair_value_count = FT_PEEK_USHORT( pair_value_table ); + pair_value_array = pair_value_table + 2; + + needle = (FT_Int)right_glyph; + r = pair_value_count - 1; + l = 0; + + /* Binary search. */ + while ( l <= r ) + { + FT_UShort second_glyph; + FT_Byte* pair_value; + + + m = ( l + r ) >> 1; + pair_value = pair_value_array + + ( 2 + value_record_pair_size_in_bytes ) * m; + second_glyph = FT_PEEK_USHORT( pair_value ); + straw = second_glyph; + + if ( needle < straw ) + r = m - 1; + else if ( needle > straw ) + l = m + 1; + else + { + FT_Short x_advance = FT_PEEK_SHORT( pair_value + 2 ); + + + return x_advance; + } + } + break; + } + + case GPOS_PAIR_ADJUSTMENT_FORMAT_CLASS_PAIR: + { + FT_UShort class_def1_offset = FT_PEEK_USHORT( subtable + 8 ); + FT_UShort class_def2_offset = FT_PEEK_USHORT( subtable + 10 ); + + FT_Int left_glyph_class = + tt_gpos_get_glyph_class( subtable + class_def1_offset, + left_glyph ); + FT_Int right_glyph_class = + tt_gpos_get_glyph_class( subtable + class_def2_offset, + right_glyph ); + + FT_UShort class1_count = FT_PEEK_USHORT( subtable + 12 ); + FT_UShort class2_count = FT_PEEK_USHORT( subtable + 14 ); + + FT_Byte *class1_records, *class2_records; + FT_Short x_advance; + + + if ( left_glyph_class < 0 || + left_glyph_class >= class1_count ) + return 0; /* malformed */ + if ( right_glyph_class < 0 || + right_glyph_class >= class2_count ) + return 0; /* malformed */ + + if ( right_glyph_class == 0 ) + continue; /* right glyph not found in this table */ + + class1_records = subtable + 16; + class2_records = + class1_records + 2 * ( left_glyph_class * class2_count ); + + x_advance = + FT_PEEK_SHORT( class2_records + 2 * right_glyph_class ); + + return x_advance; + } + } + } + } + } + + return 0; + } + +#else /* !TT_CONFIG_OPTION_GPOS_KERNING */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_gpos_dummy_; + +#endif /* !TT_CONFIG_OPTION_GPOS_KERNING */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttgpos.h b/Dependencies/freetype/freetype/src/sfnt/ttgpos.h new file mode 100644 index 00000000..570e9e3d --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttgpos.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * + * ttgpos.c + * + * Load the TrueType GPOS table. The only GPOS layout feature this + * currently supports is kerning, from x advances in the pair adjustment + * layout feature. + * + * Copyright (C) 2024 by + * David Saltzman + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + */ + + +#ifndef TTGPOS_H_ +#define TTGPOS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + + FT_LOCAL( FT_Error ) + tt_face_load_gpos( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_gpos( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_gpos_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + +#endif /* TT_CONFIG_OPTION_GPOS_KERNING */ + + +FT_END_HEADER + +#endif /* TTGPOS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttkern.c b/Dependencies/freetype/freetype/src/sfnt/ttkern.c new file mode 100644 index 00000000..f0411366 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttkern.c @@ -0,0 +1,317 @@ +/**************************************************************************** + * + * ttkern.c + * + * Load the basic TrueType kerning table. This doesn't handle + * kerning data within the GPOS table at the moment. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttkern.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttkern + + +#undef TT_KERN_INDEX +#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, num_tables; + FT_UInt32 avail = 0, ordered = 0; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 4 ) /* the case of a malformed table */ + { + FT_ERROR(( "tt_face_load_kern:" + " kerning table is too small - ignored\n" )); + error = FT_THROW( Table_Missing ); + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) + { + FT_ERROR(( "tt_face_load_kern:" + " could not extract kerning table\n" )); + goto Exit; + } + + face->kern_table_size = table_size; + + p = face->kern_table; + p_limit = p + table_size; + + p += 2; /* skip version */ + num_tables = FT_NEXT_USHORT( p ); + + if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ + num_tables = 32; + + for ( nn = 0; nn < num_tables; nn++ ) + { + FT_UInt num_pairs, length, coverage, format; + FT_Byte* p_next; + FT_UInt32 mask = (FT_UInt32)1UL << nn; + + + if ( p + 6 > p_limit ) + break; + + p_next = p; + + p += 2; /* skip version */ + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + + if ( length <= 6 + 8 ) + break; + + p_next += length; + + if ( p_next > p_limit ) /* handle broken table */ + p_next = p_limit; + + format = coverage >> 8; + + /* we currently only support format 0 kerning tables */ + if ( format != 0 ) + goto NextTable; + + /* only use horizontal kerning tables */ + if ( ( coverage & 3U ) != 0x0001 || + p + 8 > p_next ) + goto NextTable; + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ + num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); + + avail |= mask; + + /* + * Now check whether the pairs in this table are ordered. + * We then can use binary search. + */ + if ( num_pairs > 0 ) + { + FT_ULong count; + FT_ULong old_pair; + + + old_pair = FT_NEXT_ULONG( p ); + p += 2; + + for ( count = num_pairs - 1; count > 0; count-- ) + { + FT_UInt32 cur_pair; + + + cur_pair = FT_NEXT_ULONG( p ); + if ( cur_pair < old_pair ) + break; + + p += 2; + old_pair = cur_pair; + } + + if ( count == 0 ) + ordered |= mask; + } + + NextTable: + p = p_next; + } + + face->num_kern_tables = nn; + face->kern_avail_bits = avail; + face->kern_order_bits = ordered; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->kern_table ); + face->kern_table_size = 0; + face->num_kern_tables = 0; + face->kern_avail_bits = 0; + face->kern_order_bits = 0; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + FT_UInt count, mask; + + FT_Byte* p; + FT_Byte* p_limit; + + + if ( !face->kern_table ) + return result; + + p = face->kern_table; + p_limit = p + face->kern_table_size; + + p += 4; + mask = 0x0001; + + for ( count = face->num_kern_tables; + count > 0 && p + 6 <= p_limit; + count--, mask <<= 1 ) + { + FT_Byte* base = p; + FT_Byte* next; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt length = FT_NEXT_USHORT( p ); + FT_UInt coverage = FT_NEXT_USHORT( p ); + FT_UInt num_pairs; + FT_Int value = 0; + + FT_UNUSED( version ); + + + next = base + length; + + if ( next > p_limit ) /* handle broken table */ + next = p_limit; + + if ( ( face->kern_avail_bits & mask ) == 0 ) + goto NextTable; + + FT_ASSERT( p + 8 <= next ); /* tested in tt_face_load_kern */ + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( ( next - p ) < 6 * (int)num_pairs ) /* handle broken count */ + num_pairs = (FT_UInt)( ( next - p ) / 6 ); + + switch ( coverage >> 8 ) + { + case 0: + { + FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); + + + if ( face->kern_order_bits & mask ) /* binary search */ + { + FT_UInt min = 0; + FT_UInt max = num_pairs; + + + while ( min < max ) + { + FT_UInt mid = ( min + max ) >> 1; + FT_Byte* q = p + 6 * mid; + FT_ULong key; + + + key = FT_NEXT_ULONG( q ); + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( q ); + goto Found; + } + if ( key < key0 ) + min = mid + 1; + else + max = mid; + } + } + else /* linear search */ + { + FT_UInt count2; + + + for ( count2 = num_pairs; count2 > 0; count2-- ) + { + FT_ULong key = FT_NEXT_ULONG( p ); + + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( p ); + goto Found; + } + p += 2; + } + } + } + break; + + /* + * We don't support format 2 because we haven't seen a single font + * using it in real life... + */ + + default: + ; + } + + goto NextTable; + + Found: + if ( coverage & 8 ) /* override or add */ + result = value; + else + result += value; + + NextTable: + p = next; + } + + return result; + } + +#undef TT_KERN_INDEX + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttkern.h b/Dependencies/freetype/freetype/src/sfnt/ttkern.h new file mode 100644 index 00000000..a54e51df --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttkern.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * ttkern.h + * + * Load the basic TrueType kerning table. This doesn't handle + * kerning data within the GPOS table at the moment. + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTKERN_H_ +#define TTKERN_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_kern( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + +#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) + + +FT_END_HEADER + +#endif /* TTKERN_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttload.c b/Dependencies/freetype/freetype/src/sfnt/ttload.c new file mode 100644 index 00000000..c3a5fae2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttload.c @@ -0,0 +1,1496 @@ +/**************************************************************************** + * + * ttload.c + * + * Load the basic TrueType tables, i.e., tables that can be either in + * TTF or OTF fonts (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ttload.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttload + + + /************************************************************************** + * + * @Function: + * tt_face_lookup_table + * + * @Description: + * Looks for a TrueType table by name. + * + * @Input: + * face :: + * A face object handle. + * + * tag :: + * The searched tag. + * + * @Return: + * A pointer to the table directory entry. 0 if not found. + */ + FT_LOCAL_DEF( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ) + { + TT_Table entry; + TT_Table limit; +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Bool zero_length = FALSE; +#endif + + + FT_TRACE4(( "tt_face_lookup_table: %p, `%c%c%c%c' -- ", + (void *)face, + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + + entry = face->dir_tables; + limit = entry + face->num_tables; + + for ( ; entry < limit; entry++ ) + { + /* For compatibility with Windows, we consider */ + /* zero-length tables the same as missing tables. */ + if ( entry->Tag == tag ) + { + if ( entry->Length != 0 ) + { + FT_TRACE4(( "found table.\n" )); + return entry; + } +#ifdef FT_DEBUG_LEVEL_TRACE + zero_length = TRUE; +#endif + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( zero_length ) + FT_TRACE4(( "ignoring empty table\n" )); + else + FT_TRACE4(( "could not find table\n" )); +#endif + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * tt_face_goto_table + * + * @Description: + * Looks for a TrueType table by name, then seek a stream to it. + * + * @Input: + * face :: + * A face object handle. + * + * tag :: + * The searched tag. + * + * stream :: + * The stream to seek when the table is found. + * + * @Output: + * length :: + * The length of the table if found, undefined otherwise. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ) + { + TT_Table table; + FT_Error error; + + + table = tt_face_lookup_table( face, tag ); + if ( table ) + { + if ( length ) + *length = table->Length; + + if ( FT_STREAM_SEEK( table->Offset ) ) + goto Exit; + } + else + error = FT_THROW( Table_Missing ); + + Exit: + return error; + } + + + /* Here, we */ + /* */ + /* - check that `num_tables' is valid (and adjust it if necessary); */ + /* also return the number of valid table entries */ + /* */ + /* - look for a `head' table, check its size, and parse it to check */ + /* whether its `magic' field is correctly set */ + /* */ + /* - errors (except errors returned by stream handling) */ + /* */ + /* SFNT_Err_Unknown_File_Format: */ + /* no table is defined in directory, it is not sfnt-wrapped */ + /* data */ + /* SFNT_Err_Table_Missing: */ + /* table directory is valid, but essential tables */ + /* (head/bhed/SING) are missing */ + /* */ + static FT_Error + check_table_dir( SFNT_Header sfnt, + FT_Stream stream, + FT_UShort* valid ) + { + FT_Error error; + FT_UShort nn, valid_entries = 0; + FT_UInt has_head = 0, has_sing = 0, has_meta = 0; + FT_ULong offset = sfnt->offset + 12; + + static const FT_Frame_Field table_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_TableRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG( Tag ), + FT_FRAME_ULONG( CheckSum ), + FT_FRAME_ULONG( Offset ), + FT_FRAME_ULONG( Length ), + FT_FRAME_END + }; + + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + + for ( nn = 0; nn < sfnt->num_tables; nn++ ) + { + TT_TableRec table; + + + if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) + { + FT_TRACE2(( "check_table_dir:" + " can read only %hu table%s in font (instead of %hu)\n", + nn, nn == 1 ? "" : "s", sfnt->num_tables )); + sfnt->num_tables = nn; + break; + } + + /* we ignore invalid tables */ + + if ( table.Offset > stream->size ) + { + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); + continue; + } + else if ( table.Length > stream->size - table.Offset ) + { + /* Some tables have such a simple structure that clipping its */ + /* contents is harmless. This also makes FreeType less sensitive */ + /* to invalid table lengths (which programs like Acroread seem to */ + /* ignore in general). */ + + if ( table.Tag == TTAG_hmtx || + table.Tag == TTAG_vmtx ) + valid_entries++; + else + { + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); + continue; + } + } + else + valid_entries++; + + if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) + { + FT_UInt32 magic; + + +#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + if ( table.Tag == TTAG_head ) +#endif + has_head = 1; + + /* + * The table length should be 0x36, but certain font tools make it + * 0x38, so we will just check that it is greater. + * + * Note that according to the specification, the table must be + * padded to 32-bit lengths, but this doesn't apply to the value of + * its `Length' field! + * + */ + if ( table.Length < 0x36 ) + { + FT_TRACE2(( "check_table_dir:" + " `head' or `bhed' table too small\n" )); + error = FT_THROW( Table_Missing ); + goto Exit; + } + + if ( FT_STREAM_SEEK( table.Offset + 12 ) || + FT_READ_ULONG( magic ) ) + goto Exit; + + if ( magic != 0x5F0F3CF5UL ) + FT_TRACE2(( "check_table_dir:" + " invalid magic number in `head' or `bhed' table\n")); + + if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) + goto Exit; + } + else if ( table.Tag == TTAG_SING ) + has_sing = 1; + else if ( table.Tag == TTAG_META ) + has_meta = 1; + } + + *valid = valid_entries; + + if ( !valid_entries ) + { + FT_TRACE2(( "check_table_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* if `sing' and `meta' tables are present, there is no `head' table */ + if ( has_head || ( has_sing && has_meta ) ) + { + error = FT_Err_Ok; + goto Exit; + } + else + { + FT_TRACE2(( "check_table_dir:" )); +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); +#else + FT_TRACE2(( " neither `head' nor `sing' table found\n" )); +#endif + error = FT_THROW( Table_Missing ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_font_dir + * + * @Description: + * Loads the header of a SFNT font file. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Output: + * sfnt :: + * The SFNT header. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * The stream cursor must be at the beginning of the font directory. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ) + { + SFNT_HeaderRec sfnt; + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort nn, valid_entries = 0; + + static const FT_Frame_Field offset_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE SFNT_HeaderRec + + FT_FRAME_START( 8 ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( search_range ), + FT_FRAME_USHORT( entry_selector ), + FT_FRAME_USHORT( range_shift ), + FT_FRAME_END + }; + + + FT_TRACE2(( "tt_face_load_font_dir: %p\n", (void *)face )); + + /* read the offset table */ + + sfnt.offset = FT_STREAM_POS(); + + if ( FT_READ_ULONG( sfnt.format_tag ) || + FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) + goto Exit; + + /* many fonts don't have these fields set correctly */ +#if 0 + if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || + sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) + return FT_THROW( Unknown_File_Format ); +#endif + + /* load the table directory */ + + FT_TRACE2(( "-- Number of tables: %10hu\n", sfnt.num_tables )); + FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); + + if ( sfnt.format_tag != TTAG_OTTO ) + { + /* check first */ + error = check_table_dir( &sfnt, stream, &valid_entries ); + if ( error ) + { + FT_TRACE2(( "tt_face_load_font_dir:" + " invalid table directory for TrueType\n" )); + goto Exit; + } + } + else + { + valid_entries = sfnt.num_tables; + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + } + + face->num_tables = valid_entries; + face->format_tag = sfnt.format_tag; + + if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) + goto Exit; + + if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || + FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset length checksum\n" )); + FT_TRACE2(( " ----------------------------------\n" )); + + valid_entries = 0; + for ( nn = 0; nn < sfnt.num_tables; nn++ ) + { + TT_TableRec entry; + FT_UShort i; + FT_Bool duplicate; + + + entry.Tag = FT_GET_TAG4(); + entry.CheckSum = FT_GET_ULONG(); + entry.Offset = FT_GET_ULONG(); + entry.Length = FT_GET_ULONG(); + + /* ignore invalid tables that can't be sanitized */ + + if ( entry.Offset > stream->size ) + continue; + else if ( entry.Length > stream->size - entry.Offset ) + { + if ( entry.Tag == TTAG_hmtx || + entry.Tag == TTAG_vmtx ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + FT_ULong old_length = entry.Length; +#endif + + + /* make metrics table length a multiple of 4 */ + entry.Length = ( stream->size - entry.Offset ) & ~3U; + + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" + " (sanitized; original length %08lx)", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum, + old_length )); + } + else + continue; + } +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", + (FT_Char)( entry.Tag >> 24 ), + (FT_Char)( entry.Tag >> 16 ), + (FT_Char)( entry.Tag >> 8 ), + (FT_Char)( entry.Tag ), + entry.Offset, + entry.Length, + entry.CheckSum )); +#endif + + /* ignore duplicate tables – the first one wins */ + duplicate = 0; + for ( i = 0; i < valid_entries; i++ ) + { + if ( face->dir_tables[i].Tag == entry.Tag ) + { + duplicate = 1; + break; + } + } + if ( duplicate ) + { + FT_TRACE2(( " (duplicate, ignored)\n" )); + continue; + } + else + { + FT_TRACE2(( "\n" )); + + /* we finally have a valid entry */ + face->dir_tables[valid_entries++] = entry; + } + } + + /* final adjustment to number of tables */ + face->num_tables = valid_entries; + + FT_FRAME_EXIT(); + + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + FT_TRACE2(( "table directory loaded\n" )); + FT_TRACE2(( "\n" )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_any + * + * @Description: + * Loads any font table into client memory. + * + * @Input: + * face :: + * The face object to look for. + * + * tag :: + * The tag of table to load. Use the value 0 if you want + * to access the whole font file, else set this parameter + * to a valid TrueType table tag that you can forge with + * the MAKE_TT_TAG macro. + * + * offset :: + * The starting offset in the table (or the file if + * tag == 0). + * + * length :: + * The address of the decision variable: + * + * If length == NULL: + * Loads the whole table. Returns an error if + * `offset' == 0! + * + * If *length == 0: + * Exits immediately; returning the length of the given + * table or of the font file, depending on the value of + * `tag'. + * + * If *length != 0: + * Loads the next `length' bytes of table or font, + * starting at offset `offset' (in table or font too). + * + * @Output: + * buffer :: + * The address of target buffer. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Error error; + FT_Stream stream; + TT_Table table; + FT_ULong size; + + + if ( tag != 0 ) + { + /* look for tag in font directory */ + table = tt_face_lookup_table( face, tag ); + if ( !table ) + { + error = FT_THROW( Table_Missing ); + goto Exit; + } + + offset += table->Offset; + size = table->Length; + } + else + /* tag == 0 -- the user wants to access the font file directly */ + size = face->root.stream->size; + + if ( length && *length == 0 ) + { + *length = size; + + return FT_Err_Ok; + } + + if ( length ) + size = *length; + + stream = face->root.stream; + /* the `if' is syntactic sugar for picky compilers */ + if ( FT_STREAM_READ_AT( offset, buffer, size ) ) + goto Exit; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_generic_header + * + * @Description: + * Loads the TrueType table `head' or `bhed'. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + tt_face_load_generic_header( TT_Face face, + FT_Stream stream, + FT_ULong tag ) + { + FT_Error error; + TT_Header* header; + + static const FT_Frame_Field header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Header + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Table_Version ), + FT_FRAME_ULONG ( Font_Revision ), + FT_FRAME_LONG ( CheckSum_Adjust ), + FT_FRAME_LONG ( Magic_Number ), + FT_FRAME_USHORT( Flags ), + FT_FRAME_USHORT( Units_Per_EM ), + FT_FRAME_ULONG ( Created[0] ), + FT_FRAME_ULONG ( Created[1] ), + FT_FRAME_ULONG ( Modified[0] ), + FT_FRAME_ULONG ( Modified[1] ), + FT_FRAME_SHORT ( xMin ), + FT_FRAME_SHORT ( yMin ), + FT_FRAME_SHORT ( xMax ), + FT_FRAME_SHORT ( yMax ), + FT_FRAME_USHORT( Mac_Style ), + FT_FRAME_USHORT( Lowest_Rec_PPEM ), + FT_FRAME_SHORT ( Font_Direction ), + FT_FRAME_SHORT ( Index_To_Loc_Format ), + FT_FRAME_SHORT ( Glyph_Data_Format ), + FT_FRAME_END + }; + + + error = face->goto_table( face, tag, stream, 0 ); + if ( error ) + goto Exit; + + header = &face->header; + + if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) + goto Exit; + + FT_TRACE3(( "Units per EM: %4hu\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4hd\n", header->Index_To_Loc_Format )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_head ); + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_bhed ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + /************************************************************************** + * + * @Function: + * tt_face_load_maxp + * + * @Description: + * Loads the maximum profile into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_MaxProfile* maxProfile = &face->max_profile; + + static const FT_Frame_Field maxp_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_MaxProfile + + FT_FRAME_START( 6 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( numGlyphs ), + FT_FRAME_END + }; + + static const FT_Frame_Field maxp_fields_extra[] = + { + FT_FRAME_START( 26 ), + FT_FRAME_USHORT( maxPoints ), + FT_FRAME_USHORT( maxContours ), + FT_FRAME_USHORT( maxCompositePoints ), + FT_FRAME_USHORT( maxCompositeContours ), + FT_FRAME_USHORT( maxZones ), + FT_FRAME_USHORT( maxTwilightPoints ), + FT_FRAME_USHORT( maxStorage ), + FT_FRAME_USHORT( maxFunctionDefs ), + FT_FRAME_USHORT( maxInstructionDefs ), + FT_FRAME_USHORT( maxStackElements ), + FT_FRAME_USHORT( maxSizeOfInstructions ), + FT_FRAME_USHORT( maxComponentElements ), + FT_FRAME_USHORT( maxComponentDepth ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) + goto Exit; + + maxProfile->maxPoints = 0; + maxProfile->maxContours = 0; + maxProfile->maxCompositePoints = 0; + maxProfile->maxCompositeContours = 0; + maxProfile->maxZones = 0; + maxProfile->maxTwilightPoints = 0; + maxProfile->maxStorage = 0; + maxProfile->maxFunctionDefs = 0; + maxProfile->maxInstructionDefs = 0; + maxProfile->maxStackElements = 0; + maxProfile->maxSizeOfInstructions = 0; + maxProfile->maxComponentElements = 0; + maxProfile->maxComponentDepth = 0; + + if ( maxProfile->version >= 0x10000L ) + { + if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) + goto Exit; + + /* XXX: an adjustment that is necessary to load certain */ + /* broken fonts like `Keystrokes MT' :-( */ + /* */ + /* We allocate 64 function entries by default when */ + /* the maxFunctionDefs value is smaller. */ + + if ( maxProfile->maxFunctionDefs < 64 ) + maxProfile->maxFunctionDefs = 64; + + /* we add 4 phantom points later */ + if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) + { + FT_TRACE0(( "tt_face_load_maxp:" + " too much twilight points in `maxp' table;\n" )); + FT_TRACE0(( " " + " some glyphs might be rendered incorrectly\n" )); + + maxProfile->maxTwilightPoints = 0xFFFFU - 4; + } + } + + FT_TRACE3(( "numGlyphs: %hu\n", maxProfile->numGlyphs )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_name + * + * @Description: + * Loads the name records. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_pos, table_len; + FT_ULong storage_start, storage_limit; + TT_NameTable table; + TT_Name names = NULL; + TT_LangTag langTags = NULL; + + static const FT_Frame_Field name_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameTableRec + + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( format ), + FT_FRAME_USHORT( numNameRecords ), + FT_FRAME_USHORT( storageOffset ), + FT_FRAME_END + }; + + static const FT_Frame_Field name_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameRec + + /* no FT_FRAME_START */ + FT_FRAME_USHORT( platformID ), + FT_FRAME_USHORT( encodingID ), + FT_FRAME_USHORT( languageID ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + + static const FT_Frame_Field langTag_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_LangTagRec + + /* no FT_FRAME_START */ + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + + + table = &face->name_table; + table->stream = stream; + + error = face->goto_table( face, TTAG_name, stream, &table_len ); + if ( error ) + goto Exit; + + table_pos = FT_STREAM_POS(); + + if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) + goto Exit; + + /* Some popular Asian fonts have an invalid `storageOffset' value (it */ + /* should be at least `6 + 12*numNameRecords'). However, the string */ + /* offsets, computed as `storageOffset + entry->stringOffset', are */ + /* valid pointers within the name table... */ + /* */ + /* We thus can't check `storageOffset' right now. */ + /* */ + storage_start = table_pos + 6 + 12 * table->numNameRecords; + storage_limit = table_pos + table_len; + + if ( storage_start > storage_limit ) + { + FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); + error = FT_THROW( Name_Table_Missing ); + goto Exit; + } + + /* `name' format 1 contains additional language tag records, */ + /* which we load first */ + if ( table->format == 1 ) + { + if ( FT_STREAM_SEEK( storage_start ) || + FT_READ_USHORT( table->numLangTagRecords ) ) + goto Exit; + + storage_start += 2 + 4 * table->numLangTagRecords; + + /* allocate language tag records array */ + if ( FT_QNEW_ARRAY( langTags, table->numLangTagRecords ) || + FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) + goto Exit; + + /* load language tags */ + { + TT_LangTag entry = langTags; + TT_LangTag limit = FT_OFFSET( entry, table->numLangTagRecords ); + + + for ( ; entry < limit; entry++ ) + { + (void)FT_STREAM_READ_FIELDS( langTag_record_fields, entry ); + + /* check that the langTag string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { + /* invalid entry; ignore it */ + entry->stringLength = 0; + } + + /* mark the string as not yet loaded */ + entry->string = NULL; + } + + table->langTags = langTags; + langTags = NULL; + } + + FT_FRAME_EXIT(); + + (void)FT_STREAM_SEEK( table_pos + 6 ); + } + + /* allocate name records array */ + if ( FT_QNEW_ARRAY( names, table->numNameRecords ) || + FT_FRAME_ENTER( table->numNameRecords * 12 ) ) + goto Exit; + + /* load name records */ + { + TT_Name entry = names; + FT_UInt count = table->numNameRecords; + FT_UInt valid = 0; + + + for ( ; count > 0; count-- ) + { + if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) + continue; + + /* check that the name is not empty */ + if ( entry->stringLength == 0 ) + continue; + + /* check that the name string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { + /* invalid entry; ignore it */ + continue; + } + + /* assure that we have a valid language tag ID, and */ + /* that the corresponding langTag entry is valid, too */ + if ( table->format == 1 && entry->languageID >= 0x8000U ) + { + if ( entry->languageID - 0x8000U >= table->numLangTagRecords || + !table->langTags[entry->languageID - 0x8000U].stringLength ) + { + /* invalid entry; ignore it */ + continue; + } + } + + /* mark the string as not yet converted */ + entry->string = NULL; + + valid++; + entry++; + } + + /* reduce array size to the actually used elements */ + FT_MEM_QRENEW_ARRAY( names, + table->numNameRecords, + valid ); + table->names = names; + names = NULL; + table->numNameRecords = valid; + } + + FT_FRAME_EXIT(); + + /* everything went well, update face->num_names */ + face->num_names = (FT_UShort)table->numNameRecords; + + Exit: + FT_FREE( names ); + FT_FREE( langTags ); + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_free_name + * + * @Description: + * Frees the name records. + * + * @Input: + * face :: + * A handle to the target face object. + */ + FT_LOCAL_DEF( void ) + tt_face_free_name( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_NameTable table = &face->name_table; + + + if ( table->names ) + { + TT_Name entry = table->names; + TT_Name limit = entry + table->numNameRecords; + + + for ( ; entry < limit; entry++ ) + FT_FREE( entry->string ); + + FT_FREE( table->names ); + } + + if ( table->langTags ) + { + TT_LangTag entry = table->langTags; + TT_LangTag limit = entry + table->numLangTagRecords; + + + for ( ; entry < limit; entry++ ) + FT_FREE( entry->string ); + + FT_FREE( table->langTags ); + } + + table->numNameRecords = 0; + table->numLangTagRecords = 0; + table->format = 0; + table->storageOffset = 0; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_cmap + * + * @Description: + * Loads the cmap directory in a face object. The cmaps themselves + * are loaded on demand in the `ttcmap.c' module. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + + + error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); + if ( error ) + goto Exit; + + if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) + face->cmap_size = 0; + + Exit: + return error; + } + + + + /************************************************************************** + * + * @Function: + * tt_face_load_os2 + * + * @Description: + * Loads the OS2 table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_OS2* os2; + + static const FT_Frame_Field os2_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_OS2 + + FT_FRAME_START( 78 ), + FT_FRAME_USHORT( version ), + FT_FRAME_SHORT ( xAvgCharWidth ), + FT_FRAME_USHORT( usWeightClass ), + FT_FRAME_USHORT( usWidthClass ), + FT_FRAME_SHORT ( fsType ), + FT_FRAME_SHORT ( ySubscriptXSize ), + FT_FRAME_SHORT ( ySubscriptYSize ), + FT_FRAME_SHORT ( ySubscriptXOffset ), + FT_FRAME_SHORT ( ySubscriptYOffset ), + FT_FRAME_SHORT ( ySuperscriptXSize ), + FT_FRAME_SHORT ( ySuperscriptYSize ), + FT_FRAME_SHORT ( ySuperscriptXOffset ), + FT_FRAME_SHORT ( ySuperscriptYOffset ), + FT_FRAME_SHORT ( yStrikeoutSize ), + FT_FRAME_SHORT ( yStrikeoutPosition ), + FT_FRAME_SHORT ( sFamilyClass ), + FT_FRAME_BYTE ( panose[0] ), + FT_FRAME_BYTE ( panose[1] ), + FT_FRAME_BYTE ( panose[2] ), + FT_FRAME_BYTE ( panose[3] ), + FT_FRAME_BYTE ( panose[4] ), + FT_FRAME_BYTE ( panose[5] ), + FT_FRAME_BYTE ( panose[6] ), + FT_FRAME_BYTE ( panose[7] ), + FT_FRAME_BYTE ( panose[8] ), + FT_FRAME_BYTE ( panose[9] ), + FT_FRAME_ULONG ( ulUnicodeRange1 ), + FT_FRAME_ULONG ( ulUnicodeRange2 ), + FT_FRAME_ULONG ( ulUnicodeRange3 ), + FT_FRAME_ULONG ( ulUnicodeRange4 ), + FT_FRAME_BYTE ( achVendID[0] ), + FT_FRAME_BYTE ( achVendID[1] ), + FT_FRAME_BYTE ( achVendID[2] ), + FT_FRAME_BYTE ( achVendID[3] ), + + FT_FRAME_USHORT( fsSelection ), + FT_FRAME_USHORT( usFirstCharIndex ), + FT_FRAME_USHORT( usLastCharIndex ), + FT_FRAME_SHORT ( sTypoAscender ), + FT_FRAME_SHORT ( sTypoDescender ), + FT_FRAME_SHORT ( sTypoLineGap ), + FT_FRAME_USHORT( usWinAscent ), + FT_FRAME_USHORT( usWinDescent ), + FT_FRAME_END + }; + + /* `OS/2' version 1 and newer */ + static const FT_Frame_Field os2_fields_extra1[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_ULONG( ulCodePageRange1 ), + FT_FRAME_ULONG( ulCodePageRange2 ), + FT_FRAME_END + }; + + /* `OS/2' version 2 and newer */ + static const FT_Frame_Field os2_fields_extra2[] = + { + FT_FRAME_START( 10 ), + FT_FRAME_SHORT ( sxHeight ), + FT_FRAME_SHORT ( sCapHeight ), + FT_FRAME_USHORT( usDefaultChar ), + FT_FRAME_USHORT( usBreakChar ), + FT_FRAME_USHORT( usMaxContext ), + FT_FRAME_END + }; + + /* `OS/2' version 5 and newer */ + static const FT_Frame_Field os2_fields_extra5[] = + { + FT_FRAME_START( 4 ), + FT_FRAME_USHORT( usLowerOpticalPointSize ), + FT_FRAME_USHORT( usUpperOpticalPointSize ), + FT_FRAME_END + }; + + + /* We now support old Mac fonts where the OS/2 table doesn't */ + /* exist. Simply put, we set the `version' field to 0xFFFF */ + /* and test this value each time we need to access the table. */ + error = face->goto_table( face, TTAG_OS2, stream, 0 ); + if ( error ) + goto Exit; + + os2 = &face->os2; + + if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) + goto Exit; + + os2->ulCodePageRange1 = 0; + os2->ulCodePageRange2 = 0; + os2->sxHeight = 0; + os2->sCapHeight = 0; + os2->usDefaultChar = 0; + os2->usBreakChar = 0; + os2->usMaxContext = 0; + os2->usLowerOpticalPointSize = 0; + os2->usUpperOpticalPointSize = 0xFFFF; + + if ( os2->version >= 0x0001 ) + { + /* only version 1 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra1, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0002 ) + { + /* only version 2 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) + goto Exit; + + if ( os2->version >= 0x0005 ) + { + /* only version 5 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra5, os2 ) ) + goto Exit; + } + } + } + + FT_TRACE3(( "sTypoAscender: %4hd\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4hd\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4hu\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4hu\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2hx\n", os2->fsSelection )); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_postscript + * + * @Description: + * Loads the Postscript table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Postscript* post = &face->postscript; + + static const FT_Frame_Field post_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Postscript + + FT_FRAME_START( 32 ), + FT_FRAME_LONG ( FormatType ), + FT_FRAME_LONG ( italicAngle ), + FT_FRAME_SHORT( underlinePosition ), + FT_FRAME_SHORT( underlineThickness ), + FT_FRAME_ULONG( isFixedPitch ), + FT_FRAME_ULONG( minMemType42 ), + FT_FRAME_ULONG( maxMemType42 ), + FT_FRAME_ULONG( minMemType1 ), + FT_FRAME_ULONG( maxMemType1 ), + FT_FRAME_END + }; + + + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + return error; + + if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) + return error; + + if ( post->FormatType != 0x00030000L && + post->FormatType != 0x00025000L && + post->FormatType != 0x00020000L && + post->FormatType != 0x00010000L ) + return FT_THROW( Invalid_Post_Table_Format ); + + /* we don't load the glyph names, we do that in another */ + /* module (ttpost). */ + + FT_TRACE3(( "FormatType: 0x%lx\n", post->FormatType )); + FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch + ? " yes" : " no" )); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_pclt + * + * @Description: + * Loads the PCL 5 Table. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ) + { + static const FT_Frame_Field pclt_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_PCLT + + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_ULONG ( FontNumber ), + FT_FRAME_USHORT( Pitch ), + FT_FRAME_USHORT( xHeight ), + FT_FRAME_USHORT( Style ), + FT_FRAME_USHORT( TypeFamily ), + FT_FRAME_USHORT( CapHeight ), + FT_FRAME_USHORT( SymbolSet ), + FT_FRAME_BYTES ( TypeFace, 16 ), + FT_FRAME_BYTES ( CharacterComplement, 8 ), + FT_FRAME_BYTES ( FileName, 6 ), + FT_FRAME_CHAR ( StrokeWeight ), + FT_FRAME_CHAR ( WidthType ), + FT_FRAME_BYTE ( SerifStyle ), + FT_FRAME_BYTE ( Reserved ), + FT_FRAME_END + }; + + FT_Error error; + TT_PCLT* pclt = &face->pclt; + + + /* optional table */ + error = face->goto_table( face, TTAG_PCLT, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) + goto Exit; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_gasp + * + * @Description: + * Loads the `gasp' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UShort j, num_ranges; + TT_GaspRange gasp_ranges = NULL; + + + /* the gasp table is optional */ + error = face->goto_table( face, TTAG_gasp, stream, 0 ); + if ( error ) + goto Exit; + + if ( FT_FRAME_ENTER( 4L ) ) + goto Exit; + + face->gasp.version = FT_GET_USHORT(); + num_ranges = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + /* only support versions 0 and 1 of the table */ + if ( face->gasp.version >= 2 ) + { + face->gasp.numRanges = 0; + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE3(( "numRanges: %hu\n", num_ranges )); + + if ( FT_QNEW_ARRAY( gasp_ranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) + goto Exit; + + for ( j = 0; j < num_ranges; j++ ) + { + gasp_ranges[j].maxPPEM = FT_GET_USHORT(); + gasp_ranges[j].gaspFlag = FT_GET_USHORT(); + + FT_TRACE3(( "gaspRange %hu: rangeMaxPPEM %5hu, rangeGaspBehavior 0x%hx\n", + j, + gasp_ranges[j].maxPPEM, + gasp_ranges[j].gaspFlag )); + } + + face->gasp.gaspRanges = gasp_ranges; + gasp_ranges = NULL; + face->gasp.numRanges = num_ranges; + + FT_FRAME_EXIT(); + + Exit: + FT_FREE( gasp_ranges ); + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttload.h b/Dependencies/freetype/freetype/src/sfnt/ttload.h new file mode 100644 index 00000000..2b1d62d9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttload.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * + * ttload.h + * + * Load the basic TrueType tables, i.e., tables that can be either in + * TTF or OTF fonts (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTLOAD_H_ +#define TTLOAD_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ); + + FT_LOCAL( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + + + FT_LOCAL( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_name( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_LOCAL( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ); + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + +FT_END_HEADER + +#endif /* TTLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttmtx.c b/Dependencies/freetype/freetype/src/sfnt/ttmtx.c new file mode 100644 index 00000000..27884118 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttmtx.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * + * ttmtx.c + * + * Load the metrics tables common to TTF and OTF fonts (body). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif + +#include "ttmtx.h" + +#include "sferrors.h" + + + /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ + /* be identical except for the names of their fields, */ + /* which are different. */ + /* */ + /* This ensures that `tt_face_load_hmtx' is able to read */ + /* both the horizontal and vertical headers. */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttmtx + + + /************************************************************************** + * + * @Function: + * tt_face_load_hmtx + * + * @Description: + * Load the `hmtx' or `vmtx' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load `vmtx'. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_ULong tag, table_size; + FT_ULong* ptable_offset; + FT_ULong* ptable_size; + + + if ( vertical ) + { + tag = TTAG_vmtx; + ptable_offset = &face->vert_metrics_offset; + ptable_size = &face->vert_metrics_size; + } + else + { + tag = TTAG_hmtx; + ptable_offset = &face->horz_metrics_offset; + ptable_size = &face->horz_metrics_size; + } + + error = face->goto_table( face, tag, stream, &table_size ); + if ( error ) + goto Fail; + + *ptable_size = table_size; + *ptable_offset = FT_STREAM_POS(); + + Fail: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_hhea + * + * @Description: + * Load the `hhea' or 'vhea' table into a face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * The input stream. + * + * vertical :: + * A boolean flag. If set, load `vhea'. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + TT_HoriHeader* header; + + static const FT_Frame_Field metrics_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_HoriHeader + + FT_FRAME_START( 36 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_SHORT ( Ascender ), + FT_FRAME_SHORT ( Descender ), + FT_FRAME_SHORT ( Line_Gap ), + FT_FRAME_USHORT( advance_Width_Max ), + FT_FRAME_SHORT ( min_Left_Side_Bearing ), + FT_FRAME_SHORT ( min_Right_Side_Bearing ), + FT_FRAME_SHORT ( xMax_Extent ), + FT_FRAME_SHORT ( caret_Slope_Rise ), + FT_FRAME_SHORT ( caret_Slope_Run ), + FT_FRAME_SHORT ( caret_Offset ), + FT_FRAME_SHORT ( Reserved[0] ), + FT_FRAME_SHORT ( Reserved[1] ), + FT_FRAME_SHORT ( Reserved[2] ), + FT_FRAME_SHORT ( Reserved[3] ), + FT_FRAME_SHORT ( metric_Data_Format ), + FT_FRAME_USHORT( number_Of_HMetrics ), + FT_FRAME_END + }; + + + if ( vertical ) + { + void *v = &face->vertical; + + + error = face->goto_table( face, TTAG_vhea, stream, 0 ); + if ( error ) + goto Fail; + + header = (TT_HoriHeader*)v; + } + else + { + error = face->goto_table( face, TTAG_hhea, stream, 0 ); + if ( error ) + goto Fail; + + header = &face->horizontal; + } + + if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) + goto Fail; + + FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); + FT_TRACE3(( "Descender: %5d\n", header->Descender )); + FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); + + header->long_metrics = NULL; + header->short_metrics = NULL; + + Fail: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_face_get_metrics + * + * @Description: + * Return the horizontal or vertical metrics in font units for a + * given glyph. The values are the left side bearing (top side + * bearing for vertical metrics) and advance width (advance height + * for vertical metrics). + * + * @Input: + * face :: + * A pointer to the TrueType face structure. + * + * vertical :: + * If set to TRUE, get vertical metrics. + * + * gindex :: + * The glyph index. + * + * @Output: + * abearing :: + * The bearing, either left side or top side. + * + * aadvance :: + * The advance width or advance height, depending on + * the `vertical' flag. + */ + FT_LOCAL_DEF( void ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short *abearing, + FT_UShort *aadvance ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + TT_HoriHeader* header; + FT_ULong table_pos, table_size, table_end; + FT_UShort k; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Service_MetricsVariations var = + (FT_Service_MetricsVariations)face->tt_var; +#endif + + + if ( vertical ) + { + void* v = &face->vertical; + + + header = (TT_HoriHeader*)v; + table_pos = face->vert_metrics_offset; + table_size = face->vert_metrics_size; + } + else + { + header = &face->horizontal; + table_pos = face->horz_metrics_offset; + table_size = face->horz_metrics_size; + } + + table_end = table_pos + table_size; + + k = header->number_Of_HMetrics; + + if ( k > 0 ) + { + if ( gindex < (FT_UInt)k ) + { + table_pos += 4 * gindex; + if ( table_pos + 4 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) || + FT_READ_SHORT( *abearing ) ) + goto NoData; + } + else + { + table_pos += 4 * ( k - 1 ); + if ( table_pos + 2 > table_end ) + goto NoData; + + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) ) + goto NoData; + + table_pos += 4 + 2 * ( gindex - k ); + if ( table_pos + 2 > table_end ) + *abearing = 0; + else + { + if ( FT_STREAM_SEEK( table_pos ) ) + *abearing = 0; + else + (void)FT_READ_SHORT( *abearing ); + } + } + } + else + { + NoData: + *abearing = 0; + *aadvance = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( var && face->blend ) + { + FT_Face f = FT_FACE( face ); + FT_Int a = (FT_Int)*aadvance; + FT_Int b = (FT_Int)*abearing; + + + if ( vertical ) + { + if ( var->vadvance_adjust ) + var->vadvance_adjust( f, gindex, &a ); + if ( var->tsb_adjust ) + var->tsb_adjust( f, gindex, &b ); + } + else + { + if ( var->hadvance_adjust ) + var->hadvance_adjust( f, gindex, &a ); + if ( var->lsb_adjust ) + var->lsb_adjust( f, gindex, &b ); + } + + *aadvance = (FT_UShort)a; + *abearing = (FT_Short)b; + } +#endif + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttmtx.h b/Dependencies/freetype/freetype/src/sfnt/ttmtx.h new file mode 100644 index 00000000..34b3c0e1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttmtx.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * ttmtx.h + * + * Load the metrics tables common to TTF and OTF fonts (specification). + * + * Copyright (C) 2006-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTMTX_H_ +#define TTMTX_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + + + FT_LOCAL( void ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); + +FT_END_HEADER + +#endif /* TTMTX_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttpost.c b/Dependencies/freetype/freetype/src/sfnt/ttpost.c new file mode 100644 index 00000000..5698a62c --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttpost.c @@ -0,0 +1,484 @@ +/**************************************************************************** + * + * ttpost.c + * + * PostScript name table processing for TrueType and OpenType fonts + * (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * The post table is not completely loaded by the core engine. This + * file loads the missing PS glyph names and implements an API to access + * them. + * + */ + + +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + +#include "ttpost.h" + +#include "sferrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttpost + + + /* If this configuration macro is defined, we rely on the `psnames' */ + /* module to grab the glyph names. */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + + +#include + +#define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) + + +#else /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + /* Otherwise, we ignore the `psnames' module, and provide our own */ + /* table of Mac names. Thus, it is possible to build a version of */ + /* FreeType without the Type 1 driver & psnames module. */ + +#define MAC_NAME( x ) (FT_String*)tt_post_default_names[x] + + /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */ + + static const FT_String* const tt_post_default_names[258] = + { + /* 0 */ + ".notdef", ".null", "nonmarkingreturn", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + /* 10 */ + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + /* 20 */ + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + /* 30 */ + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + /* 40 */ + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + /* 50 */ + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + /* 60 */ + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + /* 70 */ + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + /* 80 */ + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + /* 90 */ + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + /* 100 */ + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + /* 110 */ + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + /* 120 */ + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + /* 130 */ + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + /* 140 */ + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + /* 150 */ + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + /* 160 */ + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + /* 170 */ + "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + /* 180 */ + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + /* 190 */ + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", + /* 200 */ + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + /* 210 */ + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + /* 220 */ + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + /* 230 */ + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + /* 240 */ + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + /* 250 */ + "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dcroat", + }; + + +#endif /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + + static FT_Error + load_format_20( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n; + FT_UShort num_names = 0; + + FT_UShort* glyph_indices = NULL; + FT_Byte** name_strings = NULL; + FT_Byte* q; + + + if ( (FT_ULong)num_glyphs * 2 > post_len ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* load the indices and note their maximum */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2 ) ) + goto Fail; + + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_UShort idx = FT_NEXT_USHORT( q ); + + + if ( idx > num_names ) + num_names = idx; + + glyph_indices[n] = idx; + } + + FT_FRAME_EXIT(); + + /* compute number of names stored in the table */ + num_names = num_names > 257 ? num_names - 257 : 0; + + /* now load the name strings */ + if ( num_names ) + { + FT_Byte* p; + FT_Byte* p_end; + + + post_len -= (FT_ULong)num_glyphs * 2; + + if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) + + post_len + 1 ) ) + goto Fail; + + p = (FT_Byte*)( name_strings + num_names ); + if ( FT_STREAM_READ( p, post_len ) ) + goto Fail; + + p_end = p + post_len; + + /* convert from Pascal- to C-strings and set pointers */ + for ( n = 0; p < p_end && n < num_names; n++ ) + { + FT_UInt len = *p; + + + /* names in the Adobe Glyph List are shorter than 40 characters */ + if ( len >= 40U ) + FT_TRACE4(( "load_format_20: unusual %u-char name found\n", len )); + + *p++ = 0; + name_strings[n] = p; + p += len; + } + *p_end = 0; + + /* deal with missing or insufficient string data */ + if ( n < num_names ) + { + FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n", + (FT_UShort)( num_names - n ) )); + + for ( ; n < num_names; n++ ) + name_strings[n] = p_end; + } + } + + /* all right, set table fields and exit successfully */ + names->num_glyphs = num_glyphs; + names->num_names = num_names; + names->glyph_indices = glyph_indices; + names->glyph_names = name_strings; + + return FT_Err_Ok; + + Fail: + FT_FREE( name_strings ); + FT_FREE( glyph_indices ); + + Exit: + return error; + } + + + static FT_Error + load_format_25( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) + { + FT_Memory memory = stream->memory; + FT_Error error; + + FT_UShort n; + FT_UShort* glyph_indices = NULL; + FT_Byte* q; + + + /* check the number of glyphs, including the theoretical limit */ + if ( num_glyphs > post_len || + num_glyphs > 258 + 128 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* load the indices and check their Mac range */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs ) ) + goto Fail; + + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int idx = n + FT_NEXT_CHAR( q ); + + + if ( idx < 0 || idx > 257 ) + idx = 0; + + glyph_indices[n] = (FT_UShort)idx; + } + + FT_FRAME_EXIT(); + + /* OK, set table fields and exit successfully */ + names->num_glyphs = num_glyphs; + names->glyph_indices = glyph_indices; + + return FT_Err_Ok; + + Fail: + FT_FREE( glyph_indices ); + + Exit: + return error; + } + + + static FT_Error + load_post_names( TT_Face face ) + { + FT_Error error = FT_Err_Ok; + FT_Stream stream = face->root.stream; + FT_Fixed format = face->postscript.FormatType; + FT_ULong post_len; + FT_UShort num_glyphs; + + + /* seek to the beginning of the PS names table */ + error = face->goto_table( face, TTAG_post, stream, &post_len ); + if ( error ) + goto Exit; + + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + if ( post_len < 34 || + FT_STREAM_SKIP( 32 ) || + FT_READ_USHORT( num_glyphs ) || + num_glyphs > face->max_profile.numGlyphs || + num_glyphs == 0 ) + goto Exit; + + /* now read postscript names data */ + if ( format == 0x00020000L ) + error = load_format_20( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); + else if ( format == 0x00025000L ) + error = load_format_25( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); + + Exit: + face->postscript_names.loaded = 1; /* even if failed */ + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_ps_names( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_Post_Names names = &face->postscript_names; + + + if ( names->num_glyphs ) + { + FT_FREE( names->glyph_indices ); + names->num_glyphs = 0; + } + + if ( names->num_names ) + { + FT_FREE( names->glyph_names ); + names->num_names = 0; + } + + names->loaded = 0; + } + + + /************************************************************************** + * + * @Function: + * tt_face_get_ps_name + * + * @Description: + * Get the PostScript glyph name of a glyph. + * + * @Input: + * face :: + * A handle to the parent face. + * + * idx :: + * The glyph index. + * + * @InOut: + * PSname :: + * The address of a string pointer. Undefined in case of + * error, otherwise it is a pointer to the glyph name. + * + * You must not modify the returned string! + * + * @Output: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ) + { + FT_Error error; + FT_Fixed format; + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + FT_Service_PsCMaps psnames; +#endif + + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + + if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) + return FT_THROW( Invalid_Glyph_Index ); + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES + psnames = (FT_Service_PsCMaps)face->psnames; + if ( !psnames ) + return FT_THROW( Unimplemented_Feature ); +#endif + + /* `.notdef' by default */ + *PSname = MAC_NAME( 0 ); + + format = face->postscript.FormatType; + + if ( format == 0x00020000L || + format == 0x00025000L ) + { + TT_Post_Names names = &face->postscript_names; + + + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } + + if ( idx < (FT_UInt)names->num_glyphs ) + { + FT_UShort name_index = names->glyph_indices[idx]; + + + if ( name_index < 258 ) + *PSname = MAC_NAME( name_index ); + else /* only for version 2.0 */ + *PSname = (FT_String*)names->glyph_names[name_index - 258]; + } + } + + /* version 1.0 is only valid with 258 glyphs */ + else if ( format == 0x00010000L && + face->max_profile.numGlyphs == 258 ) + *PSname = MAC_NAME( idx ); + + /* nothing to do for format == 0x00030000L */ + + End: + /* post format errors ignored */ + return FT_Err_Ok; + } + +#else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_post_dummy_; + +#endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttpost.h b/Dependencies/freetype/freetype/src/sfnt/ttpost.h new file mode 100644 index 00000000..150db6c3 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttpost.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * ttpost.h + * + * PostScript name table processing for TrueType and OpenType fonts + * (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTPOST_H_ +#define TTPOST_H_ + + +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + + FT_LOCAL( void ) + tt_face_free_ps_names( TT_Face face ); + + +FT_END_HEADER + +#endif /* TTPOST_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttsbit.c b/Dependencies/freetype/freetype/src/sfnt/ttsbit.c new file mode 100644 index 00000000..cb3a8abf --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttsbit.c @@ -0,0 +1,1685 @@ +/**************************************************************************** + * + * ttsbit.c + * + * TrueType and OpenType embedded bitmap support (body). + * + * Copyright (C) 2005-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Copyright 2013 by Google, Inc. + * Google Author(s): Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + +#include "ttsbit.h" + +#include "sferrors.h" + +#include "ttmtx.h" +#include "pngshim.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsbit + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_ULong table_start; + + + face->sbit_table = NULL; + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + face->sbit_num_strikes = 0; + + error = face->goto_table( face, TTAG_CBLC, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_CBLC; + else + { + error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_EBLC; + } + + if ( error ) + { + error = face->goto_table( face, TTAG_sbix, stream, &table_size ); + if ( !error ) + face->sbit_table_type = TT_SBIT_TABLE_TYPE_SBIX; + } + if ( error ) + goto Exit; + + if ( table_size < 8 ) + { + FT_ERROR(( "tt_face_load_sbit_strikes: table too short\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + table_start = FT_STREAM_POS(); + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + FT_Byte* p; + FT_Fixed version; + FT_ULong num_strikes; + FT_UInt count; + + + if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_table_size = table_size; + + p = face->sbit_table; + + version = FT_NEXT_LONG( p ); + num_strikes = FT_NEXT_ULONG( p ); + + /* there's at least one font (FZShuSong-Z01, version 3) */ + /* that uses the wrong byte order for the `version' field */ + if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL && + ( (FT_ULong)version & 0x0000FFFFUL ) != 0x00000200UL && + ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00030000UL && + ( (FT_ULong)version & 0x0000FFFFUL ) != 0x00000300UL ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + if ( num_strikes >= 0x10000UL ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 48UL * count > table_size ) + count = (FT_UInt)( ( table_size - 8 ) / 48 ); + + face->sbit_num_strikes = count; + } + break; + + case TT_SBIT_TABLE_TYPE_SBIX: + { + FT_UShort version; + FT_UShort flags; + FT_ULong num_strikes; + FT_UInt count; + + + if ( FT_FRAME_ENTER( 8 ) ) + goto Exit; + + version = FT_GET_USHORT(); + flags = FT_GET_USHORT(); + num_strikes = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + if ( version < 1 ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Bit 0 must always be `1'. */ + /* Bit 1 controls the overlay of bitmaps with outlines. */ + /* All other bits should be zero. */ + if ( !( flags == 1 || flags == 3 ) || + num_strikes >= 0x10000UL ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( flags == 3 ) + face->root.face_flags |= FT_FACE_FLAG_SBIX_OVERLAY; + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 4UL * count > table_size ) + count = (FT_UInt)( ( table_size - 8 ) / 4 ); + + if ( FT_STREAM_SEEK( FT_STREAM_POS() - 8 ) ) + goto Exit; + + face->sbit_table_size = 8 + count * 4; + if ( FT_FRAME_EXTRACT( face->sbit_table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_num_strikes = count; + } + break; + + default: + /* we ignore unknown table formats */ + error = FT_THROW( Unknown_File_Format ); + break; + } + + if ( !error ) + FT_TRACE3(( "tt_face_load_sbit_strikes: found %u strikes\n", + face->sbit_num_strikes )); + + face->ebdt_start = 0; + face->ebdt_size = 0; + + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) + { + /* the `sbix' table is self-contained; */ + /* it has no associated data table */ + face->ebdt_start = table_start; + face->ebdt_size = table_size; + } + else if ( face->sbit_table_type != TT_SBIT_TABLE_TYPE_NONE ) + { + FT_ULong ebdt_size; + + + error = face->goto_table( face, TTAG_CBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); + + if ( !error ) + { + face->ebdt_start = FT_STREAM_POS(); + face->ebdt_size = ebdt_size; + } + } + + if ( !face->ebdt_size ) + { + FT_TRACE2(( "tt_face_load_sbit_strikes:" + " no embedded bitmap data table found;\n" )); + FT_TRACE2(( " " + " resetting number of strikes to zero\n" )); + face->sbit_num_strikes = 0; + } + + return FT_Err_Ok; + + Exit: + if ( error ) + { + if ( face->sbit_table ) + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_sbit( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE; + face->sbit_num_strikes = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ) + { + return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ) + { + /* we have to test for the existence of `sbit_strike_map' */ + /* because the function gets also used at the very beginning */ + /* to construct `sbit_strike_map' itself */ + if ( face->sbit_strike_map ) + { + if ( strike_index >= (FT_ULong)face->root.num_fixed_sizes ) + return FT_THROW( Invalid_Argument ); + + /* map to real index */ + strike_index = face->sbit_strike_map[strike_index]; + } + else + { + if ( strike_index >= (FT_ULong)face->sbit_num_strikes ) + return FT_THROW( Invalid_Argument ); + } + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + FT_Byte* strike; + FT_Char max_before_bl; + FT_Char min_after_bl; + + + strike = face->sbit_table + 8 + strike_index * 48; + + metrics->x_ppem = (FT_UShort)strike[44]; + metrics->y_ppem = (FT_UShort)strike[45]; + + metrics->ascender = (FT_Char)strike[16] * 64; /* hori.ascender */ + metrics->descender = (FT_Char)strike[17] * 64; /* hori.descender */ + + /* Due to fuzzy wording in the EBLC documentation, we find both */ + /* positive and negative values for `descender'. Additionally, */ + /* many fonts have both `ascender' and `descender' set to zero */ + /* (which is definitely wrong). MS Windows simply ignores all */ + /* those values... For these reasons we apply some heuristics */ + /* to get a reasonable, non-zero value for the height. */ + + max_before_bl = (FT_Char)strike[24]; + min_after_bl = (FT_Char)strike[25]; + + if ( metrics->descender > 0 ) + { + /* compare sign of descender with `min_after_bl' */ + if ( min_after_bl < 0 ) + metrics->descender = -metrics->descender; + } + + else if ( metrics->descender == 0 ) + { + if ( metrics->ascender == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid ascender and descender\n" )); + FT_TRACE2(( " " + " values for strike %ld (%dppem, %dppem)\n", + strike_index, + metrics->x_ppem, metrics->y_ppem )); + + /* sanitize buggy ascender and descender values */ + if ( max_before_bl || min_after_bl ) + { + metrics->ascender = max_before_bl * 64; + metrics->descender = min_after_bl * 64; + } + else + { + metrics->ascender = metrics->y_ppem * 64; + metrics->descender = 0; + } + } + } + +#if 0 + else + ; /* if we have a negative descender, simply use it */ +#endif + + metrics->height = metrics->ascender - metrics->descender; + if ( metrics->height == 0 ) + { + FT_TRACE2(( "tt_face_load_strike_metrics:" + " sanitizing invalid height value\n" )); + FT_TRACE2(( " " + " for strike (%d, %d)\n", + metrics->x_ppem, metrics->y_ppem )); + metrics->height = metrics->y_ppem * 64; + metrics->descender = metrics->ascender - metrics->height; + } + + /* Is this correct? */ + metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */ + strike[18] + /* max_width */ + (FT_Char)strike[23] /* min_advance_SB */ + ) * 64; + + /* set the scale values (in 16.16 units) so advances */ + /* from the hmtx and vmtx table are scaled correctly */ + metrics->x_scale = FT_DivFix( metrics->x_ppem * 64, + face->header.Units_Per_EM ); + metrics->y_scale = FT_DivFix( metrics->y_ppem * 64, + face->header.Units_Per_EM ); + + return FT_Err_Ok; + } + + case TT_SBIT_TABLE_TYPE_SBIX: + { + FT_Stream stream = face->root.stream; + FT_UInt offset; + FT_UShort ppem, resolution; + TT_HoriHeader *hori; + FT_Fixed scale; + + FT_Error error; + FT_Byte* p; + + + p = face->sbit_table + 8 + 4 * strike_index; + offset = FT_NEXT_ULONG( p ); + + if ( offset + 4 > face->ebdt_size ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + offset ) || + FT_FRAME_ENTER( 4 ) ) + return error; + + ppem = FT_GET_USHORT(); + resolution = FT_GET_USHORT(); + + FT_UNUSED( resolution ); /* What to do with this? */ + + FT_FRAME_EXIT(); + + metrics->x_ppem = ppem; + metrics->y_ppem = ppem; + + scale = FT_DivFix( ppem * 64, face->header.Units_Per_EM ); + hori = &face->horizontal; + + metrics->ascender = FT_MulFix( hori->Ascender, scale ); + metrics->descender = FT_MulFix( hori->Descender, scale ); + metrics->height = + FT_MulFix( hori->Ascender - hori->Descender + hori->Line_Gap, + scale ); + metrics->max_advance = FT_MulFix( hori->advance_Width_Max, scale ); + + /* set the scale values (in 16.16 units) so advances */ + /* from the hmtx and vmtx table are scaled correctly */ + metrics->x_scale = scale; + metrics->y_scale = scale; + + return error; + } + + default: + return FT_THROW( Unknown_File_Format ); + } + } + + + typedef struct TT_SBitDecoderRec_ + { + TT_Face face; + FT_Stream stream; + FT_Bitmap* bitmap; + TT_SBit_Metrics metrics; + FT_Bool metrics_loaded; + FT_Bool bitmap_allocated; + FT_Byte bit_depth; + + FT_ULong ebdt_start; + FT_ULong ebdt_size; + + FT_ULong strike_index_array; + FT_ULong strike_index_count; + FT_Byte* eblc_base; + FT_Byte* eblc_limit; + + } TT_SBitDecoderRec, *TT_SBitDecoder; + + + static FT_Error + tt_sbit_decoder_init( TT_SBitDecoder decoder, + TT_Face face, + FT_ULong strike_index, + TT_SBit_MetricsRec* metrics ) + { + FT_Error error = FT_ERR( Table_Missing ); + FT_Stream stream = face->root.stream; + + + strike_index = face->sbit_strike_map[strike_index]; + + if ( !face->ebdt_size ) + goto Exit; + if ( FT_STREAM_SEEK( face->ebdt_start ) ) + goto Exit; + + decoder->face = face; + decoder->stream = stream; + decoder->bitmap = &face->root.glyph->bitmap; + decoder->metrics = metrics; + + decoder->metrics_loaded = 0; + decoder->bitmap_allocated = 0; + + decoder->ebdt_start = face->ebdt_start; + decoder->ebdt_size = face->ebdt_size; + + decoder->eblc_base = face->sbit_table; + decoder->eblc_limit = face->sbit_table + face->sbit_table_size; + + /* now find the strike corresponding to the index */ + { + FT_Byte* p; + + + if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + p = decoder->eblc_base + 8 + 48 * strike_index; + + decoder->strike_index_array = FT_NEXT_ULONG( p ); + p += 4; + decoder->strike_index_count = FT_NEXT_ULONG( p ); + p += 34; + decoder->bit_depth = *p; + + /* decoder->strike_index_array + */ + /* 8 * decoder->strike_index_count > face->sbit_table_size ? */ + if ( decoder->strike_index_array > face->sbit_table_size || + decoder->strike_index_count > + ( face->sbit_table_size - decoder->strike_index_array ) / 8 ) + error = FT_THROW( Invalid_File_Format ); + } + + Exit: + return error; + } + + + static void + tt_sbit_decoder_done( TT_SBitDecoder decoder ) + { + FT_UNUSED( decoder ); + } + + + static FT_Error + tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder, + FT_Bool metrics_only ) + { + FT_Error error = FT_Err_Ok; + FT_UInt width, height; + FT_Bitmap* map = decoder->bitmap; + FT_ULong size; + + + if ( !decoder->metrics_loaded ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + width = decoder->metrics->width; + height = decoder->metrics->height; + + map->width = width; + map->rows = height; + + switch ( decoder->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = (int)( ( map->width + 7 ) >> 3 ); + map->num_grays = 2; + break; + + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = (int)( ( map->width + 3 ) >> 2 ); + map->num_grays = 4; + break; + + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = (int)( ( map->width + 1 ) >> 1 ); + map->num_grays = 16; + break; + + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = (int)( map->width ); + map->num_grays = 256; + break; + + case 32: + map->pixel_mode = FT_PIXEL_MODE_BGRA; + map->pitch = (int)( map->width * 4 ); + map->num_grays = 256; + break; + + default: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + size = map->rows * (FT_ULong)map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + if ( metrics_only ) + goto Exit; /* only metrics are requested */ + + error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); + if ( error ) + goto Exit; + + decoder->bitmap_allocated = 1; + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, + FT_Byte* *pp, + FT_Byte* limit, + FT_Bool big ) + { + FT_Byte* p = *pp; + TT_SBit_Metrics metrics = decoder->metrics; + + + if ( p + 5 > limit ) + goto Fail; + + metrics->height = p[0]; + metrics->width = p[1]; + metrics->horiBearingX = (FT_Char)p[2]; + metrics->horiBearingY = (FT_Char)p[3]; + metrics->horiAdvance = p[4]; + + p += 5; + if ( big ) + { + if ( p + 3 > limit ) + goto Fail; + + metrics->vertBearingX = (FT_Char)p[0]; + metrics->vertBearingY = (FT_Char)p[1]; + metrics->vertAdvance = p[2]; + + p += 3; + } + else + { + /* avoid uninitialized data in case there is no vertical info -- */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + } + + decoder->metrics_loaded = 1; + *pp = p; + return FT_Err_Ok; + + Fail: + FT_TRACE1(( "tt_sbit_decoder_load_metrics: broken table\n" )); + return FT_THROW( Invalid_Argument ); + } + + + /* forward declaration */ + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ); + + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( + TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ); + + + static FT_Error + tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* line; + FT_Int pitch, width, height, line_bits, h; + FT_UInt bit_height, bit_width; + FT_Bitmap* bitmap; + + FT_UNUSED( recurse_count ); + + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + if ( !line ) + goto Exit; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + line_bits = width * decoder->bit_depth; + + if ( x_pos < 0 || (FT_UInt)( x_pos + width ) > bit_width || + y_pos < 0 || (FT_UInt)( y_pos + height ) > bit_height ) + { + FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned:" + " invalid bitmap dimensions\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( p + ( ( line_bits + 7 ) >> 3 ) * height > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + if ( x_pos == 0 ) /* the easy one */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w; + + + for ( w = line_bits; w >= 8; w -= 8 ) + { + pwrite[0] = (FT_Byte)( pwrite[0] | *p++ ); + pwrite += 1; + } + + if ( w > 0 ) + pwrite[0] = (FT_Byte)( pwrite[0] | ( *p++ & ( 0xFF00U >> w ) ) ); + } + } + else /* x_pos > 0 */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w; + FT_UInt wval = 0; + + + for ( w = line_bits; w >= 8; w -= 8 ) + { + wval = (FT_UInt)( wval | *p++ ); + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + pwrite += 1; + wval <<= 8; + } + + if ( w > 0 ) + wval = (FT_UInt)( wval | ( *p++ & ( 0xFF00U >> w ) ) ); + + /* all bits read and there are `x_pos + w' bits to be written */ + + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + + if ( x_pos + w > 8 ) + { + pwrite++; + wval <<= 8; + pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) ); + } + } + } + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_byte_aligned: loaded\n" )); + return error; + } + + + /* + * Load a bit-aligned bitmap (with pointer `p') into a line-aligned bitmap + * (with pointer `pwrite'). In the example below, the width is 3 pixel, + * and `x_pos' is 1 pixel. + * + * p p+1 + * | | | + * | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |... + * | | | + * +-------+ +-------+ +-------+ ... + * . . . + * . . . + * v . . + * +-------+ . . + * | | . + * | 7 6 5 4 3 2 1 0 | . + * | | . + * pwrite . . + * . . + * v . + * +-------+ . + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * pwrite+1 . + * . + * v + * +-------+ + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * pwrite+2 + * + */ + + static FT_Error + tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* line; + FT_Int pitch, width, height, line_bits, h, nbits; + FT_UInt bit_height, bit_width; + FT_Bitmap* bitmap; + FT_UShort rval; + + FT_UNUSED( recurse_count ); + + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + line_bits = width * decoder->bit_depth; + + if ( x_pos < 0 || (FT_UInt)( x_pos + width ) > bit_width || + y_pos < 0 || (FT_UInt)( y_pos + height ) > bit_height ) + { + FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned:" + " invalid bitmap dimensions\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( p + ( ( line_bits * height + 7 ) >> 3 ) > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !line_bits || !height ) + { + /* nothing to do */ + goto Exit; + } + + /* now do the blit */ + + /* adjust `line' to point to the first byte of the bitmap */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + /* the higher byte of `rval' is used as a buffer */ + rval = 0; + nbits = 0; + + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* pwrite = line; + FT_Int w = line_bits; + + + /* handle initial byte (in target bitmap) specially if necessary */ + if ( x_pos ) + { + w = ( line_bits < 8 - x_pos ) ? line_bits : 8 - x_pos; + + if ( h == height ) + { + rval = *p++; + nbits = x_pos; + } + else if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + nbits += 8 - w; + } + else + { + rval >>= 8; + nbits -= w; + } + + *pwrite++ |= ( ( rval >> nbits ) & 0xFF ) & + ( ~( 0xFFU << w ) << ( 8 - w - x_pos ) ); + rval <<= 8; + + w = line_bits - w; + } + + /* handle medial bytes */ + for ( ; w >= 8; w -= 8 ) + { + rval |= *p++; + *pwrite++ |= ( rval >> nbits ) & 0xFF; + + rval <<= 8; + } + + /* handle final byte if necessary */ + if ( w > 0 ) + { + if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits += 8 - w; + + rval <<= 8; + } + else + { + *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits -= w; + } + } + } + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_bit_aligned: loaded\n" )); + return error; + } + + + static FT_Error + tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_UInt num_components, nn; + + FT_Char horiBearingX = (FT_Char)decoder->metrics->horiBearingX; + FT_Char horiBearingY = (FT_Char)decoder->metrics->horiBearingY; + FT_Byte horiAdvance = (FT_Byte)decoder->metrics->horiAdvance; + FT_Char vertBearingX = (FT_Char)decoder->metrics->vertBearingX; + FT_Char vertBearingY = (FT_Char)decoder->metrics->vertBearingY; + FT_Byte vertAdvance = (FT_Byte)decoder->metrics->vertAdvance; + + + if ( p + 2 > limit ) + goto Fail; + + num_components = FT_NEXT_USHORT( p ); + if ( p + 4 * num_components > limit ) + { + FT_TRACE1(( "tt_sbit_decoder_load_compound: broken table\n" )); + goto Fail; + } + + FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d component%s\n", + num_components, + num_components == 1 ? "" : "s" )); + + for ( nn = 0; nn < num_components; nn++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + FT_Char dx = FT_NEXT_CHAR( p ); + FT_Char dy = FT_NEXT_CHAR( p ); + + + /* NB: a recursive call */ + error = tt_sbit_decoder_load_image( decoder, + gindex, + x_pos + dx, + y_pos + dy, + recurse_count + 1, + /* request full bitmap image */ + FALSE ); + if ( error ) + break; + } + + FT_TRACE3(( "tt_sbit_decoder_load_compound: done\n" )); + + decoder->metrics->horiBearingX = horiBearingX; + decoder->metrics->horiBearingY = horiBearingY; + decoder->metrics->horiAdvance = horiAdvance; + decoder->metrics->vertBearingX = vertBearingX; + decoder->metrics->vertBearingY = vertBearingY; + decoder->metrics->vertAdvance = vertAdvance; + decoder->metrics->width = (FT_Byte)decoder->bitmap->width; + decoder->metrics->height = (FT_Byte)decoder->bitmap->rows; + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + +#ifdef FT_CONFIG_OPTION_USE_PNG + + static FT_Error + tt_sbit_decoder_load_png( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong png_len; + + FT_UNUSED( recurse_count ); + + + if ( limit - p < 4 ) + { + FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + png_len = FT_NEXT_ULONG( p ); + if ( (FT_ULong)( limit - p ) < png_len ) + { + FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + error = Load_SBit_Png( decoder->face->root.glyph, + x_pos, + y_pos, + decoder->bit_depth, + decoder->metrics, + decoder->stream->memory, + p, + png_len, + FALSE, + FALSE ); + + Exit: + if ( !error ) + FT_TRACE3(( "tt_sbit_decoder_load_png: loaded\n" )); + return error; + } + +#endif /* FT_CONFIG_OPTION_USE_PNG */ + + + static FT_Error + tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, + FT_UInt glyph_format, + FT_ULong glyph_start, + FT_ULong glyph_size, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ) + { + FT_Error error; + FT_Stream stream = decoder->stream; + FT_Byte* p; + FT_Byte* p_limit; + FT_Byte* data; + + + /* seek into the EBDT table now */ + if ( !glyph_size || + glyph_start + glyph_size > decoder->ebdt_size ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || + FT_FRAME_EXTRACT( glyph_size, data ) ) + goto Exit; + + p = data; + p_limit = p + glyph_size; + + /* read the data, depending on the glyph format */ + switch ( glyph_format ) + { + case 1: + case 2: + case 8: + case 17: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); + break; + + case 6: + case 7: + case 9: + case 18: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); + break; + + default: + error = FT_Err_Ok; + } + + if ( error ) + goto Fail; + + { + TT_SBitDecoder_LoadFunc loader; + + + switch ( glyph_format ) + { + case 1: + case 6: + loader = tt_sbit_decoder_load_byte_aligned; + break; + + case 2: + case 7: + { + /* Don't trust `glyph_format'. For example, Apple's main Korean */ + /* system font, `AppleMyungJo.ttf' (version 7.0d2e6), uses glyph */ + /* format 7, but the data is format 6. We check whether we have */ + /* an excessive number of bytes in the image: If it is equal to */ + /* the value for a byte-aligned glyph, use the other loading */ + /* routine. */ + /* */ + /* Note that for some (width,height) combinations, where the */ + /* width is not a multiple of 8, the sizes for bit- and */ + /* byte-aligned data are equal, for example (7,7) or (15,6). We */ + /* then prefer what `glyph_format' specifies. */ + + FT_UInt width = decoder->metrics->width; + FT_UInt height = decoder->metrics->height; + + FT_UInt bit_size = ( width * height + 7 ) >> 3; + FT_UInt byte_size = height * ( ( width + 7 ) >> 3 ); + + + if ( bit_size < byte_size && + byte_size == (FT_UInt)( p_limit - p ) ) + loader = tt_sbit_decoder_load_byte_aligned; + else + loader = tt_sbit_decoder_load_bit_aligned; + } + break; + + case 5: + loader = tt_sbit_decoder_load_bit_aligned; + break; + + case 8: + if ( p + 1 > p_limit ) + goto Fail; + + p += 1; /* skip padding */ + FALL_THROUGH; + + case 9: + loader = tt_sbit_decoder_load_compound; + break; + + case 17: /* small metrics, PNG image data */ + case 18: /* big metrics, PNG image data */ + case 19: /* metrics in EBLC, PNG image data */ +#ifdef FT_CONFIG_OPTION_USE_PNG + loader = tt_sbit_decoder_load_png; + break; +#else + error = FT_THROW( Unimplemented_Feature ); + goto Fail; +#endif /* FT_CONFIG_OPTION_USE_PNG */ + + default: + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder, metrics_only ); + + if ( error ) + goto Fail; + } + + if ( metrics_only ) + goto Fail; /* this is not an error */ + + error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count ); + } + + Fail: + FT_FRAME_RELEASE( data ); + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos, + FT_UInt recurse_count, + FT_Bool metrics_only ) + { + FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; + FT_Byte* p_limit = decoder->eblc_limit; + FT_ULong num_ranges = decoder->strike_index_count; + FT_UInt start, end, index_format, image_format; + FT_ULong image_start = 0, image_end = 0, image_offset; + + + /* arbitrary recursion limit */ + if ( recurse_count > 100 ) + { + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " recursion depth exceeded\n" )); + goto Failure; + } + + + /* First, we find the correct strike range that applies to this */ + /* glyph index. */ + for ( ; num_ranges > 0; num_ranges-- ) + { + start = FT_NEXT_USHORT( p ); + end = FT_NEXT_USHORT( p ); + + if ( glyph_index >= start && glyph_index <= end ) + goto FoundRange; + + p += 4; /* ignore index offset */ + } + goto NoBitmap; + + FoundRange: + image_offset = FT_NEXT_ULONG( p ); + + /* overflow check */ + p = decoder->eblc_base + decoder->strike_index_array; + if ( image_offset > (FT_ULong)( p_limit - p ) ) + goto Failure; + + p += image_offset; + if ( p + 8 > p_limit ) + goto NoBitmap; + + /* now find the glyph's location and extend within the ebdt table */ + index_format = FT_NEXT_USHORT( p ); + image_format = FT_NEXT_USHORT( p ); + image_offset = FT_NEXT_ULONG ( p ); + + switch ( index_format ) + { + case 1: /* 4-byte offsets relative to `image_offset' */ + p += 4 * ( glyph_index - start ); + if ( p + 8 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_ULONG( p ); + image_end = FT_NEXT_ULONG( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + break; + + case 2: /* big metrics, constant image size */ + { + FT_ULong image_size; + + + if ( p + 12 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + image_start = image_size * ( glyph_index - start ); + image_end = image_start + image_size; + } + break; + + case 3: /* 2-byte offsets relative to 'image_offset' */ + p += 2 * ( glyph_index - start ); + if ( p + 4 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_USHORT( p ); + image_end = FT_NEXT_USHORT( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + break; + + case 4: /* sparse glyph array with (glyph,offset) pairs */ + { + FT_ULong mm, num_glyphs; + + + if ( p + 4 > p_limit ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check for p + ( num_glyphs + 1 ) * 4 */ + if ( p + 4 > p_limit || + num_glyphs > (FT_ULong)( ( ( p_limit - p ) >> 2 ) - 1 ) ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + { + image_start = FT_NEXT_USHORT( p ); + p += 2; + image_end = FT_PEEK_USHORT( p ); + break; + } + p += 2; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + } + break; + + case 5: /* constant metrics with sparse glyph codes */ + case 19: + { + FT_ULong image_size, mm, num_glyphs; + + + if ( p + 16 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + + /* overflow check for p + 2 * num_glyphs */ + if ( num_glyphs > (FT_ULong)( ( p_limit - p ) >> 1 ) ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + break; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + + image_start = image_size * mm; + image_end = image_start + image_size; + } + break; + + default: + goto NoBitmap; + } + + if ( image_start > image_end ) + goto NoBitmap; + + image_end -= image_start; + image_start = image_offset + image_start; + + FT_TRACE3(( "tt_sbit_decoder_load_image:" + " found sbit (format %d) for glyph index %d\n", + image_format, glyph_index )); + + return tt_sbit_decoder_load_bitmap( decoder, + image_format, + image_start, + image_end, + x_pos, + y_pos, + recurse_count, + metrics_only ); + + Failure: + return FT_THROW( Invalid_Table ); + + NoBitmap: + if ( recurse_count ) + { + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " missing subglyph sbit with glyph index %d\n", + glyph_index )); + return FT_THROW( Invalid_Composite ); + } + + FT_TRACE4(( "tt_sbit_decoder_load_image:" + " no sbit found for glyph index %d\n", glyph_index )); + return FT_THROW( Missing_Bitmap ); + } + + + static FT_Error + tt_face_load_sbix_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics, + FT_Bool metrics_only ) + { + FT_UInt strike_offset, glyph_start, glyph_end; + FT_Int originOffsetX, originOffsetY; + FT_Tag graphicType; + FT_Int recurse_depth = 0; + + FT_Error error; + FT_Byte* p; + + FT_UNUSED( map ); +#ifndef FT_CONFIG_OPTION_USE_PNG + FT_UNUSED( metrics_only ); +#endif + + + strike_index = face->sbit_strike_map[strike_index]; + + metrics->width = 0; + metrics->height = 0; + + p = face->sbit_table + 8 + 4 * strike_index; + strike_offset = FT_NEXT_ULONG( p ); + + retry: + if ( glyph_index > (FT_UInt)face->root.num_glyphs ) + return FT_THROW( Invalid_Argument ); + + if ( strike_offset >= face->ebdt_size || + face->ebdt_size - strike_offset < 4 + glyph_index * 4 + 8 ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + + strike_offset + 4 + + glyph_index * 4 ) || + FT_FRAME_ENTER( 8 ) ) + return error; + + glyph_start = FT_GET_ULONG(); + glyph_end = FT_GET_ULONG(); + + FT_FRAME_EXIT(); + + if ( glyph_start == glyph_end ) + return FT_THROW( Missing_Bitmap ); + if ( glyph_start > glyph_end || + glyph_end - glyph_start < 8 || + face->ebdt_size - strike_offset < glyph_end ) + return FT_THROW( Invalid_File_Format ); + + if ( FT_STREAM_SEEK( face->ebdt_start + strike_offset + glyph_start ) || + FT_FRAME_ENTER( glyph_end - glyph_start ) ) + return error; + + originOffsetX = FT_GET_SHORT(); + originOffsetY = FT_GET_SHORT(); + + graphicType = FT_GET_TAG4(); + + switch ( graphicType ) + { + case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ): + if ( recurse_depth < 4 ) + { + glyph_index = FT_GET_USHORT(); + FT_FRAME_EXIT(); + recurse_depth++; + goto retry; + } + error = FT_THROW( Invalid_File_Format ); + break; + + case FT_MAKE_TAG( 'p', 'n', 'g', ' ' ): +#ifdef FT_CONFIG_OPTION_USE_PNG + error = Load_SBit_Png( face->root.glyph, + 0, + 0, + 32, + metrics, + stream->memory, + stream->cursor, + glyph_end - glyph_start - 8, + TRUE, + metrics_only ); +#else + error = FT_THROW( Unimplemented_Feature ); +#endif + break; + + case FT_MAKE_TAG( 'j', 'p', 'g', ' ' ): + case FT_MAKE_TAG( 't', 'i', 'f', 'f' ): + case FT_MAKE_TAG( 'r', 'g', 'b', 'l' ): /* used on iOS 7.1 */ + error = FT_THROW( Unknown_File_Format ); + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + FT_FRAME_EXIT(); + + if ( !error ) + { + FT_Short abearing; /* not used here */ + FT_UShort aadvance; + + + tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); + + metrics->horiBearingX = (FT_Short)originOffsetX; + metrics->vertBearingX = (FT_Short)originOffsetX; + + metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); + metrics->vertBearingY = (FT_Short)originOffsetY; + + metrics->horiAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); + + if ( face->vertical_info ) + tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); + else if ( face->os2.version != 0xFFFFU ) + aadvance = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + + metrics->vertAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); + } + + return error; + } + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + FT_Error error = FT_Err_Ok; + + + switch ( (FT_UInt)face->sbit_table_type ) + { + case TT_SBIT_TABLE_TYPE_EBLC: + case TT_SBIT_TABLE_TYPE_CBLC: + { + TT_SBitDecoderRec decoder[1]; + + + error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); + if ( !error ) + { + error = tt_sbit_decoder_load_image( + decoder, + glyph_index, + 0, + 0, + 0, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + tt_sbit_decoder_done( decoder ); + } + } + break; + + case TT_SBIT_TABLE_TYPE_SBIX: + error = tt_face_load_sbix_image( + face, + strike_index, + glyph_index, + stream, + map, + metrics, + ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); + break; + + default: + error = FT_THROW( Unknown_File_Format ); + break; + } + + /* Flatten color bitmaps if color was not requested. */ + if ( !error && + !( load_flags & FT_LOAD_COLOR ) && + !( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) && + map->pixel_mode == FT_PIXEL_MODE_BGRA ) + { + FT_Bitmap new_map; + FT_Library library = face->root.glyph->library; + + + FT_Bitmap_Init( &new_map ); + + /* Convert to 8bit grayscale. */ + error = FT_Bitmap_Convert( library, map, &new_map, 1 ); + if ( error ) + FT_Bitmap_Done( library, &new_map ); + else + { + map->pixel_mode = new_map.pixel_mode; + map->pitch = new_map.pitch; + map->num_grays = new_map.num_grays; + + ft_glyphslot_set_bitmap( face->root.glyph, new_map.buffer ); + face->root.glyph->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + } + + return error; + } + +#else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_sbit_dummy_; + +#endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttsbit.h b/Dependencies/freetype/freetype/src/sfnt/ttsbit.h new file mode 100644 index 00000000..96f80a58 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttsbit.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * ttsbit.h + * + * TrueType and OpenType embedded bitmap support (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTSBIT_H_ +#define TTSBIT_H_ + + +#include "ttload.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_sbit( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_sbit( TT_Face face ); + + + FT_LOCAL( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + + FT_LOCAL( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ); + + +FT_END_HEADER + +#endif /* TTSBIT_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttsvg.c b/Dependencies/freetype/freetype/src/sfnt/ttsvg.c new file mode 100644 index 00000000..298afd8b --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttsvg.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * ttsvg.c + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * 'SVG' table specification: + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/svg + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_SVG + +#include "ttsvg.h" + + + /* NOTE: These table sizes are given by the specification. */ +#define SVG_TABLE_HEADER_SIZE (10U) +#define SVG_DOCUMENT_RECORD_SIZE (12U) +#define SVG_DOCUMENT_LIST_MINIMUM_SIZE (2U + SVG_DOCUMENT_RECORD_SIZE) +#define SVG_MINIMUM_SIZE (SVG_TABLE_HEADER_SIZE + \ + SVG_DOCUMENT_LIST_MINIMUM_SIZE) + + + typedef struct Svg_ + { + FT_UShort version; /* table version (starting at 0) */ + FT_UShort num_entries; /* number of SVG document records */ + + FT_Byte* svg_doc_list; /* pointer to the start of SVG Document List */ + + void* table; /* memory that backs up SVG */ + FT_ULong table_size; + + } Svg; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsvg + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_ULong table_size; + FT_Byte* table = NULL; + FT_Byte* p = NULL; + Svg* svg = NULL; + FT_ULong offsetToSVGDocumentList; + + + error = face->goto_table( face, TTAG_SVG, stream, &table_size ); + if ( error ) + goto NoSVG; + + if ( table_size < SVG_MINIMUM_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoSVG; + + /* Allocate memory for the SVG object */ + if ( FT_NEW( svg ) ) + goto NoSVG; + + p = table; + svg->version = FT_NEXT_USHORT( p ); + offsetToSVGDocumentList = FT_NEXT_ULONG( p ); + + if ( offsetToSVGDocumentList < SVG_TABLE_HEADER_SIZE || + offsetToSVGDocumentList > table_size - + SVG_DOCUMENT_LIST_MINIMUM_SIZE ) + goto InvalidTable; + + svg->svg_doc_list = (FT_Byte*)( table + offsetToSVGDocumentList ); + + p = svg->svg_doc_list; + svg->num_entries = FT_NEXT_USHORT( p ); + + FT_TRACE3(( "version: %d\n", svg->version )); + FT_TRACE3(( "number of entries: %d\n", svg->num_entries )); + + if ( offsetToSVGDocumentList + 2U + + svg->num_entries * SVG_DOCUMENT_RECORD_SIZE > table_size ) + goto InvalidTable; + + svg->table = table; + svg->table_size = table_size; + + face->svg = svg; + face->root.face_flags |= FT_FACE_FLAG_SVG; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoSVG: + FT_FRAME_RELEASE( table ); + FT_FREE( svg ); + face->svg = NULL; + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_svg( TT_Face face ) + { + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + Svg* svg = (Svg*)face->svg; + + + if ( svg ) + { + FT_FRAME_RELEASE( svg->table ); + FT_FREE( svg ); + } + } + + + typedef struct Svg_doc_ + { + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_ULong offset; + FT_ULong length; + + } Svg_doc; + + + static Svg_doc + extract_svg_doc( FT_Byte* stream ) + { + Svg_doc doc; + + + doc.start_glyph_id = FT_NEXT_USHORT( stream ); + doc.end_glyph_id = FT_NEXT_USHORT( stream ); + + doc.offset = FT_NEXT_ULONG( stream ); + doc.length = FT_NEXT_ULONG( stream ); + + return doc; + } + + + static FT_Int + compare_svg_doc( Svg_doc doc, + FT_UInt glyph_index ) + { + if ( glyph_index < doc.start_glyph_id ) + return -1; + else if ( glyph_index > doc.end_glyph_id ) + return 1; + else + return 0; + } + + + static FT_Error + find_doc( FT_Byte* document_records, + FT_UShort num_entries, + FT_UInt glyph_index, + FT_ULong *doc_offset, + FT_ULong *doc_length, + FT_UShort *start_glyph, + FT_UShort *end_glyph ) + { + FT_Error error; + + Svg_doc start_doc; + Svg_doc mid_doc = { 0, 0, 0, 0 }; /* pacify compiler */ + Svg_doc end_doc; + + FT_Bool found = FALSE; + FT_UInt i = 0; + + FT_UInt start_index = 0; + FT_UInt end_index = num_entries - 1; + FT_Int comp_res; + + + /* search algorithm */ + if ( num_entries == 0 ) + { + error = FT_THROW( Invalid_Table ); + return error; + } + + start_doc = extract_svg_doc( document_records + start_index * 12 ); + end_doc = extract_svg_doc( document_records + end_index * 12 ); + + if ( ( compare_svg_doc( start_doc, glyph_index ) == -1 ) || + ( compare_svg_doc( end_doc, glyph_index ) == 1 ) ) + { + error = FT_THROW( Invalid_Glyph_Index ); + return error; + } + + while ( start_index <= end_index ) + { + i = ( start_index + end_index ) / 2; + mid_doc = extract_svg_doc( document_records + i * 12 ); + comp_res = compare_svg_doc( mid_doc, glyph_index ); + + if ( comp_res == 1 ) + { + start_index = i + 1; + start_doc = extract_svg_doc( document_records + start_index * 4 ); + } + else if ( comp_res == -1 ) + { + end_index = i - 1; + end_doc = extract_svg_doc( document_records + end_index * 4 ); + } + else + { + found = TRUE; + break; + } + } + /* search algorithm end */ + + if ( found != TRUE ) + { + FT_TRACE5(( "SVG glyph not found\n" )); + error = FT_THROW( Invalid_Glyph_Index ); + } + else + { + *doc_offset = mid_doc.offset; + *doc_length = mid_doc.length; + + *start_glyph = mid_doc.start_glyph_id; + *end_glyph = mid_doc.end_glyph_id; + + error = FT_Err_Ok; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ) + { + FT_Error error = FT_Err_Ok; + TT_Face face = (TT_Face)glyph->face; + FT_Memory memory = face->root.memory; + Svg* svg = (Svg*)face->svg; + + FT_Byte* doc_list; + FT_ULong doc_limit; + + FT_Byte* doc; + FT_ULong doc_offset; + FT_ULong doc_length; + FT_UShort doc_start_glyph_id; + FT_UShort doc_end_glyph_id; + + FT_SVG_Document svg_document = (FT_SVG_Document)glyph->other; + + + FT_ASSERT( !( svg == NULL ) ); + + doc_list = svg->svg_doc_list; + + error = find_doc( doc_list + 2, svg->num_entries, glyph_index, + &doc_offset, &doc_length, + &doc_start_glyph_id, &doc_end_glyph_id ); + if ( error != FT_Err_Ok ) + goto Exit; + + doc_limit = svg->table_size - + (FT_ULong)( doc_list - (FT_Byte*)svg->table ); + if ( doc_offset > doc_limit || + doc_length > doc_limit - doc_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + doc = doc_list + doc_offset; + + if ( doc_length > 6 && + doc[0] == 0x1F && + doc[1] == 0x8B && + doc[2] == 0x08 ) + { +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_ULong uncomp_size; + FT_Byte* uncomp_buffer = NULL; + + + /* + * Get the size of the original document. This helps in allotting the + * buffer to accommodate the uncompressed version. The last 4 bytes + * of the compressed document are equal to the original size modulo + * 2^32. Since the size of SVG documents is less than 2^32 bytes we + * can use this accurately. The four bytes are stored in + * little-endian format. + */ + FT_TRACE4(( "SVG document is GZIP compressed\n" )); + uncomp_size = (FT_ULong)doc[doc_length - 1] << 24 | + (FT_ULong)doc[doc_length - 2] << 16 | + (FT_ULong)doc[doc_length - 3] << 8 | + (FT_ULong)doc[doc_length - 4]; + + if ( FT_QALLOC( uncomp_buffer, uncomp_size ) ) + goto Exit; + + error = FT_Gzip_Uncompress( memory, + uncomp_buffer, + &uncomp_size, + doc, + doc_length ); + if ( error ) + { + FT_FREE( uncomp_buffer ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + glyph->internal->flags |= FT_GLYPH_OWN_GZIP_SVG; + + doc = uncomp_buffer; + doc_length = uncomp_size; + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + } + + svg_document->svg_document = doc; + svg_document->svg_document_length = doc_length; + + svg_document->metrics = glyph->face->size->metrics; + svg_document->units_per_EM = glyph->face->units_per_EM; + + svg_document->start_glyph_id = doc_start_glyph_id; + svg_document->end_glyph_id = doc_end_glyph_id; + + svg_document->transform.xx = 0x10000; + svg_document->transform.xy = 0; + svg_document->transform.yx = 0; + svg_document->transform.yy = 0x10000; + + svg_document->delta.x = 0; + svg_document->delta.y = 0; + + FT_TRACE5(( "start_glyph_id: %d\n", doc_start_glyph_id )); + FT_TRACE5(( "end_glyph_id: %d\n", doc_end_glyph_id )); + FT_TRACE5(( "svg_document:\n" )); + FT_TRACE5(( " %.*s\n", (FT_UInt)doc_length, doc )); + + glyph->other = svg_document; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_SVG */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_svg_dummy_; + +#endif /* !FT_CONFIG_OPTION_SVG */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/ttsvg.h b/Dependencies/freetype/freetype/src/sfnt/ttsvg.h new file mode 100644 index 00000000..20f9e47c --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/ttsvg.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * ttsvg.h + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef TTSVG_H_ +#define TTSVG_H_ + +#include +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_svg( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + +FT_END_HEADER + +#endif /* TTSVG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/woff2tags.c b/Dependencies/freetype/freetype/src/sfnt/woff2tags.c new file mode 100644 index 00000000..532ccfa1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/woff2tags.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * + * woff2tags.c + * + * WOFF2 Font table tags (base). + * + * Copyright (C) 2019-2024 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include "woff2tags.h" + + /* + * Return tag from index in the order given in WOFF2 specification. + * + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + * + * for details. + */ + FT_LOCAL_DEF( FT_Tag ) + woff2_known_tags( FT_Byte index ) + { + static const FT_Tag known_tags[63] = + { + FT_MAKE_TAG('c', 'm', 'a', 'p'), /* 0 */ + FT_MAKE_TAG('h', 'e', 'a', 'd'), /* 1 */ + FT_MAKE_TAG('h', 'h', 'e', 'a'), /* 2 */ + FT_MAKE_TAG('h', 'm', 't', 'x'), /* 3 */ + FT_MAKE_TAG('m', 'a', 'x', 'p'), /* 4 */ + FT_MAKE_TAG('n', 'a', 'm', 'e'), /* 5 */ + FT_MAKE_TAG('O', 'S', '/', '2'), /* 6 */ + FT_MAKE_TAG('p', 'o', 's', 't'), /* 7 */ + FT_MAKE_TAG('c', 'v', 't', ' '), /* 8 */ + FT_MAKE_TAG('f', 'p', 'g', 'm'), /* 9 */ + FT_MAKE_TAG('g', 'l', 'y', 'f'), /* 10 */ + FT_MAKE_TAG('l', 'o', 'c', 'a'), /* 11 */ + FT_MAKE_TAG('p', 'r', 'e', 'p'), /* 12 */ + FT_MAKE_TAG('C', 'F', 'F', ' '), /* 13 */ + FT_MAKE_TAG('V', 'O', 'R', 'G'), /* 14 */ + FT_MAKE_TAG('E', 'B', 'D', 'T'), /* 15 */ + FT_MAKE_TAG('E', 'B', 'L', 'C'), /* 16 */ + FT_MAKE_TAG('g', 'a', 's', 'p'), /* 17 */ + FT_MAKE_TAG('h', 'd', 'm', 'x'), /* 18 */ + FT_MAKE_TAG('k', 'e', 'r', 'n'), /* 19 */ + FT_MAKE_TAG('L', 'T', 'S', 'H'), /* 20 */ + FT_MAKE_TAG('P', 'C', 'L', 'T'), /* 21 */ + FT_MAKE_TAG('V', 'D', 'M', 'X'), /* 22 */ + FT_MAKE_TAG('v', 'h', 'e', 'a'), /* 23 */ + FT_MAKE_TAG('v', 'm', 't', 'x'), /* 24 */ + FT_MAKE_TAG('B', 'A', 'S', 'E'), /* 25 */ + FT_MAKE_TAG('G', 'D', 'E', 'F'), /* 26 */ + FT_MAKE_TAG('G', 'P', 'O', 'S'), /* 27 */ + FT_MAKE_TAG('G', 'S', 'U', 'B'), /* 28 */ + FT_MAKE_TAG('E', 'B', 'S', 'C'), /* 29 */ + FT_MAKE_TAG('J', 'S', 'T', 'F'), /* 30 */ + FT_MAKE_TAG('M', 'A', 'T', 'H'), /* 31 */ + FT_MAKE_TAG('C', 'B', 'D', 'T'), /* 32 */ + FT_MAKE_TAG('C', 'B', 'L', 'C'), /* 33 */ + FT_MAKE_TAG('C', 'O', 'L', 'R'), /* 34 */ + FT_MAKE_TAG('C', 'P', 'A', 'L'), /* 35 */ + FT_MAKE_TAG('S', 'V', 'G', ' '), /* 36 */ + FT_MAKE_TAG('s', 'b', 'i', 'x'), /* 37 */ + FT_MAKE_TAG('a', 'c', 'n', 't'), /* 38 */ + FT_MAKE_TAG('a', 'v', 'a', 'r'), /* 39 */ + FT_MAKE_TAG('b', 'd', 'a', 't'), /* 40 */ + FT_MAKE_TAG('b', 'l', 'o', 'c'), /* 41 */ + FT_MAKE_TAG('b', 's', 'l', 'n'), /* 42 */ + FT_MAKE_TAG('c', 'v', 'a', 'r'), /* 43 */ + FT_MAKE_TAG('f', 'd', 's', 'c'), /* 44 */ + FT_MAKE_TAG('f', 'e', 'a', 't'), /* 45 */ + FT_MAKE_TAG('f', 'm', 't', 'x'), /* 46 */ + FT_MAKE_TAG('f', 'v', 'a', 'r'), /* 47 */ + FT_MAKE_TAG('g', 'v', 'a', 'r'), /* 48 */ + FT_MAKE_TAG('h', 's', 't', 'y'), /* 49 */ + FT_MAKE_TAG('j', 'u', 's', 't'), /* 50 */ + FT_MAKE_TAG('l', 'c', 'a', 'r'), /* 51 */ + FT_MAKE_TAG('m', 'o', 'r', 't'), /* 52 */ + FT_MAKE_TAG('m', 'o', 'r', 'x'), /* 53 */ + FT_MAKE_TAG('o', 'p', 'b', 'd'), /* 54 */ + FT_MAKE_TAG('p', 'r', 'o', 'p'), /* 55 */ + FT_MAKE_TAG('t', 'r', 'a', 'k'), /* 56 */ + FT_MAKE_TAG('Z', 'a', 'p', 'f'), /* 57 */ + FT_MAKE_TAG('S', 'i', 'l', 'f'), /* 58 */ + FT_MAKE_TAG('G', 'l', 'a', 't'), /* 59 */ + FT_MAKE_TAG('G', 'l', 'o', 'c'), /* 60 */ + FT_MAKE_TAG('F', 'e', 'a', 't'), /* 61 */ + FT_MAKE_TAG('S', 'i', 'l', 'l'), /* 62 */ + }; + + + if ( index > 62 ) + return 0; + + return known_tags[index]; + } + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int woff2tags_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/sfnt/woff2tags.h b/Dependencies/freetype/freetype/src/sfnt/woff2tags.h new file mode 100644 index 00000000..d03b4b41 --- /dev/null +++ b/Dependencies/freetype/freetype/src/sfnt/woff2tags.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * woff2tags.h + * + * WOFF2 Font table tags (specification). + * + * Copyright (C) 2019-2024 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WOFF2TAGS_H +#define WOFF2TAGS_H + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + FT_LOCAL( FT_Tag ) + woff2_known_tags( FT_Byte index ); + +#endif + +FT_END_HEADER + +#endif /* WOFF2TAGS_H */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/smooth/ftgrays.c b/Dependencies/freetype/freetype/src/smooth/ftgrays.c new file mode 100644 index 00000000..b7c0632a --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/ftgrays.c @@ -0,0 +1,2149 @@ +/**************************************************************************** + * + * ftgrays.c + * + * A new `perfect' anti-aliasing renderer (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /************************************************************************** + * + * This file can be compiled without the rest of the FreeType engine, by + * defining the STANDALONE_ macro when compiling it. You also need to + * put the files `ftgrays.h' and `ftimage.h' into the current + * compilation directory. Typically, you could do something like + * + * - copy `src/smooth/ftgrays.c' (this file) to your current directory + * + * - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the + * same directory + * + * - compile `ftgrays' with the STANDALONE_ macro defined, as in + * + * cc -c -DSTANDALONE_ ftgrays.c + * + * The renderer can be initialized with a call to + * `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated + * with a call to `ft_gray_raster.raster_render'. + * + * See the comments and documentation in the file `ftimage.h' for more + * details on how the raster works. + * + */ + + /************************************************************************** + * + * This is a new anti-aliasing scan-converter for FreeType 2. The + * algorithm used here is _very_ different from the one in the standard + * `ftraster' module. Actually, `ftgrays' computes the _exact_ + * coverage of the outline on each pixel cell by straight segments. + * + * It is based on ideas that I initially found in Raph Levien's + * excellent LibArt graphics library (see https://www.levien.com/libart + * for more information, though the web pages do not tell anything + * about the renderer; you'll have to dive into the source code to + * understand how it works). + * + * Note, however, that this is a _very_ different implementation + * compared to Raph's. Coverage information is stored in a very + * different way, and I don't use sorted vector paths. Also, it doesn't + * use floating point values. + * + * Bézier segments are flattened by splitting them until their deviation + * from straight line becomes much smaller than a pixel. Therefore, the + * pixel coverage by a Bézier curve is calculated approximately. To + * estimate the deviation, we use the distance from the control point + * to the conic chord centre or the cubic chord trisection. These + * distances vanish fast after each split. In the conic case, they vanish + * predictably and the number of necessary splits can be calculated. + * + * This renderer has the following advantages: + * + * - It doesn't need an intermediate bitmap. Instead, one can supply a + * callback function that will be called by the renderer to draw gray + * spans on any target surface. You can thus do direct composition on + * any kind of bitmap, provided that you give the renderer the right + * callback. + * + * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on + * each pixel cell by straight segments. + * + * - It performs a single pass on the outline (the `standard' FT2 + * renderer makes two passes). + * + * - It can easily be modified to render to _any_ number of gray levels + * cheaply. + * + * - For small (< 80) pixel sizes, it is faster than the standard + * renderer. + * + */ + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT smooth + + +#ifdef STANDALONE_ + + + /* The size in bytes of the render pool used by the scan-line converter */ + /* to do all of its work. */ +#define FT_RENDER_POOL_SIZE 16384L + + + /* Auxiliary macros for token concatenation. */ +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) + +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + + + /* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +#define FT_HYPOT( x, y ) \ + ( x = FT_ABS( x ), \ + y = FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + + + /* define this to dump debugging information */ +/* #define FT_DEBUG_LEVEL_TRACE */ + + +#ifdef FT_DEBUG_LEVEL_TRACE +#include +#include +#endif + +#include +#include +#include +#include +#define FT_CHAR_BIT CHAR_BIT +#define FT_UINT_MAX UINT_MAX +#define FT_INT_MAX INT_MAX +#define FT_ULONG_MAX ULONG_MAX + +#define ADD_INT( a, b ) \ + (int)( (unsigned int)(a) + (unsigned int)(b) ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) + + +#define ft_memset memset + +#define ft_setjmp setjmp +#define ft_longjmp longjmp +#define ft_jmp_buf jmp_buf + +typedef ptrdiff_t FT_PtrDist; + + +#define Smooth_Err_Ok 0 +#define Smooth_Err_Invalid_Outline -1 +#define Smooth_Err_Cannot_Render_Glyph -2 +#define Smooth_Err_Invalid_Argument -3 +#define Smooth_Err_Raster_Overflow -4 + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#include "ftimage.h" +#include "ftgrays.h" + + + /* This macro is used to indicate that a function parameter is unused. */ + /* Its purpose is simply to reduce compiler warnings. Note also that */ + /* simply defining it as `(void)x' doesn't avoid warnings with certain */ + /* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) + + + /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + void + FT_Message( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + } + + + /* empty function useful for setting a breakpoint to catch errors */ + int + FT_Throw( int error, + int line, + const char* file ) + { + FT_UNUSED( error ); + FT_UNUSED( line ); + FT_UNUSED( file ); + + return 0; + } + + + /* we don't handle tracing levels in stand-alone mode; */ +#ifndef FT_TRACE5 +#define FT_TRACE5( varformat ) FT_Message varformat +#endif +#ifndef FT_TRACE7 +#define FT_TRACE7( varformat ) FT_Message varformat +#endif +#ifndef FT_ERROR +#define FT_ERROR( varformat ) FT_Message varformat +#endif + +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( Smooth_Err_, e ) ) + +#else /* !FT_DEBUG_LEVEL_TRACE */ + +#define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ +#define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ +#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ +#define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define FT_Trace_Enable() do { } while ( 0 ) /* nothing */ +#define FT_Trace_Disable() do { } while ( 0 ) /* nothing */ + + +#define FT_DEFINE_OUTLINE_FUNCS( class_, \ + move_to_, line_to_, \ + conic_to_, cubic_to_, \ + shift_, delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; + +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \ + raster_new_, raster_reset_, \ + raster_set_mode_, raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; + + +#else /* !STANDALONE_ */ + + +#include +#include FT_CONFIG_CONFIG_H +#include "ftgrays.h" +#include +#include +#include +#include + +#include "ftsmerrs.h" + + +#endif /* !STANDALONE_ */ + + +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif + +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif + +#ifndef FT_ZERO +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) +#endif + + /* as usual, for the speed hungry :-) */ + +#undef RAS_ARG +#undef RAS_ARG_ +#undef RAS_VAR +#undef RAS_VAR_ + +#ifndef FT_STATIC_RASTER + +#define RAS_ARG gray_PWorker worker +#define RAS_ARG_ gray_PWorker worker, + +#define RAS_VAR worker +#define RAS_VAR_ worker, + +#else /* FT_STATIC_RASTER */ + +#define RAS_ARG void +#define RAS_ARG_ /* empty */ +#define RAS_VAR /* empty */ +#define RAS_VAR_ /* empty */ + +#endif /* FT_STATIC_RASTER */ + + + /* must be at least 6 bits! */ +#define PIXEL_BITS 8 + +#define ONE_PIXEL ( 1 << PIXEL_BITS ) +#undef TRUNC +#define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#undef FRACT +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) ) +#endif + + + /* Compute `dividend / divisor' and return both its quotient and */ + /* remainder, cast to a specific type. This macro also ensures that */ + /* the remainder is always positive. We use the remainder to keep */ + /* track of accumulating errors and compensate for them. */ +#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) % (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + FT_END_STMNT + +#if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __arm__ ) + /* Work around a bug specific to GCC which make the compiler fail to */ + /* optimize a division and modulo operation on the same parameters */ + /* into a single call to `__aeabi_idivmod'. See */ + /* */ + /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ +#undef FT_DIV_MOD +#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ + FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ + FT_END_STMNT +#endif /* __arm__ */ + + + /* Calculating coverages for a slanted line requires a division each */ + /* time the line crosses from cell to cell. These macros speed up */ + /* the repetitive divisions by replacing them with multiplications */ + /* and right shifts so that at most two divisions are performed for */ + /* each slanted line. Nevertheless, these divisions are noticeable */ + /* in the overall performance because flattened curves produce a */ + /* very large number of slanted lines. */ + /* */ + /* The division results here are always within ONE_PIXEL. Therefore */ + /* the shift magnitude should be at least PIXEL_BITS wider than the */ + /* divisors to provide sufficient accuracy of the multiply-shift. */ + /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */ + /* leave enough room for 64-bit unsigned multiplication however. */ +#define FT_UDIVPREP( c, b ) \ + FT_Int64 b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0 +#define FT_UDIV( a, b ) \ + (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 ) + + + /* Scale area and apply fill rule to calculate the coverage byte. */ + /* The top fill bit is used for the non-zero rule. The eighth */ + /* fill bit is used for the even-odd rule. The higher coverage */ + /* bytes are either clamped for the non-zero-rule or discarded */ + /* later for the even-odd rule. */ +#define FT_FILL_RULE( coverage, area, fill ) \ + FT_BEGIN_STMNT \ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \ + if ( coverage & fill ) \ + coverage = ~coverage; \ + if ( coverage > 255 && fill & INT_MIN ) \ + coverage = 255; \ + FT_END_STMNT + + + /* It is faster to write small spans byte-by-byte than calling */ + /* `memset'. This is mainly due to the cost of the function call. */ +#define FT_GRAY_SET( d, s, count ) \ + FT_BEGIN_STMNT \ + unsigned char* q = d; \ + switch ( count ) \ + { \ + case 7: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 6: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 5: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 4: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 3: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 2: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 1: *q = (unsigned char)s; FALL_THROUGH; \ + case 0: break; \ + default: FT_MEM_SET( d, s, count ); \ + } \ + FT_END_STMNT + + + /************************************************************************** + * + * TYPE DEFINITIONS + */ + + /* don't change the following types to FT_Int or FT_Pos, since we might */ + /* need to define them to "float" or "double" when experimenting with */ + /* new algorithms */ + + typedef long TPos; /* subpixel coordinate */ + typedef int TCoord; /* integer scanline/pixel coordinate */ + typedef int TArea; /* cell areas, coordinate products */ + + + typedef struct TCell_* PCell; + + typedef struct TCell_ + { + TCoord x; /* same with gray_TWorker.ex */ + TCoord cover; /* same with gray_TWorker.cover */ + TArea area; + PCell next; + + } TCell; + + typedef struct TPixmap_ + { + unsigned char* origin; /* pixmap origin at the bottom-left */ + int pitch; /* pitch to go down one row */ + + } TPixmap; + + /* maximum number of gray cells in the buffer */ +#if FT_RENDER_POOL_SIZE > 2048 +#define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) ) +#else +#define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) ) +#endif + + /* FT_Span buffer size for direct rendering only */ +#define FT_MAX_GRAY_SPANS 16 + + +#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ + /* We disable the warning `structure was padded due to */ + /* __declspec(align())' in order to compile cleanly with */ + /* the maximum level of warnings. */ +#pragma warning( push ) +#pragma warning( disable : 4324 ) +#endif /* _MSC_VER */ + + typedef struct gray_TWorker_ + { + FT_BBox cbox; + + TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ + TCoord min_ey, max_ey; + TCoord count_ey; /* same as (max_ey - min_ey) */ + + PCell cell; /* current cell */ + PCell cell_free; /* call allocation next free slot */ + PCell cell_null; /* last cell, used as dumpster and limit */ + + PCell* ycells; /* array of cell linked-lists; one per */ + /* vertical coordinate in the current band */ + + TPos x, y; /* last point position */ + + FT_Outline outline; /* input outline */ + TPixmap target; /* target pixmap */ + + FT_Raster_Span_Func render_span; + void* render_span_data; + + ft_jmp_buf jump_buffer; + + } gray_TWorker, *gray_PWorker; + +#if defined( _MSC_VER ) +#pragma warning( pop ) +#endif + +#ifndef FT_STATIC_RASTER +#define ras (*worker) +#else + static gray_TWorker ras; +#endif + + /* The |x| value of the null cell. Must be the largest possible */ + /* integer value stored in a `TCell.x` field. */ +#define CELL_MAX_X_VALUE INT_MAX + + +#define FT_INTEGRATE( ras, a, b ) \ + ras.cell->cover = ADD_INT( ras.cell->cover, a ), \ + ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) ) + + + typedef struct gray_TRaster_ + { + void* memory; + + } gray_TRaster, *gray_PRaster; + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* to be called while in the debugger -- */ + /* this function causes a compiler warning since it is unused otherwise */ + static void + gray_dump_cells( RAS_ARG ) + { + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + + + printf( "%3d:", y ); + + for ( ; cell != ras.cell_null; cell = cell->next ) + printf( " (%3d, c:%4d, a:%6d)", + cell->x, cell->cover, cell->area ); + printf( "\n" ); + } + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * Set the current cell to a new position. + */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + /* Move the cell pointer to a new position in the linked list. We use */ + /* a dumpster null cell for everything outside of the clipping region */ + /* during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ + + TCoord ey_index = ey - ras.min_ey; + + + if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) + ras.cell = ras.cell_null; + else + { + PCell* pcell = ras.ycells + ey_index; + PCell cell; + + + ex = FT_MAX( ex, ras.min_ex - 1 ); + + while ( 1 ) + { + cell = *pcell; + + if ( cell->x > ex ) + break; + + if ( cell->x == ex ) + goto Found; + + pcell = &cell->next; + } + + /* insert new cell */ + cell = ras.cell_free++; + if ( cell >= ras.cell_null ) + ft_longjmp( ras.jump_buffer, 1 ); + + cell->x = ex; + cell->area = 0; + cell->cover = 0; + + cell->next = *pcell; + *pcell = cell; + + Found: + ras.cell = cell; + } + } + + +#ifndef FT_INT64 + + /************************************************************************** + * + * Render a scanline as one or more cells. + */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod; + TPos p, dx; + int incr; + + + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } + + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + goto End; + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + dx = x2 - x1; + dy = y2 - y1; + + if ( dx > 0 ) + { + p = ( ONE_PIXEL - fx1 ) * dy; + first = ONE_PIXEL; + incr = 1; + } + else + { + p = fx1 * dy; + first = 0; + incr = -1; + dx = -dx; + } + + /* the fractional part of y-delta is mod/dx. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + /* XXX: y-delta and x-delta below should be related. */ + FT_DIV_MOD( TCoord, p, dx, delta, mod ); + + FT_INTEGRATE( ras, delta, fx1 + first ); + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + + if ( ex1 != ex2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dy; + FT_DIV_MOD( TCoord, p, dx, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dx ) + { + mod -= (TCoord)dx; + delta++; + } + + FT_INTEGRATE( ras, delta, ONE_PIXEL ); + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } while ( ex1 != ex2 ); + } + + fx1 = ONE_PIXEL - first; + + End: + FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 ); + } + + + /************************************************************************** + * + * Render a given line as a series of scanlines. + */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2, first, delta, mod; + TPos p, dx, dy, x, x2; + int incr; + + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + fy1 = FRACT( ras.y ); + fy2 = FRACT( to_y ); + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* vertical line - avoid calling gray_render_scanline */ + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = FRACT( ras.x ) << 1; + + + if ( dy > 0) + { + first = ONE_PIXEL; + incr = 1; + } + else + { + first = 0; + incr = -1; + } + + delta = first - fy1; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + + delta = first + first - ONE_PIXEL; + while ( ey1 != ey2 ) + { + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; + + gray_set_cell( RAS_VAR_ ex, ey1 ); + } + + delta = fy2 - ONE_PIXEL + first; + FT_INTEGRATE( ras, delta, two_fx); + + goto End; + } + + /* ok, we have to render several scanlines */ + if ( dy > 0) + { + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + } + else + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + /* the fractional part of x-delta is mod/dy. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + FT_DIV_MOD( TCoord, p, dy, delta, mod ); + + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ); + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + + if ( ey1 != ey2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dx; + FT_DIV_MOD( TCoord, p, dy, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dy ) + { + mod -= (TCoord)dy; + delta++; + } + + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + x2, first ); + x = x2; + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } while ( ey1 != ey2 ); + } + + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + to_x, fy2 ); + + End: + ras.x = to_x; + ras.y = to_y; + } + +#else + + /************************************************************************** + * + * Render a straight line across multiple cells in any direction. + */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TPos dx, dy; + TCoord fx1, fy1, fx2, fy2; + TCoord ex1, ey1, ex2, ey2; + + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + ex1 = TRUNC( ras.x ); + ex2 = TRUNC( to_x ); + + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); + + dx = to_x - ras.x; + dy = to_y - ras.y; + + if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ + ; + else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ + { + gray_set_cell( RAS_VAR_ ex2, ey2 ); + goto End; + } + else if ( dx == 0 ) + { + if ( dy > 0 ) /* vertical line up */ + do + { + fy2 = ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); + fy1 = 0; + ey1++; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + else /* vertical line down */ + do + { + fy2 = 0; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); + fy1 = ONE_PIXEL; + ey1--; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + } + else /* any other line */ + { + FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1; + FT_UDIVPREP( ex1 != ex2, dx ); + FT_UDIVPREP( ey1 != ey2, dy ); + + + /* The fundamental value `prod' determines which side and the */ + /* exact coordinate where the line exits current cell. It is */ + /* also easily updated when moving from one cell to the next. */ + do + { + if ( prod - dx * ONE_PIXEL > 0 && + prod <= 0 ) /* left */ + { + fx2 = 0; + fy2 = FT_UDIV( -prod, -dx ); + prod -= dy * ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = ONE_PIXEL; + fy1 = fy2; + ex1--; + } + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 && + prod - dx * ONE_PIXEL <= 0 ) /* up */ + { + prod -= dx * ONE_PIXEL; + fx2 = FT_UDIV( -prod, dy ); + fy2 = ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = fx2; + fy1 = 0; + ey1++; + } + else if ( prod + dy * ONE_PIXEL >= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */ + { + prod += dy * ONE_PIXEL; + fx2 = ONE_PIXEL; + fy2 = FT_UDIV( prod, dx ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = 0; + fy1 = fy2; + ex1++; + } + else /* ( prod > 0 && + prod + dy * ONE_PIXEL < 0 ) down */ + { + fx2 = FT_UDIV( prod, -dy ); + fy2 = 0; + prod += dx * ONE_PIXEL; + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + fx1 = fx2; + fy1 = ONE_PIXEL; + ey1--; + } + + gray_set_cell( RAS_VAR_ ex1, ey1 ); + + } while ( ex1 != ex2 || ey1 != ey2 ); + } + + fx2 = FRACT( to_x ); + fy2 = FRACT( to_y ); + + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); + + End: + ras.x = to_x; + ras.y = to_y; + } + +#endif + + /* + * For now, the code that uses DDA to render conic curves requires + * `FT_Int64` to be defined. See for example + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. + */ + +#ifdef FT_INT64 + +#define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector p0, p1, p2; + TPos ax, ay, bx, by, dx, dy; + int shift; + + FT_Int64 rx, ry; + FT_Int64 qx, qy; + FT_Int64 px, py; + + FT_UInt count; + + + p0.x = ras.x; + p0.y = ras.y; + p1.x = UPSCALE( control->x ); + p1.y = UPSCALE( control->y ); + p2.x = UPSCALE( to->x ); + p2.y = UPSCALE( to->y ); + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( p0.y ) >= ras.max_ey && + TRUNC( p1.y ) >= ras.max_ey && + TRUNC( p2.y ) >= ras.max_ey ) || + ( TRUNC( p0.y ) < ras.min_ey && + TRUNC( p1.y ) < ras.min_ey && + TRUNC( p2.y ) < ras.min_ey ) ) + { + ras.x = p2.x; + ras.y = p2.y; + return; + } + + bx = p1.x - p0.x; + by = p1.y - p0.y; + ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ + ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ + + dx = FT_ABS( ax ); + dy = FT_ABS( ay ); + if ( dx < dy ) + dx = dy; + + if ( dx <= ONE_PIXEL / 4 ) + { + gray_render_line( RAS_VAR_ p2.x, p2.y ); + return; + } + + /* We can calculate the number of necessary segments because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + shift = 16; + do + { + dx >>= 2; + shift--; + + } while ( dx > ONE_PIXEL / 4 ); + count = 0x10000U >> shift; + + /* + * The (P0,P1,P2) arc equation, for t in [0,1] range: + * + * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 + * + * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 + * = P0 + 2*B*t + A*t^2 + * + * for A = P0 + P2 - 2*P1 + * and B = P1 - P0 + * + * Let's consider the difference when advancing by a small + * parameter h: + * + * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t + * + * And then its own difference: + * + * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) + * + * Since R is always a constant, it is possible to compute + * successive positions with: + * + * P = P0 + * Q = Q(h,0) = 2*B*h + A*h*h + * R = 2*A*h*h + * + * loop: + * P += Q + * Q += R + * EMIT(P) + * + * To ensure accurate results, perform computations on 64-bit + * values, after scaling them by 2^32. + * + * h = 1 / 2^N + * + * R << 32 = 2 * A << (32 - N - N) + * = A << (33 - 2*N) + * + * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) + * = (B << (33 - N)) + (A << (32 - 2*N)) + */ + + rx = LEFT_SHIFT( ax, shift + shift ); + ry = LEFT_SHIFT( ay, shift + shift ); + + qx = LEFT_SHIFT( bx, shift + 17 ) + rx; + qy = LEFT_SHIFT( by, shift + 17 ) + ry; + + rx *= 2; + ry *= 2; + + px = LEFT_SHIFT( p0.x, 32 ); + py = LEFT_SHIFT( p0.y, 32 ); + + do + { + px += qx; + py += qy; + qx += rx; + qy += ry; + + gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), + (FT_Pos)( py >> 32 ) ); + } while ( --count ); + } + +#else /* !FT_INT64 */ + + /* + * Note that multiple attempts to speed up the function below + * with SSE2 intrinsics, using various data layouts, have turned + * out to be slower than the non-SIMD code below. + */ + static void + gray_split_conic( FT_Vector* base ) + { + TPos a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; + } + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ + FT_Vector* arc = bez_stack; + TPos dx, dy; + int draw; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); + dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); + if ( dx < dy ) + dx = dy; + + /* We can calculate the number of necessary bisections because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + draw = 1; + while ( dx > ONE_PIXEL / 4 ) + { + dx >>= 2; + draw <<= 1; + } + + /* We use decrement counter to count the total number of segments */ + /* to draw starting from 2^level. Before each draw we split as */ + /* many times as there are trailing zeros in the counter. */ + do + { + int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + + + while ( ( split >>= 1 ) ) + { + gray_split_conic( arc ); + arc += 2; + } + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + arc -= 2; + + } while ( --draw ); + } + +#endif /* !FT_INT64 */ + + + /* + * For cubic Bézier, binary splits are still faster than DDA + * because the splits are adaptive to how quickly each sub-arc + * approaches their chord trisection points. + * + * It might be useful to experiment with SSE2 to speed up + * `gray_split_cubic`, though. + */ + static void + gray_split_cubic( FT_Vector* base ) + { + TPos a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; + } + + + static void + gray_render_cubic( RAS_ARG_ const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to ) + { + FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ + FT_Vector* arc = bez_stack; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey && + TRUNC( arc[3].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey && + TRUNC( arc[3].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + for (;;) + { + /* with each split, control points quickly converge towards */ + /* chord trisection points and the vanishing distances below */ + /* indicate when the segment is flat enough to draw */ + if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || + FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || + FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || + FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) + goto Split; + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + + if ( arc == bez_stack ) + return; + + arc -= 3; + continue; + + Split: + gray_split_cubic( arc ); + arc += 3; + } + } + + + static int + gray_move_to( const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + TPos x, y; + + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + + gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); + + ras.x = x; + ras.y = y; + return 0; + } + + + static int + gray_line_to( const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); + return 0; + } + + + static int + gray_conic_to( const FT_Vector* control, + const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_conic( RAS_VAR_ control, to ); + return 0; + } + + + static int + gray_cubic_to( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* worker_ ) /* gray_PWorker */ + { + gray_PWorker worker = (gray_PWorker)worker_; + + + gray_render_cubic( RAS_VAR_ control1, control2, to ); + return 0; + } + + +#ifdef STANDALONE_ + + /************************************************************************** + * + * The following functions should only compile in stand-alone mode, + * i.e., when building this component without the rest of FreeType. + * + */ + + /************************************************************************** + * + * @Function: + * FT_Outline_Decompose + * + * @Description: + * Walk over an outline's structure to decompose it into individual + * segments and Bézier arcs. This function is also able to emit + * `move to' and `close to' operations to indicate the start and end + * of new contours in the outline. + * + * @Input: + * outline :: + * A pointer to the source target. + * + * func_interface :: + * A table of `emitters', i.e., function pointers + * called during decomposition to indicate path + * operations. + * + * @InOut: + * user :: + * A typeless pointer which is passed to each + * emitter during the decomposition. It can be + * used to store the state during the + * decomposition. + * + * @Return: + * Error code. 0 means success. + */ + static int + FT_Outline_Decompose( const FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + int error; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int last; /* index of last point in contour */ + + char tag; /* current point's state */ + + int shift; + TPos delta; + + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return FT_THROW( Invalid_Argument ); + + shift = func_interface->shift; + delta = func_interface->delta; + + last = -1; + for ( n = 0; n < outline->n_contours; n++ ) + { + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); + + first = last + 1; + last = outline->contours[n]; + if ( last < first ) + goto Invalid_Outline; + + limit = outline->points + last; + + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + FT_TRACE5(( " move to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case FT_CURVE_TAG_ON: /* emit a single line_to */ + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " line to (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } + + case FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_middle.x / 64.0, v_middle.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + + v_control = vec; + goto Do_Conic; + } + + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; + + default: /* FT_CURVE_TAG_CUBIC */ + { + FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + + if ( point <= limit ) + { + FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->line_to( &v_start, user ); + + Close: + if ( error ) + goto Exit; + } + + FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); + return Smooth_Err_Ok; + + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); + return error; + + Invalid_Outline: + return FT_THROW( Invalid_Outline ); + } + +#endif /* STANDALONE_ */ + + + FT_DEFINE_OUTLINE_FUNCS( + func_interface, + + (FT_Outline_MoveTo_Func) gray_move_to, /* move_to */ + (FT_Outline_LineTo_Func) gray_line_to, /* line_to */ + (FT_Outline_ConicTo_Func)gray_conic_to, /* conic_to */ + (FT_Outline_CubicTo_Func)gray_cubic_to, /* cubic_to */ + + 0, /* shift */ + 0 /* delta */ + ) + + + static int + gray_convert_glyph_inner( RAS_ARG_ + int continued ) + { + volatile int error; + + + if ( ft_setjmp( ras.jump_buffer ) == 0 ) + { + if ( continued ) + FT_Trace_Disable(); + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + if ( continued ) + FT_Trace_Enable(); + + FT_TRACE7(( "band [%d..%d]: %td cell%s remaining\n", + ras.min_ey, + ras.max_ey, + ras.cell_null - ras.cell_free, + ras.cell_null - ras.cell_free == 1 ? "" : "s" )); + } + else + { + error = FT_THROW( Raster_Overflow ); + + FT_TRACE7(( "band [%d..%d]: to be bisected\n", + ras.min_ey, ras.max_ey )); + } + + return error; + } + + + static void + gray_sweep( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + unsigned char* line = ras.target.origin - ras.target.pitch * y; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, cell->x - x ); + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + line[cell->x] = (unsigned char)coverage; + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); + } + } + } + + + static void + gray_sweep_direct( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + FT_Span span[FT_MAX_GRAY_SPANS]; + int n = 0; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( cell->x - x ); + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)cell->x; + span[n].len = 1; + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( ras.max_ex - x ); + + ++n; + } + + if ( n ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + } + + + static int + gray_convert_glyph( RAS_ARG ) + { + TCell buffer[FT_MAX_GRAY_POOL]; + size_t height = (size_t)( ras.cbox.yMax - ras.cbox.yMin ); + size_t n = FT_MAX_GRAY_POOL / 8; + TCoord y; + TCoord bands[32]; /* enough to accommodate bisections */ + TCoord* band; + + int continued = 0; + + + /* Initialize the null cell at the end of the poll. */ + ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; + ras.cell_null->x = CELL_MAX_X_VALUE; + ras.cell_null->area = 0; + ras.cell_null->cover = 0; + ras.cell_null->next = NULL; + + /* set up vertical bands */ + ras.ycells = (PCell*)buffer; + + if ( height > n ) + { + /* two divisions rounded up */ + n = ( height + n - 1 ) / n; + height = ( height + n - 1 ) / n; + } + + for ( y = ras.cbox.yMin; y < ras.cbox.yMax; ) + { + ras.min_ey = y; + y += height; + ras.max_ey = FT_MIN( y, ras.cbox.yMax ); + + ras.count_ey = ras.max_ey - ras.min_ey; + + band = bands; + band[1] = ras.cbox.xMin; + band[0] = ras.cbox.xMax; + + do + { + TCoord i; + int error; + + + ras.min_ex = band[1]; + ras.max_ex = band[0]; + + /* memory management: zero out and skip ycells */ + for ( i = 0; i < ras.count_ey; ++i ) + ras.ycells[i] = ras.cell_null; + + n = ( (size_t)ras.count_ey * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) + / sizeof ( TCell ); + + ras.cell_free = buffer + n; + ras.cell = ras.cell_null; + + error = gray_convert_glyph_inner( RAS_VAR_ continued ); + continued = 1; + + if ( !error ) + { + if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ + gray_sweep_direct( RAS_VAR ); + else + gray_sweep( RAS_VAR ); + band--; + continue; + } + else if ( error != Smooth_Err_Raster_Overflow ) + return error; + + /* render pool overflow; we will reduce the render band by half */ + i = ( band[0] - band[1] ) >> 1; + + /* this should never happen even with tiny rendering pool */ + if ( i == 0 ) + { + FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); + return FT_THROW( Raster_Overflow ); + } + + band++; + band[1] = band[0]; + band[0] += i; + } while ( band >= bands ); + } + + return Smooth_Err_Ok; + } + + + static int + gray_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + +#ifndef FT_STATIC_RASTER + gray_TWorker worker[1]; +#endif + + + if ( !raster ) + return FT_THROW( Invalid_Argument ); + + /* this version does not support monochrome rendering */ + if ( !( params->flags & FT_RASTER_FLAG_AA ) ) + return FT_THROW( Cannot_Render_Glyph ); + + if ( !outline ) + return FT_THROW( Invalid_Outline ); + + /* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return Smooth_Err_Ok; + + if ( !outline->contours || !outline->points ) + return FT_THROW( Invalid_Outline ); + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return FT_THROW( Invalid_Outline ); + + ras.outline = *outline; + + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + { + if ( !params->gray_spans ) + return Smooth_Err_Ok; + + ras.render_span = (FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + + ras.cbox = params->clip_box; + } + else + { + /* if direct mode is not set, we must have a target bitmap */ + if ( !target_map ) + return FT_THROW( Invalid_Argument ); + + /* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return Smooth_Err_Ok; + + if ( !target_map->buffer ) + return FT_THROW( Invalid_Argument ); + + if ( target_map->pitch < 0 ) + ras.target.origin = target_map->buffer; + else + ras.target.origin = target_map->buffer + + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch; + + ras.target.pitch = target_map->pitch; + + ras.render_span = (FT_Raster_Span_Func)NULL; + ras.render_span_data = NULL; + + ras.cbox.xMin = 0; + ras.cbox.yMin = 0; + ras.cbox.xMax = (FT_Pos)target_map->width; + ras.cbox.yMax = (FT_Pos)target_map->rows; + } + + /* exit if nothing to do */ + if ( ras.cbox.xMin >= ras.cbox.xMax || ras.cbox.yMin >= ras.cbox.yMax ) + return Smooth_Err_Ok; + + return gray_convert_glyph( RAS_VAR ); + } + + + /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ + /**** a static object. *****/ + +#ifdef STANDALONE_ + + static int + gray_raster_new( void* memory, + FT_Raster* araster ) + { + static gray_TRaster the_raster; + + FT_UNUSED( memory ); + + + *araster = (FT_Raster)&the_raster; + FT_ZERO( &the_raster ); + + return 0; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + /* nothing */ + FT_UNUSED( raster ); + } + +#else /* !STANDALONE_ */ + + static int + gray_raster_new( void* memory_, + FT_Raster* araster_ ) + { + FT_Memory memory = (FT_Memory)memory_; + gray_PRaster* araster = (gray_PRaster*)araster_; + + FT_Error error; + gray_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + gray_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; + + + FT_FREE( raster ); + } + +#endif /* !STANDALONE_ */ + + + static void + gray_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static int + gray_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + + return 0; /* nothing to do */ + } + + + FT_DEFINE_RASTER_FUNCS( + ft_grays_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) gray_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) gray_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)gray_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) gray_raster_render, /* raster_render */ + (FT_Raster_Done_Func) gray_raster_done /* raster_done */ + ) + + +/* END */ + + +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ diff --git a/Dependencies/freetype/freetype/src/smooth/ftgrays.h b/Dependencies/freetype/freetype/src/smooth/ftgrays.h new file mode 100644 index 00000000..940fbe8c --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/ftgrays.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * + * ftgrays.h + * + * FreeType smooth renderer declaration + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTGRAYS_H_ +#define FTGRAYS_H_ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifdef STANDALONE_ +#include "ftimage.h" +#else +#include +#include +#endif + + + /************************************************************************** + * + * To make ftgrays.h independent from configuration files we check + * whether FT_EXPORT_VAR has been defined already. + * + * On some systems and compilers (Win32 mostly), an extra keyword is + * necessary to compile the library as a DLL. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; + + +#ifdef __cplusplus + } +#endif + +#endif /* FTGRAYS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/smooth/ftsmerrs.h b/Dependencies/freetype/freetype/src/smooth/ftsmerrs.h new file mode 100644 index 00000000..6d41fb8e --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/ftsmerrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * ftsmerrs.h + * + * smooth renderer error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the smooth renderer error enumeration + * constants. + * + */ + +#ifndef FTSMERRS_H_ +#define FTSMERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Smooth_Err_ +#define FT_ERR_BASE FT_Mod_Err_Smooth + +#include + +#endif /* FTSMERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/smooth/ftsmooth.c b/Dependencies/freetype/freetype/src/smooth/ftsmooth.c new file mode 100644 index 00000000..f0acc1ea --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/ftsmooth.c @@ -0,0 +1,605 @@ +/**************************************************************************** + * + * ftsmooth.c + * + * Anti-aliasing renderer interface (body). + * + * Copyright (C) 2000-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include "ftsmooth.h" +#include "ftgrays.h" + +#include "ftsmerrs.h" + + + /* sets render-specific mode */ + static FT_Error + ft_smooth_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + /* transform a given glyph image */ + static FT_Error + ft_smooth_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + + Exit: + return error; + } + + + /* return the glyph's control box */ + static void + ft_smooth_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + typedef struct TOrigin_ + { + unsigned char* origin; /* pixmap origin at the bottom-left */ + int pitch; /* pitch to go down one row */ + + } TOrigin; + +#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + FT_Vector* sub = render->root.library->lcd_geometry; + + + /* set up default subpixel geometry for striped RGB panels. */ + sub[0].x = -21; + sub[0].y = 0; + sub[1].x = 0; + sub[1].y = 0; + sub[2].x = 21; + sub[2].y = 0; + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + /* This function writes every third byte in direct rendering mode */ + static void + ft_smooth_lcd_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) /* TOrigin* */ + { + TOrigin* target = (TOrigin*)target_; + + unsigned char* dst_line = target->origin - y * target->pitch; + unsigned char* dst; + unsigned short w; + + + for ( ; count--; spans++ ) + for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) + *dst = spans->coverage; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + TOrigin target; + + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Set up direct rendering to record them on each third byte. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_lcd_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width; + params.clip_box.yMax = bitmap->rows; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + FT_Outline_Translate( outline, + -sub[0].x, + -sub[0].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].x; + y = sub[0].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[0].x - sub[1].x, + sub[0].y - sub[1].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].x; + y = sub[1].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[1].x - sub[2].x, + sub[1].y - sub[2].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].x; + y = sub[2].y; + + Exit: + FT_Outline_Translate( outline, x, y ); + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + int pitch = bitmap->pitch; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Notice that the subpixel geometry vectors are rotated. */ + /* Triple the pitch to render on each third row. */ + bitmap->pitch *= 3; + bitmap->rows /= 3; + + FT_Outline_Translate( outline, + -sub[0].y, + sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].y; + y = -sub[0].x; + if ( error ) + goto Exit; + + bitmap->buffer += pitch; + FT_Outline_Translate( outline, + sub[0].y - sub[1].y, + sub[1].x - sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].y; + y = -sub[1].x; + bitmap->buffer -= pitch; + if ( error ) + goto Exit; + + bitmap->buffer += 2 * pitch; + FT_Outline_Translate( outline, + sub[1].y - sub[2].y, + sub[2].x - sub[1].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].y; + y = -sub[2].x; + bitmap->buffer -= 2 * pitch; + + Exit: + FT_Outline_Translate( outline, x, y ); + + bitmap->pitch /= 3; + bitmap->rows *= 3; + + return error; + } + +#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + + /* set up default LCD filtering */ + FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x /= 3; + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y /= 3; + + return error; + } + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +/* Oversampling scale to be used in rendering overlaps */ +#define SCALE ( 1 << 2 ) + + /* This function averages inflated spans in direct rendering mode */ + static void + ft_smooth_overlap_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) + { + TOrigin* target = (TOrigin*)target_; + + + unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; + unsigned short x; + unsigned int cover, sum; + + + /* When accumulating the oversampled spans we need to assure that */ + /* fully covered pixels are equal to 255 and do not overflow. */ + /* It is important that the SCALE is a power of 2, each subpixel */ + /* cover can also reach a power of 2 after rounding, and the total */ + /* is clamped to 255 when it adds up to 256. */ + for ( ; count--; spans++ ) + { + cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); + for ( x = 0; x < spans->len; x++ ) + { + sum = dst[( spans->x + x ) / SCALE] + cover; + dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); + } + } + } + + + static FT_Error + ft_smooth_raster_overlap( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + TOrigin target; + + + /* Reject outlines that are too wide for 16-bit FT_Span. */ + /* Other limits are applied upstream with the same error code. */ + if ( bitmap->width * SCALE > 0x7FFF ) + return FT_THROW( Raster_Overflow ); + + /* Set up direct rendering to average oversampled spans. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_overlap_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width * SCALE; + params.clip_box.yMax = bitmap->rows * SCALE; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + /* inflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x *= SCALE; + vec->y *= SCALE; + } + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x /= SCALE; + vec->y /= SCALE; + } + + return error; + } + +#undef SCALE + + static FT_Error + ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = render->root.memory; + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check mode */ + if ( mode != FT_RENDER_MODE_NORMAL && + mode != FT_RENDER_MODE_LIGHT && + mode != FT_RENDER_MODE_LCD && + mode != FT_RENDER_MODE_LCD_V ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* allocate new one */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + x_shift = 64 * -slot->bitmap_left; + y_shift = 64 * -slot->bitmap_top; + if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + y_shift += 64 * (FT_Int)bitmap->rows / 3; + else + y_shift += 64 * (FT_Int)bitmap->rows; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + if ( mode == FT_RENDER_MODE_NORMAL || + mode == FT_RENDER_MODE_LIGHT ) + { + if ( outline->flags & FT_OUTLINE_OVERLAP ) + error = ft_smooth_raster_overlap( render, outline, bitmap ); + else + { + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + error = render->raster_render( render->raster, ¶ms ); + } + } + else + { + if ( mode == FT_RENDER_MODE_LCD ) + error = ft_smooth_raster_lcd ( render, outline, bitmap ); + else if ( mode == FT_RENDER_MODE_LCD_V ) + error = ft_smooth_raster_lcdv( render, outline, bitmap ); + +#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* finally apply filtering */ + { + FT_Byte* lcd_weights; + FT_Bitmap_LcdFilterFunc lcd_filter_func; + + + /* Per-face LCD filtering takes priority if set up. */ + if ( slot->face && slot->face->internal->lcd_filter_func ) + { + lcd_weights = slot->face->internal->lcd_weights; + lcd_filter_func = slot->face->internal->lcd_filter_func; + } + else + { + lcd_weights = slot->library->lcd_weights; + lcd_filter_func = slot->library->lcd_filter_func; + } + + if ( lcd_filter_func ) + lcd_filter_func( bitmap, lcd_weights ); + } + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + } + + Exit: + if ( !error ) + { + /* everything is fine; the glyph is now officially a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + } + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_smooth_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + + "smooth", + 0x10000L, + 0x20000L, + + NULL, /* module specific interface */ + + (FT_Module_Constructor)ft_smooth_init, /* module_init */ + (FT_Module_Destructor) NULL, /* module_done */ + (FT_Module_Requester) NULL, /* get_interface */ + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_smooth_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_smooth_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/smooth/ftsmooth.h b/Dependencies/freetype/freetype/src/smooth/ftsmooth.h new file mode 100644 index 00000000..d7b61a9e --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/ftsmooth.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftsmooth.h + * + * Anti-aliasing renderer interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTSMOOTH_H_ +#define FTSMOOTH_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_DECLARE_RENDERER( ft_smooth_renderer_class ) + + +FT_END_HEADER + +#endif /* FTSMOOTH_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/smooth/smooth.c b/Dependencies/freetype/freetype/src/smooth/smooth.c new file mode 100644 index 00000000..8c506818 --- /dev/null +++ b/Dependencies/freetype/freetype/src/smooth/smooth.c @@ -0,0 +1,25 @@ +/**************************************************************************** + * + * smooth.c + * + * FreeType anti-aliasing rasterer module component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ftgrays.c" +#include "ftsmooth.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/svg/ftsvg.c b/Dependencies/freetype/freetype/src/svg/ftsvg.c new file mode 100644 index 00000000..35788a2d --- /dev/null +++ b/Dependencies/freetype/freetype/src/svg/ftsvg.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * + * ftsvg.c + * + * The FreeType SVG renderer interface (body). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "ftsvg.h" +#include "svgtypes.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otsvg + + +#ifdef FT_CONFIG_OPTION_SVG + + /* ft_svg_init */ + static FT_Error + ft_svg_init( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + FT_Error error = FT_Err_Ok; + + + render->loaded = FALSE; + render->hooks_set = FALSE; + + return error; + } + + + static void + ft_svg_done( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + + if ( render->loaded == TRUE && + render->hooks_set == TRUE ) + render->hooks.free_svg( &render->state ); + + render->loaded = FALSE; + } + + + static FT_Error + ft_svg_preset_slot( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)module; + SVG_RendererHooks hooks = svg_renderer->hooks; + + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_preset_slot: first presetting call," + " calling init hook\n" )); + hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + return hooks.preset_slot( slot, cache, &svg_renderer->state ); + } + + + static FT_Error + ft_svg_render( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)renderer; + + FT_Library library = renderer->root.library; + FT_Memory memory = library->memory; + FT_Error error; + + FT_ULong size_image_buffer; + + SVG_RendererHooks hooks = svg_renderer->hooks; + + + FT_UNUSED( mode ); + FT_UNUSED( origin ); + + if ( mode != FT_RENDER_MODE_NORMAL ) + return FT_THROW( Bad_Argument ); + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" )); + error = hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE ); + + size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows; + /* No `FT_QALLOC` here since we need a clean, empty canvas */ + /* to start with. */ + if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) ) + return error; + + error = hooks.render_svg( slot, &svg_renderer->state ); + if ( error ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + return error; + } + + + static const SVG_Interface svg_interface = + { + ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */ + }; + + + static FT_Error + ft_svg_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks; + + + if ( value_is_string == TRUE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + hooks = (SVG_RendererHooks*)value; + + if ( !hooks->init_svg || + !hooks->free_svg || + !hooks->render_svg || + !hooks->preset_slot ) + { + FT_TRACE0(( "ft_svg_property_set:" + " SVG rendering hooks not set because\n" )); + FT_TRACE0(( " " + " at least one function pointer is NULL\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + renderer->hooks = *hooks; + renderer->hooks_set = TRUE; + } + else + error = FT_THROW( Missing_Property ); + + Exit: + return error; + } + + + static FT_Error + ft_svg_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks = (SVG_RendererHooks*)value; + + + *hooks = renderer->hooks; + } + else + error = FT_THROW( Missing_Property ); + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + ft_svg_service_properties, + + ft_svg_property_set, /* FT_Properties_SetFunc set_property */ + ft_svg_property_get /* FT_Properties_GetFunc get_property */ + ) + + + FT_DEFINE_SERVICEDESCREC1( + ft_svg_services, + FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties ) + + + FT_CALLBACK_DEF( FT_Module_Interface ) + ft_svg_get_interface( FT_Module module, + const char* ft_svg_interface ) + { + FT_Module_Interface result; + + + FT_UNUSED( module ); + + result = ft_service_list_lookup( ft_svg_services, ft_svg_interface ); + if ( result ) + return result; + + return 0; + } + + + static FT_Error + ft_svg_transform( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + FT_UNUSED( renderer ); + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = doc->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ), + FT_MulFix( matrix->xy, doc->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ), + FT_MulFix( matrix->yy, doc->delta.y ) ), + delta->y ); + + doc->delta.x = x; + doc->delta.y = y; + doc->transform = a; + + return FT_Err_Ok; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_MODULE( a ) a +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG +#else +#define PUT_SVG_MODULE( a ) NULL +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE +#endif + + + FT_DEFINE_RENDERER( + ft_svg_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SVG_RendererRec ), + + "ot-svg", + 0x10000L, + 0x20000L, + + (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */ + + PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */ + PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */ + PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */ + + SVG_GLYPH_FORMAT, + + PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */ + PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */ + NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + NULL, /* FT_Renderer_SetModeFunc set_mode */ + NULL /* FT_Raster_Funcs* raster_class */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/svg/ftsvg.h b/Dependencies/freetype/freetype/src/svg/ftsvg.h new file mode 100644 index 00000000..623c091d --- /dev/null +++ b/Dependencies/freetype/freetype/src/svg/ftsvg.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * ftsvg.h + * + * The FreeType SVG renderer interface (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTSVG_H_ +#define FTSVG_H_ + +#include +#include +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_RENDERER( ft_svg_renderer_class ) + +FT_END_HEADER + +#endif /* FTSVG_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/svg/svg.c b/Dependencies/freetype/freetype/src/svg/svg.c new file mode 100644 index 00000000..1f1c04b2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/svg/svg.c @@ -0,0 +1,24 @@ +/**************************************************************************** + * + * svg.c + * + * FreeType SVG renderer module component (body only). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "svgtypes.h" +#include "ftsvg.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/svg/svgtypes.h b/Dependencies/freetype/freetype/src/svg/svgtypes.h new file mode 100644 index 00000000..f1d6d73c --- /dev/null +++ b/Dependencies/freetype/freetype/src/svg/svgtypes.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * svgtypes.h + * + * The FreeType SVG renderer internal types (specification). + * + * Copyright (C) 2022-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef SVGTYPES_H_ +#define SVGTYPES_H_ + +#include +#include +#include +#include + + + typedef struct SVG_RendererRec_ + { + FT_RendererRec root; /* this inherits FT_RendererRec */ + FT_Bool loaded; + FT_Bool hooks_set; + SVG_RendererHooks hooks; /* this holds hooks for SVG rendering */ + FT_Pointer state; /* a place for hooks to store state, if needed */ + + } SVG_RendererRec; + + typedef struct SVG_RendererRec_* SVG_Renderer; + +#endif /* SVGTYPES_H_ */ + + +/* EOF */ diff --git a/Dependencies/freetype/freetype/src/tools/afblue.pl b/Dependencies/freetype/freetype/src/tools/afblue.pl new file mode 100644 index 00000000..1341c773 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/afblue.pl @@ -0,0 +1,551 @@ +#! /usr/bin/perl -w +# -*- Perl -*- +# +# afblue.pl +# +# Process a blue zone character data file. +# +# Copyright (C) 2013-2024 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, +# modified, and distributed under the terms of the FreeType project +# license, LICENSE.TXT. By continuing to use, modify, or distribute +# this file you indicate that you have read the license and +# understand and accept it fully. + +use strict; +use warnings; +use English '-no_match_vars'; +use open ':std', ':encoding(UTF-8)'; + + +my $prog = $PROGRAM_NAME; +$prog =~ s| .* / ||x; # Remove path. + +die "usage: $prog datafile < infile > outfile\n" if $#ARGV != 0; + + +my $datafile = $ARGV[0]; + +my %diversions; # The extracted and massaged data from `datafile'. +my @else_stack; # Booleans to track else-clauses. +my @name_stack; # Stack of integers used for names of aux. variables. + +my $curr_enum; # Name of the current enumeration. +my $curr_array; # Name of the current array. +my $curr_max; # Name of the current maximum value. + +my $curr_enum_element; # Name of the current enumeration element. +my $curr_offset; # The offset relative to current aux. variable. +my $curr_elem_size; # The number of non-space characters in the current string or + # the number of elements in the current block. + +my $have_sections = 0; # Boolean; set if start of a section has been seen. +my $have_strings; # Boolean; set if current section contains strings. +my $have_blocks; # Boolean; set if current section contains blocks. + +my $have_enum_element; # Boolean; set if we have an enumeration element. +my $in_string; # Boolean; set if a string has been parsed. + +my $num_sections = 0; # Number of sections seen so far. + +my $last_aux; # Name of last auxiliary variable. + + +# Regular expressions. + +# [] [] ':' [] '\n' +my $section_re = qr/ ^ \s* (\S+) \s+ (\S+) \s+ (\S+) \s* : \s* $ /x; + +# [] [] '\n' +my $enum_element_re = qr/ ^ \s* ( [A-Za-z0-9_]+ ) \s* $ /x; + +# '#' '\n' +my $preprocessor_re = qr/ ^ \# /x; + +# [] '/' '/' '\n' +my $comment_re = qr| ^ \s* // |x; + +# empty line +my $whitespace_only_re = qr/ ^ \s* $ /x; + +# [] '"' '"' [] '\n' ( doesn't contain newlines) +my $string_re = qr/ ^ \s* + " ( (?> (?: (?> [^"\\]+ ) | \\. )* ) ) " + \s* $ /x; + +# [] '{' '}' [] '\n' ( can contain newlines) +my $block_start_re = qr/ ^ \s* \{ /x; + +# We need the capturing group for `split' to make it return the separator +# tokens (i.e., the opening and closing brace) also. +my $brace_re = qr/ ( [{}] ) /x; + + +sub Warn +{ + my $message = shift; + warn "$datafile:$INPUT_LINE_NUMBER: warning: $message\n"; +} + + +sub Die +{ + my $message = shift; + die "$datafile:$INPUT_LINE_NUMBER: error: $message\n"; +} + + +my $warned_before = 0; + +sub warn_before +{ + Warn("data before first section gets ignored") unless $warned_before; + $warned_before = 1; +} + + +sub strip_newline +{ + chomp; + s/ \x0D $ //x; +} + + +sub end_curr_string +{ + # Append final null byte to string. + if ($have_strings) + { + push @{$diversions{$curr_array}}, " '\\0',\n" if $in_string; + + $curr_offset++; + $in_string = 0; + } +} + + +sub update_max_elem_size +{ + if ($curr_elem_size) + { + my $max = pop @{$diversions{$curr_max}}; + $max = $curr_elem_size if $curr_elem_size > $max; + push @{$diversions{$curr_max}}, $max; + } +} + + +sub convert_non_ascii_char +{ + # A UTF-8 character outside of the printable ASCII range, with possibly a + # leading backslash character. + my $s = shift; + + # Here we count characters, not bytes. + $curr_elem_size += length $s; + + utf8::encode($s); + $s = uc unpack 'H*', $s; + + $curr_offset += $s =~ s/\G(..)/'\\x$1', /sg; + + return $s; +} + + +sub convert_ascii_chars +{ + # A series of ASCII characters in the printable range. + my $s = shift; + + # We reduce multiple space characters to a single one. + $s =~ s/ +/ /g; + + # Count all non-space characters. Note that `()' applies a list context + # to the capture that is used to count the elements. + $curr_elem_size += () = $s =~ /[^ ]/g; + + $curr_offset += $s =~ s/\G(.)/'$1', /g; + + return $s; +} + + +sub convert_literal +{ + my $s = shift; + my $orig = $s; + + # ASCII printables and space + my $safe_re = '\x20-\x7E'; + # ASCII printables and space, no backslash + my $safe_no_backslash_re = '\x20-\x5B\x5D-\x7E'; + + $s =~ s{ + (?: \\? ( [^$safe_re] ) + | ( (?: [$safe_no_backslash_re] + | \\ [$safe_re] )+ ) ) + } + { + defined($1) ? convert_non_ascii_char($1) + : convert_ascii_chars($2) + }egx; + + # We assume that `$orig' doesn't contain `*/' + return $s . " /* $orig */"; +} + + +sub aux_name +{ + return "af_blue_" . $num_sections. "_" . join('_', @name_stack); +} + + +sub aux_name_next +{ + $name_stack[$#name_stack]++; + my $name = aux_name(); + $name_stack[$#name_stack]--; + + return $name; +} + + +sub enum_val_string +{ + # Build string that holds code to save the current offset in an + # enumeration element. + my $aux = shift; + + my $add = ($last_aux eq "af_blue_" . $num_sections . "_0" ) + ? "" + : "$last_aux + "; + + return " $aux = $add$curr_offset,\n"; +} + + + +# Process data file. + +open(DATA, $datafile) || die "$prog: can't open \`$datafile': $OS_ERROR\n"; + +while () +{ + strip_newline(); + + next if /$comment_re/; + next if /$whitespace_only_re/; + + if (/$section_re/) + { + Warn("previous section is empty") if ($have_sections + && !$have_strings + && !$have_blocks); + + end_curr_string(); + update_max_elem_size(); + + # Save captured groups from `section_re'. + $curr_enum = $1; + $curr_array = $2; + $curr_max = $3; + + $curr_enum_element = ""; + $curr_offset = 0; + + Warn("overwriting already defined enumeration \`$curr_enum'") + if exists($diversions{$curr_enum}); + Warn("overwriting already defined array \`$curr_array'") + if exists($diversions{$curr_array}); + Warn("overwriting already defined maximum value \`$curr_max'") + if exists($diversions{$curr_max}); + + $diversions{$curr_enum} = []; + $diversions{$curr_array} = []; + $diversions{$curr_max} = []; + + push @{$diversions{$curr_max}}, 0; + + @name_stack = (); + push @name_stack, 0; + + $have_sections = 1; + $have_strings = 0; + $have_blocks = 0; + + $have_enum_element = 0; + $in_string = 0; + + $num_sections++; + $curr_elem_size = 0; + + $last_aux = aux_name(); + + next; + } + + if (/$preprocessor_re/) + { + if ($have_sections) + { + # Having preprocessor conditionals complicates the computation of + # correct offset values. We have to introduce auxiliary enumeration + # elements with the name `af_blue____...' that store + # offsets to be used in conditional clauses. `' is the number of + # sections seen so far, `' is the number of `#if' and `#endif' + # conditionals seen so far in the topmost level, `' the number of + # `#if' and `#endif' conditionals seen so far one level deeper, etc. + # As a consequence, uneven values are used within a clause, and even + # values after a clause, since the C standard doesn't allow the + # redefinition of an enumeration value. For example, the name + # `af_blue_5_1_6' is used to construct enumeration values in the fifth + # section after the third (second-level) if-clause within the first + # (top-level) if-clause. After the first top-level clause has + # finished, `af_blue_5_2' is used. The current offset is then + # relative to the value stored in the current auxiliary element. + + if (/ ^ \# \s* if /x) + { + push @else_stack, 0; + + $name_stack[$#name_stack]++; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* elif /x) + { + Die("unbalanced #elif") unless @else_stack; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ \# \s* else /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #else") unless defined($prev_else); + Die("#else already seen") if $prev_else; + push @else_stack, 1; + + pop @name_stack; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()); + $last_aux = aux_name(); + + push @name_stack, 0; + + $curr_offset = 0; + } + elsif (/ ^ (\# \s*) endif /x) + { + my $prev_else = pop @else_stack; + Die("unbalanced #endif") unless defined($prev_else); + + pop @name_stack; + + # If there is no else-clause for an if-clause, we add one. This is + # necessary to have correct offsets. + if (!$prev_else) + { + # Use amount of whitespace from `endif'. + push @{$diversions{$curr_enum}}, enum_val_string(aux_name_next()) + . $1 . "else\n"; + $last_aux = aux_name(); + + $curr_offset = 0; + } + + $name_stack[$#name_stack]++; + + push @{$diversions{$curr_enum}}, enum_val_string(aux_name()); + $last_aux = aux_name(); + + $curr_offset = 0; + } + + # Handle (probably continued) preprocessor lines. + CONTINUED_LOOP: + { + do + { + strip_newline(); + + push @{$diversions{$curr_enum}}, $ARG . "\n"; + push @{$diversions{$curr_array}}, $ARG . "\n"; + + last CONTINUED_LOOP unless / \\ $ /x; + + } while (); + } + } + else + { + warn_before(); + } + + next; + } + + if (/$enum_element_re/) + { + end_curr_string(); + update_max_elem_size(); + + $curr_enum_element = $1; + $have_enum_element = 1; + $curr_elem_size = 0; + + next; + } + + if (/$string_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_blocks; + + # Save captured group from `string_re'. + my $string = $1; + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + $string = convert_literal($string); + + push @{$diversions{$curr_array}}, " $string\n"; + + $have_strings = 1; + $in_string = 1; + } + else + { + warn_before(); + } + + next; + } + + if (/$block_start_re/) + { + if ($have_sections) + { + Die("strings and blocks can't be mixed in a section") if $have_strings; + + my $depth = 0; + my $block = ""; + my $block_end = 0; + + # Count braces while getting the block. + BRACE_LOOP: + { + do + { + strip_newline(); + + foreach my $substring (split(/$brace_re/)) + { + if ($block_end) + { + Die("invalid data after last matching closing brace") + if $substring !~ /$whitespace_only_re/; + } + + $block .= $substring; + + if ($substring eq '{') + { + $depth++; + } + elsif ($substring eq '}') + { + $depth--; + + $block_end = 1 if $depth == 0; + } + } + + # If we are here, we have run out of substrings, so get next line + # or exit. + last BRACE_LOOP if $block_end; + + $block .= "\n"; + + } while (); + } + + if ($have_enum_element) + { + push @{$diversions{$curr_enum}}, enum_val_string($curr_enum_element); + $have_enum_element = 0; + } + + push @{$diversions{$curr_array}}, $block . ",\n"; + + $curr_offset++; + $curr_elem_size++; + + $have_blocks = 1; + } + else + { + warn_before(); + } + + next; + } + + # Garbage. We weren't able to parse the data. + Die("syntax error"); +} + +# Finalize data. +end_curr_string(); +update_max_elem_size(); + + +# Filter stdin to stdout, replacing `@...@' templates. + +sub emit_diversion +{ + my $diversion_name = shift; + return (exists($diversions{$1})) ? "@{$diversions{$1}}" + : "@" . $diversion_name . "@"; +} + + +$LIST_SEPARATOR = ''; + +my $s1 = "This file has been generated by the Perl script \`$prog',"; +my $s1len = length $s1; +my $s2 = "using data from file \`$datafile'."; +my $s2len = length $s2; +my $slen = ($s1len > $s2len) ? $s1len : $s2len; + +print "/* " . $s1 . " " x ($slen - $s1len) . " */\n" + . "/* " . $s2 . " " x ($slen - $s2len) . " */\n" + . "\n"; + +while () +{ + s/ @ ( [A-Za-z0-9_]+? ) @ / emit_diversion($1) /egx; + print; +} + +# EOF diff --git a/Dependencies/freetype/freetype/src/tools/apinames.c b/Dependencies/freetype/freetype/src/tools/apinames.c new file mode 100644 index 00000000..5a49b064 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/apinames.c @@ -0,0 +1,556 @@ +/* + * This little program is used to parse the FreeType headers and + * find the declaration of all public APIs. This is easy, because + * they all look like the following: + * + * FT_EXPORT( return_type ) + * function_name( function arguments ); + * + * You must pass the list of header files as arguments. Wildcards are + * accepted if you are using GCC for compilation (and probably by + * other compilers too). + * + * Author: FreeType team, 2005-2023 + * + * This code is explicitly placed into the public domain. + * + */ + +#include +#include +#include +#include +#include + +#include "vms_shorten_symbol.c" + +#define PROGRAM_NAME "apinames" +#define PROGRAM_VERSION "0.5" + +#define LINEBUFF_SIZE 1024 + + +typedef enum OutputFormat_ +{ + OUTPUT_LIST = 0, /* output the list of names, one per line */ + OUTPUT_WINDOWS_DEF, /* output a Windows .DEF file for Visual C++ or Mingw */ + OUTPUT_BORLAND_DEF, /* output a Windows .DEF file for Borland C++ */ + OUTPUT_WATCOM_LBC, /* output a Watcom Linker Command File */ + OUTPUT_VMS_OPT, /* output an OpenVMS Linker Option File */ + OUTPUT_NETWARE_IMP, /* output a NetWare ImportFile */ + OUTPUT_GNU_VERMAP /* output a version map for GNU or Solaris linker */ + +} OutputFormat; + + +static void +panic( const char* fmt, + ... ) +{ + va_list ap; + + + fprintf( stderr, "PANIC: " ); + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); + + fprintf( stderr, "\n" ); + + exit(2); +} + + +typedef struct NameRec_ +{ + char* name; + unsigned int hash; + +} NameRec, *Name; + + +static Name the_names; +static int num_names; +static int max_names; + + +static void +names_add( const char* name, + const char* end ) +{ + unsigned int h; + int nn, len; + Name nm; + + + if ( end <= name ) + return; + + /* compute hash value */ + len = (int)( end - name ); + h = 0; + + for ( nn = 0; nn < len; nn++ ) + h = h * 33 + name[nn]; + + /* check for an pre-existing name */ + for ( nn = 0; nn < num_names; nn++ ) + { + nm = the_names + nn; + + if ( (int)nm->hash == h && + memcmp( name, nm->name, len ) == 0 && + nm->name[len] == 0 ) + return; + } + + /* add new name */ + if ( num_names >= max_names ) + { + max_names += ( max_names >> 1 ) + 4; + the_names = (NameRec*)realloc( the_names, + sizeof ( the_names[0] ) * max_names ); + if ( !the_names ) + panic( "not enough memory" ); + } + nm = &the_names[num_names++]; + + nm->hash = h; + nm->name = (char*)malloc( len + 1 ); + if ( !nm->name ) + panic( "not enough memory" ); + + memcpy( nm->name, name, len ); + nm->name[len] = 0; +} + + +static int +name_compare( const void* name1, + const void* name2 ) +{ + Name n1 = (Name)name1; + Name n2 = (Name)name2; + + return strcmp( n1->name, n2->name ); +} + + +static void +names_sort( void ) +{ + qsort( the_names, (size_t)num_names, + sizeof ( the_names[0] ), name_compare ); +} + + +static void +names_dump( FILE* out, + OutputFormat format, + const char* dll_name ) +{ + int nn; + + + switch ( format ) + { + case OUTPUT_WINDOWS_DEF: + if ( dll_name ) + fprintf( out, "LIBRARY %s\n", dll_name ); + + fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); + fprintf( out, "EXPORTS\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, " %s\n", the_names[nn].name ); + + break; + + case OUTPUT_BORLAND_DEF: + if ( dll_name ) + fprintf( out, "LIBRARY %s\n", dll_name ); + + fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); + fprintf( out, "EXPORTS\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, " _%s\n", the_names[nn].name ); + + break; + + case OUTPUT_WATCOM_LBC: + { + const char* dot; + + + if ( !dll_name ) + { + fprintf( stderr, + "you must provide a DLL name with the -d option!\n" ); + exit( 4 ); + } + + /* we must omit the `.dll' suffix from the library name */ + dot = strchr( dll_name, '.' ); + if ( dot ) + { + char temp[512]; + int len = dot - dll_name; + + + if ( len > (int)( sizeof ( temp ) - 1 ) ) + len = sizeof ( temp ) - 1; + + memcpy( temp, dll_name, len ); + temp[len] = 0; + + dll_name = (const char*)temp; + } + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "++_%s.%s.%s\n", + the_names[nn].name, dll_name, the_names[nn].name ); + } + + break; + + case OUTPUT_VMS_OPT: + fprintf( out, "case_sensitive=YES\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + { + char short_symbol[32]; + + + if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 ) + panic( "could not shorten name '%s'", the_names[nn].name ); + fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol ); + + /* Also emit a 64-bit symbol, as created by the `vms_auto64` tool. */ + /* It has the string '64__' appended to its name. */ + strcat( the_names[nn].name , "64__" ); + if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 ) + panic( "could not shorten name '%s'", the_names[nn].name ); + fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol ); + } + + break; + + case OUTPUT_NETWARE_IMP: + if ( dll_name ) + fprintf( out, " (%s)\n", dll_name ); + + for ( nn = 0; nn < num_names - 1; nn++ ) + fprintf( out, " %s,\n", the_names[nn].name ); + fprintf( out, " %s\n", the_names[num_names - 1].name ); + + break; + + case OUTPUT_GNU_VERMAP: + fprintf( out, "{\n\tglobal:\n" ); + + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "\t\t%s;\n", the_names[nn].name ); + + fprintf( out, "\tlocal:\n\t\t*;\n};\n" ); + + break; + + default: /* LIST */ + for ( nn = 0; nn < num_names; nn++ ) + fprintf( out, "%s\n", the_names[nn].name ); + + break; + } +} + + +/* states of the line parser */ + +typedef enum State_ +{ + STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */ + STATE_TYPE /* type was read, waiting for function name */ + +} State; + + +static int +read_header_file( FILE* file, + int verbose ) +{ + static char buff[LINEBUFF_SIZE + 1]; + State state = STATE_START; + + + while ( !feof( file ) ) + { + char* p; + + + if ( !fgets( buff, LINEBUFF_SIZE, file ) ) + break; + + p = buff; + + /* skip leading whitespace */ + while ( *p == ' ' || *p == '\t' ) + p++; + + /* skip empty lines */ + if ( *p == '\n' || *p == '\r' ) + continue; + + switch ( state ) + { + case STATE_START: + if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 ) + break; + + p += 10; + for (;;) + { + if ( *p == 0 || *p == '\n' || *p == '\r' ) + goto NextLine; + + if ( *p == ')' ) + { + p++; + break; + } + + p++; + } + + state = STATE_TYPE; + + /* + * Sometimes, the name is just after `FT_EXPORT(...)', so skip + * whitespace and fall-through if we find an alphanumeric character. + */ + while ( *p == ' ' || *p == '\t' ) + p++; + + if ( !isalpha( *p ) ) + break; + + /* fall-through */ + + case STATE_TYPE: + { + char* name = p; + + + while ( isalnum( *p ) || *p == '_' ) + p++; + + if ( p > name ) + { + if ( verbose ) + fprintf( stderr, ">>> %.*s\n", (int)( p - name ), name ); + + names_add( name, p ); + } + + state = STATE_START; + } + + break; + + default: + ; + } + +NextLine: + ; + } /* end of while loop */ + + return 0; +} + + +static void +usage( void ) +{ + static const char* const format = + "%s %s: extract FreeType API names from header files\n" + "\n" + "This program extracts the list of public FreeType API functions.\n" + "It receives a list of header files as an argument and\n" + "generates a sorted list of unique identifiers in various formats.\n" + "\n" + "usage: %s header1 [options] [header2 ...]\n" + "\n" + "options: - parse the contents of stdin, ignore arguments\n" + " -v verbose mode, output sent to standard error\n" + " -oFILE write output to FILE instead of standard output\n" + " -dNAME indicate DLL file name, 'freetype.dll' by default\n" + " -w output .DEF file for Visual C++ and Mingw\n" + " -wB output .DEF file for Borland C++\n" + " -wW output Watcom Linker Response File\n" + " -wV output OpenVMS Linker Options File\n" + " -wN output NetWare Import File\n" + " -wL output version map for GNU or Solaris linker\n" + "\n"; + + fprintf( stderr, + format, + PROGRAM_NAME, + PROGRAM_VERSION, + PROGRAM_NAME ); + + exit( 1 ); +} + + +int +main( int argc, + const char* const* argv ) +{ + int from_stdin = 0; + int verbose = 0; + OutputFormat format = OUTPUT_LIST; /* the default */ + FILE* out = stdout; + const char* library_name = NULL; + + + if ( argc < 2 ) + usage(); + + /* `-' used as a single argument means read source file from stdin */ + while ( argc > 1 && argv[1][0] == '-' ) + { + const char* arg = argv[1]; + + + switch ( arg[1] ) + { + case 'v': + verbose = 1; + + break; + + case 'o': + if ( arg[2] == 0 ) + { + if ( argc < 2 ) + usage(); + + arg = argv[2]; + argv++; + argc--; + } + else + arg += 2; + + out = fopen( arg, "wt" ); + if ( !out ) + { + fprintf( stderr, "could not open '%s' for writing\n", arg ); + exit( 3 ); + } + + break; + + case 'd': + if ( arg[2] == 0 ) + { + if ( argc < 2 ) + usage(); + + arg = argv[2]; + argv++; + argc--; + } + else + arg += 2; + + library_name = arg; + + break; + + case 'w': + format = OUTPUT_WINDOWS_DEF; + + switch ( arg[2] ) + { + case 'B': + format = OUTPUT_BORLAND_DEF; + break; + + case 'W': + format = OUTPUT_WATCOM_LBC; + break; + + case 'V': + format = OUTPUT_VMS_OPT; + break; + + case 'N': + format = OUTPUT_NETWARE_IMP; + break; + + case 'L': + format = OUTPUT_GNU_VERMAP; + break; + + case 0: + break; + + default: + usage(); + } + + break; + + case 0: + from_stdin = 1; + + break; + + default: + usage(); + } + + argc--; + argv++; + + } /* end of while loop */ + + if ( from_stdin ) + read_header_file( stdin, verbose ); + else + { + for ( --argc, argv++; argc > 0; argc--, argv++ ) + { + FILE* file = fopen( argv[0], "rb" ); + + + if ( !file ) + fprintf( stderr, "unable to open '%s'\n", argv[0] ); + else + { + if ( verbose ) + fprintf( stderr, "opening '%s'\n", argv[0] ); + + read_header_file( file, verbose ); + fclose( file ); + } + } + } + + if ( num_names == 0 ) + panic( "could not find exported functions\n" ); + + names_sort(); + names_dump( out, format, library_name ); + + if ( out != stdout ) + fclose( out ); + + return 0; +} + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/tools/chktrcmp.py b/Dependencies/freetype/freetype/src/tools/chktrcmp.py new file mode 100644 index 00000000..d072a878 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/chktrcmp.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# +# Check trace components in FreeType 2 source. +# Author: suzuki toshiya, 2009, 2013, 2020 +# +# This code is explicitly into the public domain. + +import sys +import os +import re + +SRC_FILE_LIST = [] +USED_COMPONENT = {} +KNOWN_COMPONENT = {} + +SRC_FILE_DIRS = ["src"] +TRACE_DEF_FILES = ["include/freetype/internal/fttrace.h"] + + +def usage(): + print("Usage: %s [option]" % sys.argv[0]) + print("Search used-but-defined and defined-but-not-used trace_XXX macros") + print("") + print(" --help:") + print(" Show this help") + print("") + print(" --src-dirs=dir1:dir2:...") + print(" Specify the directories of C source files to be checked") + print(" Default is %s" % ":".join(SRC_FILE_DIRS)) + print("") + print(" --def-files=file1:file2:...") + print(" Specify the header files including FT_TRACE_DEF()") + print(" Default is %s" % ":".join(TRACE_DEF_FILES)) + print("") + + +# -------------------------------------------------------------- +# Parse command line options +# +for i in range(1, len(sys.argv)): + if sys.argv[i].startswith("--help"): + usage() + exit(0) + if sys.argv[i].startswith("--src-dirs="): + SRC_FILE_DIRS = sys.argv[i].replace("--src-dirs=", "", 1).split(":") + elif sys.argv[i].startswith("--def-files="): + TRACE_DEF_FILES = sys.argv[i].replace("--def-files=", "", 1).split(":") + +# -------------------------------------------------------------- +# Scan C source and header files using trace macros. +# + +c_pathname_pat = re.compile('^.*\.[ch]$', re.IGNORECASE) +trace_use_pat = re.compile('^[ \t]*#define[ \t]+FT_COMPONENT[ \t]+') + +for d in SRC_FILE_DIRS: + for (p, dlst, flst) in os.walk(d): + for f in flst: + if c_pathname_pat.match(f) is not None: + src_pathname = os.path.join(p, f) + + line_num = 0 + for src_line in open(src_pathname, 'r'): + line_num = line_num + 1 + src_line = src_line.strip() + if trace_use_pat.match(src_line) is not None: + component_name = trace_use_pat.sub('', src_line) + if component_name in USED_COMPONENT: + USED_COMPONENT[component_name]\ + .append("%s:%d" % (src_pathname, line_num)) + else: + USED_COMPONENT[component_name] =\ + ["%s:%d" % (src_pathname, line_num)] + +# -------------------------------------------------------------- +# Scan header file(s) defining trace macros. +# + +trace_def_pat_opn = re.compile('^.*FT_TRACE_DEF[ \t]*\([ \t]*') +trace_def_pat_cls = re.compile('[ \t\)].*$') + +for f in TRACE_DEF_FILES: + line_num = 0 + for hdr_line in open(f, 'r'): + line_num = line_num + 1 + hdr_line = hdr_line.strip() + if trace_def_pat_opn.match(hdr_line) is not None: + component_name = trace_def_pat_opn.sub('', hdr_line) + component_name = trace_def_pat_cls.sub('', component_name) + if component_name in KNOWN_COMPONENT: + print("trace component %s is defined twice," + " see %s and fttrace.h:%d" % + (component_name, KNOWN_COMPONENT[component_name], + line_num)) + else: + KNOWN_COMPONENT[component_name] =\ + "%s:%d" % (os.path.basename(f), line_num) + +# -------------------------------------------------------------- +# Compare the used and defined trace macros. +# + +print("# Trace component used in the implementations but not defined in " + "fttrace.h.") +cmpnt = list(USED_COMPONENT.keys()) +cmpnt.sort() +for c in cmpnt: + if c not in KNOWN_COMPONENT: + print("Trace component %s (used in %s) is not defined." % + (c, ", ".join(USED_COMPONENT[c]))) + +print("# Trace component is defined but not used in the implementations.") +cmpnt = list(KNOWN_COMPONENT.keys()) +cmpnt.sort() +for c in cmpnt: + if c not in USED_COMPONENT: + if c != "any": + print("Trace component %s (defined in %s) is not used." % + (c, KNOWN_COMPONENT[c])) diff --git a/Dependencies/freetype/freetype/src/tools/cordic.py b/Dependencies/freetype/freetype/src/tools/cordic.py new file mode 100644 index 00000000..65114298 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/cordic.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# compute arctangent table for CORDIC computations in fttrigon.c +import math + +# units = 64*65536.0 # don't change !! +units = 180 * 2 ** 16 +scale = units / math.pi +shrink = 1.0 +angles2 = [] + +print("") +print("table of arctan( 1/2^n ) for PI = " + repr(units / 65536.0) + " units") + +for n in range(1, 32): + + x = 0.5 ** n # tangent value + + angle = math.atan(x) # arctangent + angle2 = round(angle * scale) # arctangent in FT_Angle units + + if angle2 <= 0: + break + + angles2.append(repr(int(angle2))) + shrink /= math.sqrt(1 + x * x) + +print(", ".join(angles2)) +print("shrink factor = " + repr(shrink)) +print("shrink factor 2 = " + repr(int(shrink * (2 ** 32)))) +print("expansion factor = " + repr(1 / shrink)) +print("") diff --git a/Dependencies/freetype/freetype/src/tools/ftrandom/Makefile b/Dependencies/freetype/freetype/src/tools/ftrandom/Makefile new file mode 100644 index 00000000..24dc49c5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/ftrandom/Makefile @@ -0,0 +1,45 @@ +# TOP_DIR and OBJ_DIR should be set by the user to the right directories, +# if necessary. + +TOP_DIR ?= ../../.. +OBJ_DIR ?= $(TOP_DIR)/objs + + +# The setup below is for gcc on a Unix-like platform, +# where FreeType has been set up to create a static library +# (which is the default). + +VPATH = $(OBJ_DIR) \ + $(OBJ_DIR)/.libs + +SRC_DIR = $(TOP_DIR)/src/tools/ftrandom + +CC = gcc +WFLAGS = -Wmissing-prototypes \ + -Wunused \ + -Wimplicit \ + -Wreturn-type \ + -Wparentheses \ + -pedantic \ + -Wformat \ + -Wchar-subscripts \ + -Wsequence-point +CFLAGS = $(WFLAGS) \ + -g +INCLUDES = -I $(TOP_DIR)/include +LDFLAGS = +LIBS = -lm \ + -lz \ + -lpng \ + -lbz2 \ + -lharfbuzz + +all: $(OBJ_DIR)/ftrandom + +$(OBJ_DIR)/ftrandom.o: $(SRC_DIR)/ftrandom.c + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +$(OBJ_DIR)/ftrandom: $(OBJ_DIR)/ftrandom.o libfreetype.a + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +# EOF diff --git a/Dependencies/freetype/freetype/src/tools/ftrandom/README b/Dependencies/freetype/freetype/src/tools/ftrandom/README new file mode 100644 index 00000000..7c610864 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/ftrandom/README @@ -0,0 +1,69 @@ +ftrandom +======== + +This program expects a set of directories containing good fonts, and a set +of extensions of fonts to be tested. It will randomly pick a font, copy it, +introduce an error and then test it. + +The FreeType tests are quite basic; for each erroneous font ftrandom + + . forks off a new tester, + . initializes the library, + . opens each font in the file, + . loads each glyph, + . optionally reviews the contours of the glyph, + . optionally rasterizes the glyph, and + . closes the face. + +If a tester takes longer than 20 seconds, ftrandom saves the erroneous font +and continues. If the tester exits normally or with an error, then the +superstructure removes the test font and continues. + + +Command line options +-------------------- + + --all Test every font in the directory(ies) no matter + what its extension. + --check-outlines Call `FT_Outline_Decompose' on each glyph. + --dir Append to the list of directories to search + for good fonts. No recursive search. + --error-count Introduce single-byte errors into the + erroneous fonts (default: 1). + --error-fraction Multiply the file size of the font by and + introduce that many errors into the erroneous + font file. should be in the range [0;1] + (default: 0.0). + --ext Add to the set of font types tested. + --help Print out this list of options. + --nohints Specify FT_LOAD_NO_HINTING when loading glyphs. + --rasterize Call `FT_Render_Glyph' as well as loading it. + --result This is the directory in which test files are + placed. + --test Run a single test on a pre-generated testcase. + This is done in the current process so it can be + debugged more easily. + +The default font extensions tested by ftrandom are + + .ttf .otf .ttc .cid .pfb .pfa .bdf .pcf .pfr .fon .otb .cff + +The default font directory is controlled by the macro `GOOD_FONTS_DIR' in +the source code (and can be thus specified during compilation); its default +value is + + /usr/local/share/fonts + +The default result directory is `results' (in the current directory). + + +Compilation +----------- + +Two possible solutions. + +. Run ftrandom within a debugging tool like `valgrind' to catch various + memory issues. + +. Compile FreeType with sanitizer flags as provided by gcc or clang, for + example, then link it with ftrandom. diff --git a/Dependencies/freetype/freetype/src/tools/ftrandom/ftrandom.c b/Dependencies/freetype/freetype/src/tools/ftrandom/ftrandom.c new file mode 100644 index 00000000..0ee765e5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/ftrandom/ftrandom.c @@ -0,0 +1,720 @@ +/* Copyright (C) 2005, 2007, 2008, 2013 by George Williams */ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* modified by Werner Lemberg */ +/* This file is now part of the FreeType library */ + + +#define _XOPEN_SOURCE 600 /* for `kill', `strdup', `random', and `srandom' */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define true 1 +#define false 0 +#define forever for (;;) + + + static int check_outlines = false; + static int nohints = false; + static int rasterize = false; + static char* results_dir = "results"; + +#define GOOD_FONTS_DIR "/usr/local/share/fonts" + + static char* default_dir_list[] = + { + GOOD_FONTS_DIR, + NULL + }; + + static char* default_ext_list[] = + { + "ttf", + "otf", + "ttc", + "cid", + "pfb", + "pfa", + "bdf", + "pcf", + "pfr", + "fon", + "otb", + "cff", + NULL + }; + + static unsigned int error_count = 1; + static double error_fraction = 0.0; + + static FT_F26Dot6 font_size = 12 * 64; + + static struct fontlist + { + char* name; + long len; + unsigned int isbinary: 1; + unsigned int isascii: 1; + unsigned int ishex: 1; + + } *fontlist; + + static unsigned int fcnt; + + + static int + FT_MoveTo( const FT_Vector *to, + void *user ) + { + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_LineTo( const FT_Vector *to, + void *user ) + { + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_ConicTo( const FT_Vector *_cp, + const FT_Vector *to, + void *user ) + { + FT_UNUSED( _cp ); + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static int + FT_CubicTo( const FT_Vector *cp1, + const FT_Vector *cp2, + const FT_Vector *to, + void *user ) + { + FT_UNUSED( cp1 ); + FT_UNUSED( cp2 ); + FT_UNUSED( to ); + FT_UNUSED( user ); + + return 0; + } + + + static FT_Outline_Funcs outlinefuncs = + { + FT_MoveTo, + FT_LineTo, + FT_ConicTo, + FT_CubicTo, + 0, 0 /* No shift, no delta */ + }; + + + static void + TestFace( FT_Face face ) + { + unsigned int gid; + int load_flags = FT_LOAD_DEFAULT; + + + if ( check_outlines && + FT_IS_SCALABLE( face ) ) + load_flags = FT_LOAD_NO_BITMAP; + + if ( nohints ) + load_flags |= FT_LOAD_NO_HINTING; + + FT_Set_Char_Size( face, 0, font_size, 72, 72 ); + + for ( gid = 0; gid < face->num_glyphs; gid++ ) + { + if ( check_outlines && + FT_IS_SCALABLE( face ) ) + { + if ( !FT_Load_Glyph( face, gid, load_flags ) ) + FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL ); + } + else + FT_Load_Glyph( face, gid, load_flags ); + + if ( rasterize ) + FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + } + + FT_Done_Face( face ); + } + + + static void + ExecuteTest( char* testfont ) + { + FT_Library context; + FT_Face face; + + + if ( FT_Init_FreeType( &context ) ) + { + fprintf( stderr, "Can't initialize FreeType.\n" ); + exit( 1 ); + } + + if ( FT_New_Face( context, testfont, 0, &face ) ) + { + /* The font is erroneous, so if this fails that's ok. */ + exit( 0 ); + } + + if ( face->num_faces == 1 ) + TestFace( face ); + else + { + long i, num; + + + num = face->num_faces; + FT_Done_Face( face ); + + for ( i = 0; i < num; i++ ) + { + if ( !FT_New_Face( context, testfont, i, &face ) ) + TestFace( face ); + } + } + + FT_Done_FreeType( context ); + + exit( 0 ); + } + + + static int + extmatch( char* filename, + char** extensions ) + { + int i; + char* pt; + + + if ( !extensions ) + return true; + + pt = strrchr( filename, '.' ); + if ( !pt ) + return false; + if ( pt < strrchr( filename, '/' ) ) + return false; + + for ( i = 0; extensions[i] != NULL; i++ ) + if ( strcasecmp( pt + 1, extensions[i] ) == 0 || + strcasecmp( pt, extensions[i] ) == 0 ) + return true; + + return false; + } + + + static void + figurefiletype( struct fontlist* item ) + { + FILE* foo; + + + item->isbinary = item->isascii = item->ishex = false; + + foo = fopen( item->name, "rb" ); + if ( foo ) + { + /* Try to guess the file type from the first few characters... */ + int ch1 = getc( foo ); + int ch2 = getc( foo ); + int ch3 = getc( foo ); + int ch4 = getc( foo ); + + + fclose( foo ); + + if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) || + ( ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O' ) || + ( ch1 == 't' && ch2 == 'r' && ch3 == 'u' && ch4 == 'e' ) || + ( ch1 == 't' && ch2 == 't' && ch3 == 'c' && ch4 == 'f' ) ) + { + /* ttf, otf, ttc files */ + item->isbinary = true; + } + else if ( ch1 == 0x80 && ch2 == '\01' ) + { + /* PFB header */ + item->isbinary = true; + } + else if ( ch1 == '%' && ch2 == '!' ) + { + /* Random PostScript */ + if ( strstr( item->name, ".pfa" ) || + strstr( item->name, ".PFA" ) ) + item->ishex = true; + else + item->isascii = true; + } + else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 ) + { + /* Bare CFF */ + item->isbinary = true; + } + else if ( ch1 == 'S' && ch2 == 'T' && ch3 == 'A' && ch4 == 'R' ) + { + /* BDF */ + item->ishex = true; + } + else if ( ch1 == 'P' && ch2 == 'F' && ch3 == 'R' && ch4 == '0' ) + { + /* PFR */ + item->isbinary = true; + } + else if ( ( ch1 == '\1' && ch2 == 'f' && ch3 == 'c' && ch4 == 'p' ) || + ( ch1 == 'M' && ch2 == 'Z' ) ) + { + /* Windows FON */ + item->isbinary = true; + } + else + { + fprintf( stderr, + "Can't recognize file type of `%s', assuming binary\n", + item->name ); + item->isbinary = true; + } + } + else + { + fprintf( stderr, "Can't open `%s' for typing the file.\n", + item->name ); + item->isbinary = true; + } + } + + + static void + FindFonts( char** fontdirs, + char** extensions ) + { + int i; + unsigned int max; + char buffer[1025]; + struct stat statb; + + + max = 0; + fcnt = 0; + + for ( i = 0; fontdirs[i] != NULL; i++ ) + { + DIR* examples; + struct dirent* ent; + + + examples = opendir( fontdirs[i] ); + if ( !examples ) + { + fprintf( stderr, + "Can't open example font directory `%s'\n", + fontdirs[i] ); + exit( 1 ); + } + + while ( ( ent = readdir( examples ) ) != NULL ) + { + snprintf( buffer, sizeof ( buffer ), + "%s/%s", fontdirs[i], ent->d_name ); + if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) ) + continue; + if ( !extensions || extmatch( buffer, extensions ) ) + { + if ( fcnt >= max ) + { + max += 100; + fontlist = realloc( fontlist, max * sizeof ( struct fontlist ) ); + if ( !fontlist ) + { + fprintf( stderr, "Can't allocate memory\n" ); + exit( 1 ); + } + } + + fontlist[fcnt].name = strdup( buffer ); + fontlist[fcnt].len = statb.st_size; + + figurefiletype( &fontlist[fcnt] ); + fcnt++; + } + } + + closedir( examples ); + } + + if ( fcnt == 0 ) + { + fprintf( stderr, "Can't find matching font files.\n" ); + exit( 1 ); + } + + fontlist[fcnt].name = NULL; + } + + + static unsigned int + getErrorCnt( struct fontlist* item ) + { + if ( error_count == 0 && error_fraction == 0.0 ) + return 0; + + return error_count + (unsigned int)( error_fraction * item->len ); + } + + + static int + getRandom( int low, + int high ) + { + if ( low - high < 0x10000L ) + return low + ( ( random() >> 8 ) % ( high + 1 - low ) ); + + return low + ( random() % ( high + 1 - low ) ); + } + + + static int + copyfont( struct fontlist* item, + char* newfont ) + { + static char buffer[8096]; + FILE *good, *newf; + size_t len; + unsigned int i, err_cnt; + + + good = fopen( item->name, "r" ); + if ( !good ) + { + fprintf( stderr, "Can't open `%s'\n", item->name ); + return false; + } + + newf = fopen( newfont, "w+" ); + if ( !newf ) + { + fprintf( stderr, "Can't create temporary output file `%s'\n", + newfont ); + exit( 1 ); + } + + while ( ( len = fread( buffer, 1, sizeof ( buffer ), good ) ) > 0 ) + fwrite( buffer, 1, len, newf ); + + fclose( good ); + + err_cnt = getErrorCnt( item ); + for ( i = 0; i < err_cnt; i++ ) + { + fseek( newf, getRandom( 0, (int)( item->len - 1 ) ), SEEK_SET ); + + if ( item->isbinary ) + putc( getRandom( 0, 0xFF ), newf ); + else if ( item->isascii ) + putc( getRandom( 0x20, 0x7E ), newf ); + else + { + int hex = getRandom( 0, 15 ); + + + if ( hex < 10 ) + hex += '0'; + else + hex += 'A' - 10; + + putc( hex, newf ); + } + } + + if ( ferror( newf ) ) + { + fclose( newf ); + unlink( newfont ); + return false; + } + + fclose( newf ); + + return true; + } + + + static int child_pid; + + static void + abort_test( int sig ) + { + FT_UNUSED( sig ); + + /* If a time-out happens, then kill the child */ + kill( child_pid, SIGFPE ); + write( 2, "Timeout... ", 11 ); + } + + + static void + do_test( void ) + { + int i = getRandom( 0, (int)( fcnt - 1 ) ); + static int test_num = 0; + char buffer[1024]; + + + snprintf( buffer, 1024, "%s/test%d", results_dir, test_num++ ); + + if ( copyfont ( &fontlist[i], buffer ) ) + { + signal( SIGALRM, abort_test ); + /* Anything that takes more than 20 seconds */ + /* to parse and/or rasterize is an error. */ + alarm( 20 ); + if ( ( child_pid = fork() ) == 0 ) + ExecuteTest( buffer ); + else if ( child_pid != -1 ) + { + int status; + + + waitpid( child_pid, &status, 0 ); + alarm( 0 ); + if ( WIFSIGNALED ( status ) ) + printf( "Error found in file `%s'\n", buffer ); + else + unlink( buffer ); + } + else + { + fprintf( stderr, "Can't fork test case.\n" ); + exit( 1 ); + } + alarm( 0 ); + } + } + + + static void + usage( FILE* out, + char* name ) + { + char** d = default_dir_list; + char** e = default_ext_list; + + + fprintf( out, "%s [options] -- Generate random erroneous fonts\n" + " and attempt to parse them with FreeType.\n\n", name ); + + fprintf( out, " --all All non-directory files are assumed to be fonts.\n" ); + fprintf( out, " --check-outlines Make sure we can parse the outlines of each glyph.\n" ); + fprintf( out, " --dir Append to list of font search directories\n" + " (no recursive search).\n" ); + fprintf( out, " --error-count Introduce single byte errors into each font\n" + " (default: 1)\n" ); + fprintf( out, " --error-fraction Introduce *filesize single byte errors\n" + " into each font (default: 0.0).\n" ); + fprintf( out, " --ext Add to list of extensions indicating fonts.\n" ); + fprintf( out, " --help Print this.\n" ); + fprintf( out, " --nohints Turn off hinting.\n" ); + fprintf( out, " --rasterize Attempt to rasterize each glyph.\n" ); + fprintf( out, " --results Place the created test fonts into \n" + " (default: `results')\n" ); + fprintf( out, " --size Use the given font size for the tests.\n" ); + fprintf( out, " --test Run a single test on an already existing file.\n" ); + fprintf( out, "\n" ); + + fprintf( out, "Default font extensions:\n" ); + fprintf( out, " " ); + while ( *e ) + fprintf( out, " .%s", *e++ ); + fprintf( out, "\n" ); + + fprintf( out, "Default font directories:\n" ); + fprintf( out, " " ); + while ( *d ) + fprintf( out, " %s", *d++ ); + fprintf( out, "\n" ); + } + + + int + main( int argc, + char** argv ) + { + char **dirs, **exts; + int dcnt = 0, ecnt = 0, rset = false, allexts = false; + int i; + time_t now; + char* testfile = NULL; + + + dirs = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) ); + exts = calloc( (size_t)( argc + 1 ), sizeof ( char ** ) ); + + for ( i = 1; i < argc; i++ ) + { + char* pt = argv[i]; + char* end; + + + if ( pt[0] == '-' && pt[1] == '-' ) + pt++; + + if ( strcmp( pt, "-all" ) == 0 ) + allexts = true; + else if ( strcmp( pt, "-check-outlines" ) == 0 ) + check_outlines = true; + else if ( strcmp( pt, "-dir" ) == 0 ) + dirs[dcnt++] = argv[++i]; + else if ( strcmp( pt, "-error-count" ) == 0 ) + { + if ( !rset ) + error_fraction = 0.0; + rset = true; + error_count = (unsigned int)strtoul( argv[++i], &end, 10 ); + if ( *end != '\0' ) + { + fprintf( stderr, "Bad value for error-count: %s\n", argv[i] ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-error-fraction" ) == 0 ) + { + if ( !rset ) + error_count = 0; + rset = true; + error_fraction = strtod( argv[++i], &end ); + if ( *end != '\0' ) + { + fprintf( stderr, "Bad value for error-fraction: %s\n", argv[i] ); + exit( 1 ); + } + if ( error_fraction < 0.0 || error_fraction > 1.0 ) + { + fprintf( stderr, "error-fraction must be in the range [0;1]\n" ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-ext" ) == 0 ) + exts[ecnt++] = argv[++i]; + else if ( strcmp( pt, "-help" ) == 0 ) + { + usage( stdout, argv[0] ); + exit( 0 ); + } + else if ( strcmp( pt, "-nohints" ) == 0 ) + nohints = true; + else if ( strcmp( pt, "-rasterize" ) == 0 ) + rasterize = true; + else if ( strcmp( pt, "-results" ) == 0 ) + results_dir = argv[++i]; + else if ( strcmp( pt, "-size" ) == 0 ) + { + font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 ); + if ( *end != '\0' || font_size < 64 ) + { + fprintf( stderr, "Bad value for size: %s\n", argv[i] ); + exit( 1 ); + } + } + else if ( strcmp( pt, "-test" ) == 0 ) + testfile = argv[++i]; + else + { + usage( stderr, argv[0] ); + exit( 1 ); + } + } + + if ( allexts ) + { + free( exts ); + exts = NULL; + } + else if ( ecnt == 0 ) + { + free( exts ); + exts = default_ext_list; + } + + if ( dcnt == 0 ) + { + free( dirs ); + dirs = default_dir_list; + } + + if ( testfile ) + ExecuteTest( testfile ); /* This should never return */ + + time( &now ); + srandom( (unsigned int)now ); + + FindFonts( dirs, exts ); + mkdir( results_dir, 0755 ); + + forever + do_test(); + + return 0; + } + + +/* EOF */ diff --git a/Dependencies/freetype/freetype/src/tools/glnames.py b/Dependencies/freetype/freetype/src/tools/glnames.py new file mode 100644 index 00000000..0b6d8247 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/glnames.py @@ -0,0 +1,5533 @@ +#!/usr/bin/env python3 + +# +# FreeType 2 glyph name builder +# +# Copyright (C) 1996-2024 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +""" +usage: %s + + This python script generates the glyph names tables defined in the + `psnames' module. + + Its single argument is the name of the header file to be created. +""" + +import os.path +import struct +import sys + +# This table lists the glyphs according to the Macintosh specification. +# It is used by the TrueType Postscript names table. +# +# See +# +# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html +# +# for the official list. +# +mac_standard_names = [ + # 0 + ".notdef", ".null", "nonmarkingreturn", "space", "exclam", + "quotedbl", "numbersign", "dollar", "percent", "ampersand", + + # 10 + "quotesingle", "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", "zero", + + # 20 + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "colon", + + # 30 + "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", + + # 40 + "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", + + # 50 + "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", + + # 60 + "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "grave", "a", "b", + + # 70 + "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", + + # 80 + "m", "n", "o", "p", "q", + "r", "s", "t", "u", "v", + + # 90 + "w", "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", "Adieresis", "Aring", + + # 100 + "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", + "aacute", "agrave", "acircumflex", "adieresis", "atilde", + + # 110 + "aring", "ccedilla", "eacute", "egrave", "ecircumflex", + "edieresis", "iacute", "igrave", "icircumflex", "idieresis", + + # 120 + "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", + "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", + + # 130 + "dagger", "degree", "cent", "sterling", "section", + "bullet", "paragraph", "germandbls", "registered", "copyright", + + # 140 + "trademark", "acute", "dieresis", "notequal", "AE", + "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", + + # 150 + "yen", "mu", "partialdiff", "summation", "product", + "pi", "integral", "ordfeminine", "ordmasculine", "Omega", + + # 160 + "ae", "oslash", "questiondown", "exclamdown", "logicalnot", + "radical", "florin", "approxequal", "Delta", "guillemotleft", + + # 170 + "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", + "Otilde", "OE", "oe", "endash", "emdash", + + # 180 + "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", + "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", + + # 190 + "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", + "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", + "Acircumflex", + + # 200 + "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", + "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", + + # 210 + "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", + "dotlessi", "circumflex", "tilde", "macron", "breve", + + # 220 + "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", + "caron", "Lslash", "lslash", "Scaron", "scaron", + + # 230 + "Zcaron", "zcaron", "brokenbar", "Eth", "eth", + "Yacute", "yacute", "Thorn", "thorn", "minus", + + # 240 + "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", + "onequarter", "threequarters", "franc", "Gbreve", "gbreve", + + # 250 + "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", + "Ccaron", "ccaron", "dcroat" +] + +# The list of standard `SID' glyph names. For the official list, +# see Annex A of document at +# +# https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf +# +sid_standard_names = [ + # 0 + ".notdef", "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quoteright", "parenleft", + + # 10 + "parenright", "asterisk", "plus", "comma", "hyphen", + "period", "slash", "zero", "one", "two", + + # 20 + "three", "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", "less", + + # 30 + "equal", "greater", "question", "at", "A", + "B", "C", "D", "E", "F", + + # 40 + "G", "H", "I", "J", "K", + "L", "M", "N", "O", "P", + + # 50 + "Q", "R", "S", "T", "U", + "V", "W", "X", "Y", "Z", + + # 60 + "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", + "quoteleft", "a", "b", "c", "d", + + # 70 + "e", "f", "g", "h", "i", + "j", "k", "l", "m", "n", + + # 80 + "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", + + # 90 + "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "exclamdown", "cent", "sterling", "fraction", + + # 100 + "yen", "florin", "section", "currency", "quotesingle", + "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", + + # 110 + "fl", "endash", "dagger", "daggerdbl", "periodcentered", + "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", + + # 120 + "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", + "acute", "circumflex", "tilde", "macron", "breve", + + # 130 + "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", + "ogonek", "caron", "emdash", "AE", "ordfeminine", + + # 140 + "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "lslash", "oslash", "oe", "germandbls", + + # 150 + "onesuperior", "logicalnot", "mu", "trademark", "Eth", + "onehalf", "plusminus", "Thorn", "onequarter", "divide", + + # 160 + "brokenbar", "degree", "thorn", "threequarters", "twosuperior", + "registered", "minus", "eth", "multiply", "threesuperior", + + # 170 + "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", + "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", + + # 180 + "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", + "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", + + # 190 + "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", + "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", + + # 200 + "aacute", "acircumflex", "adieresis", "agrave", "aring", + "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", + + # 210 + "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", + + # 220 + "otilde", "scaron", "uacute", "ucircumflex", "udieresis", + "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + + # 230 + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", + "Acutesmall", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", + + # 240 + "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", + "fiveoldstyle", + "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", + "commasuperior", + + # 250 + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", + "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", + + # 260 + "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", + "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + + # 270 + "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", + "Asmall", + "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", + + # 280 + "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", + "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", + + # 290 + "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", + "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", + + # 300 + "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", + "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", + "Dieresissmall", + + # 310 + "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", + "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", + "questiondownsmall", + + # 320 + "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", + "twothirds", "zerosuperior", "foursuperior", "fivesuperior", + "sixsuperior", + + # 330 + "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", + "oneinferior", + "twoinferior", "threeinferior", "fourinferior", "fiveinferior", + "sixinferior", + + # 340 + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", + "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", + "Acircumflexsmall", + + # 350 + "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", + "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", + "Igravesmall", + + # 360 + "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", + "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", + + # 370 + "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", + "Ucircumflexsmall", + "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", + "001.000", + + # 380 + "001.001", "001.002", "001.003", "Black", "Bold", + "Book", "Light", "Medium", "Regular", "Roman", + + # 390 + "Semibold" +] + +# This table maps character codes of the Adobe Standard Type 1 +# encoding to glyph indices in the sid_standard_names table. +# +t1_standard_encoding = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, + 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, + 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, + + 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, + 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, + + 148, 149, 0, 0, 0, 0 +] + +# This table maps character codes of the Adobe Expert Type 1 +# encoding to glyph indices in the sid_standard_names table. +# +t1_expert_encoding = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, + + 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, + 0, 0, 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, 110, 267, + 268, 269, 0, 270, 271, 272, 273, 274, 275, 276, + + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, 309, 310, + 311, 0, 312, 0, 0, 313, 0, 0, 314, 315, + 0, 0, 316, 317, 318, 0, 0, 0, 158, 155, + 163, 319, 320, 321, 322, 323, 324, 325, 0, 0, + + 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + + 373, 374, 375, 376, 377, 378 +] + +# This data has been taken literally from the files `glyphlist.txt' +# and `zapfdingbats.txt' version 2.0, Sept 2002. It is available from +# +# https://github.com/adobe-type-tools/agl-aglfn +# +adobe_glyph_list = """\ +A;0041 +AE;00C6 +AEacute;01FC +AEmacron;01E2 +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Abreveacute;1EAE +Abrevecyrillic;04D0 +Abrevedotbelow;1EB6 +Abrevegrave;1EB0 +Abrevehookabove;1EB2 +Abrevetilde;1EB4 +Acaron;01CD +Acircle;24B6 +Acircumflex;00C2 +Acircumflexacute;1EA4 +Acircumflexdotbelow;1EAC +Acircumflexgrave;1EA6 +Acircumflexhookabove;1EA8 +Acircumflexsmall;F7E2 +Acircumflextilde;1EAA +Acute;F6C9 +Acutesmall;F7B4 +Acyrillic;0410 +Adblgrave;0200 +Adieresis;00C4 +Adieresiscyrillic;04D2 +Adieresismacron;01DE +Adieresissmall;F7E4 +Adotbelow;1EA0 +Adotmacron;01E0 +Agrave;00C0 +Agravesmall;F7E0 +Ahookabove;1EA2 +Aiecyrillic;04D4 +Ainvertedbreve;0202 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Amonospace;FF21 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringbelow;1E00 +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +Aybarmenian;0531 +B;0042 +Bcircle;24B7 +Bdotaccent;1E02 +Bdotbelow;1E04 +Becyrillic;0411 +Benarmenian;0532 +Beta;0392 +Bhook;0181 +Blinebelow;1E06 +Bmonospace;FF22 +Brevesmall;F6F4 +Bsmall;F762 +Btopbar;0182 +C;0043 +Caarmenian;053E +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillaacute;1E08 +Ccedillasmall;F7E7 +Ccircle;24B8 +Ccircumflex;0108 +Cdot;010A +Cdotaccent;010A +Cedillasmall;F7B8 +Chaarmenian;0549 +Cheabkhasiancyrillic;04BC +Checyrillic;0427 +Chedescenderabkhasiancyrillic;04BE +Chedescendercyrillic;04B6 +Chedieresiscyrillic;04F4 +Cheharmenian;0543 +Chekhakassiancyrillic;04CB +Cheverticalstrokecyrillic;04B8 +Chi;03A7 +Chook;0187 +Circumflexsmall;F6F6 +Cmonospace;FF23 +Coarmenian;0551 +Csmall;F763 +D;0044 +DZ;01F1 +DZcaron;01C4 +Daarmenian;0534 +Dafrican;0189 +Dcaron;010E +Dcedilla;1E10 +Dcircle;24B9 +Dcircumflexbelow;1E12 +Dcroat;0110 +Ddotaccent;1E0A +Ddotbelow;1E0C +Decyrillic;0414 +Deicoptic;03EE +Delta;2206 +Deltagreek;0394 +Dhook;018A +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Digammagreek;03DC +Djecyrillic;0402 +Dlinebelow;1E0E +Dmonospace;FF24 +Dotaccentsmall;F6F7 +Dslash;0110 +Dsmall;F764 +Dtopbar;018B +Dz;01F2 +Dzcaron;01C5 +Dzeabkhasiancyrillic;04E0 +Dzecyrillic;0405 +Dzhecyrillic;040F +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecedillabreve;1E1C +Echarmenian;0535 +Ecircle;24BA +Ecircumflex;00CA +Ecircumflexacute;1EBE +Ecircumflexbelow;1E18 +Ecircumflexdotbelow;1EC6 +Ecircumflexgrave;1EC0 +Ecircumflexhookabove;1EC2 +Ecircumflexsmall;F7EA +Ecircumflextilde;1EC4 +Ecyrillic;0404 +Edblgrave;0204 +Edieresis;00CB +Edieresissmall;F7EB +Edot;0116 +Edotaccent;0116 +Edotbelow;1EB8 +Efcyrillic;0424 +Egrave;00C8 +Egravesmall;F7E8 +Eharmenian;0537 +Ehookabove;1EBA +Eightroman;2167 +Einvertedbreve;0206 +Eiotifiedcyrillic;0464 +Elcyrillic;041B +Elevenroman;216A +Emacron;0112 +Emacronacute;1E16 +Emacrongrave;1E14 +Emcyrillic;041C +Emonospace;FF25 +Encyrillic;041D +Endescendercyrillic;04A2 +Eng;014A +Enghecyrillic;04A4 +Enhookcyrillic;04C7 +Eogonek;0118 +Eopen;0190 +Epsilon;0395 +Epsilontonos;0388 +Ercyrillic;0420 +Ereversed;018E +Ereversedcyrillic;042D +Escyrillic;0421 +Esdescendercyrillic;04AA +Esh;01A9 +Esmall;F765 +Eta;0397 +Etarmenian;0538 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Etilde;1EBC +Etildebelow;1E1A +Euro;20AC +Ezh;01B7 +Ezhcaron;01EE +Ezhreversed;01B8 +F;0046 +Fcircle;24BB +Fdotaccent;1E1E +Feharmenian;0556 +Feicoptic;03E4 +Fhook;0191 +Fitacyrillic;0472 +Fiveroman;2164 +Fmonospace;FF26 +Fourroman;2163 +Fsmall;F766 +G;0047 +GBsquare;3387 +Gacute;01F4 +Gamma;0393 +Gammaafrican;0194 +Gangiacoptic;03EA +Gbreve;011E +Gcaron;01E6 +Gcedilla;0122 +Gcircle;24BC +Gcircumflex;011C +Gcommaaccent;0122 +Gdot;0120 +Gdotaccent;0120 +Gecyrillic;0413 +Ghadarmenian;0542 +Ghemiddlehookcyrillic;0494 +Ghestrokecyrillic;0492 +Gheupturncyrillic;0490 +Ghook;0193 +Gimarmenian;0533 +Gjecyrillic;0403 +Gmacron;1E20 +Gmonospace;FF27 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +Gsmallhook;029B +Gstroke;01E4 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +HPsquare;33CB +Haabkhasiancyrillic;04A8 +Hadescendercyrillic;04B2 +Hardsigncyrillic;042A +Hbar;0126 +Hbrevebelow;1E2A +Hcedilla;1E28 +Hcircle;24BD +Hcircumflex;0124 +Hdieresis;1E26 +Hdotaccent;1E22 +Hdotbelow;1E24 +Hmonospace;FF28 +Hoarmenian;0540 +Horicoptic;03E8 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +Hzsquare;3390 +I;0049 +IAcyrillic;042F +IJ;0132 +IUcyrillic;042E +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icaron;01CF +Icircle;24BE +Icircumflex;00CE +Icircumflexsmall;F7EE +Icyrillic;0406 +Idblgrave;0208 +Idieresis;00CF +Idieresisacute;1E2E +Idieresiscyrillic;04E4 +Idieresissmall;F7EF +Idot;0130 +Idotaccent;0130 +Idotbelow;1ECA +Iebrevecyrillic;04D6 +Iecyrillic;0415 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Ihookabove;1EC8 +Iicyrillic;0418 +Iinvertedbreve;020A +Iishortcyrillic;0419 +Imacron;012A +Imacroncyrillic;04E2 +Imonospace;FF29 +Iniarmenian;053B +Iocyrillic;0401 +Iogonek;012E +Iota;0399 +Iotaafrican;0196 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Istroke;0197 +Itilde;0128 +Itildebelow;1E2C +Izhitsacyrillic;0474 +Izhitsadblgravecyrillic;0476 +J;004A +Jaarmenian;0541 +Jcircle;24BF +Jcircumflex;0134 +Jecyrillic;0408 +Jheharmenian;054B +Jmonospace;FF2A +Jsmall;F76A +K;004B +KBsquare;3385 +KKsquare;33CD +Kabashkircyrillic;04A0 +Kacute;1E30 +Kacyrillic;041A +Kadescendercyrillic;049A +Kahookcyrillic;04C3 +Kappa;039A +Kastrokecyrillic;049E +Kaverticalstrokecyrillic;049C +Kcaron;01E8 +Kcedilla;0136 +Kcircle;24C0 +Kcommaaccent;0136 +Kdotbelow;1E32 +Keharmenian;0554 +Kenarmenian;053F +Khacyrillic;0425 +Kheicoptic;03E6 +Khook;0198 +Kjecyrillic;040C +Klinebelow;1E34 +Kmonospace;FF2B +Koppacyrillic;0480 +Koppagreek;03DE +Ksicyrillic;046E +Ksmall;F76B +L;004C +LJ;01C7 +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcedilla;013B +Lcircle;24C1 +Lcircumflexbelow;1E3C +Lcommaaccent;013B +Ldot;013F +Ldotaccent;013F +Ldotbelow;1E36 +Ldotbelowmacron;1E38 +Liwnarmenian;053C +Lj;01C8 +Ljecyrillic;0409 +Llinebelow;1E3A +Lmonospace;FF2C +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +MBsquare;3386 +Macron;F6D0 +Macronsmall;F7AF +Macute;1E3E +Mcircle;24C2 +Mdotaccent;1E40 +Mdotbelow;1E42 +Menarmenian;0544 +Mmonospace;FF2D +Msmall;F76D +Mturned;019C +Mu;039C +N;004E +NJ;01CA +Nacute;0143 +Ncaron;0147 +Ncedilla;0145 +Ncircle;24C3 +Ncircumflexbelow;1E4A +Ncommaaccent;0145 +Ndotaccent;1E44 +Ndotbelow;1E46 +Nhookleft;019D +Nineroman;2168 +Nj;01CB +Njecyrillic;040A +Nlinebelow;1E48 +Nmonospace;FF2E +Nowarmenian;0546 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obarredcyrillic;04E8 +Obarreddieresiscyrillic;04EA +Obreve;014E +Ocaron;01D1 +Ocenteredtilde;019F +Ocircle;24C4 +Ocircumflex;00D4 +Ocircumflexacute;1ED0 +Ocircumflexdotbelow;1ED8 +Ocircumflexgrave;1ED2 +Ocircumflexhookabove;1ED4 +Ocircumflexsmall;F7F4 +Ocircumflextilde;1ED6 +Ocyrillic;041E +Odblacute;0150 +Odblgrave;020C +Odieresis;00D6 +Odieresiscyrillic;04E6 +Odieresissmall;F7F6 +Odotbelow;1ECC +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Oharmenian;0555 +Ohm;2126 +Ohookabove;1ECE +Ohorn;01A0 +Ohornacute;1EDA +Ohorndotbelow;1EE2 +Ohorngrave;1EDC +Ohornhookabove;1EDE +Ohorntilde;1EE0 +Ohungarumlaut;0150 +Oi;01A2 +Oinvertedbreve;020E +Omacron;014C +Omacronacute;1E52 +Omacrongrave;1E50 +Omega;2126 +Omegacyrillic;0460 +Omegagreek;03A9 +Omegaroundcyrillic;047A +Omegatitlocyrillic;047C +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Omonospace;FF2F +Oneroman;2160 +Oogonek;01EA +Oogonekmacron;01EC +Oopen;0186 +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Ostrokeacute;01FE +Otcyrillic;047E +Otilde;00D5 +Otildeacute;1E4C +Otildedieresis;1E4E +Otildesmall;F7F5 +P;0050 +Pacute;1E54 +Pcircle;24C5 +Pdotaccent;1E56 +Pecyrillic;041F +Peharmenian;054A +Pemiddlehookcyrillic;04A6 +Phi;03A6 +Phook;01A4 +Pi;03A0 +Piwrarmenian;0553 +Pmonospace;FF30 +Psi;03A8 +Psicyrillic;0470 +Psmall;F770 +Q;0051 +Qcircle;24C6 +Qmonospace;FF31 +Qsmall;F771 +R;0052 +Raarmenian;054C +Racute;0154 +Rcaron;0158 +Rcedilla;0156 +Rcircle;24C7 +Rcommaaccent;0156 +Rdblgrave;0210 +Rdotaccent;1E58 +Rdotbelow;1E5A +Rdotbelowmacron;1E5C +Reharmenian;0550 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rinvertedbreve;0212 +Rlinebelow;1E5E +Rmonospace;FF32 +Rsmall;F772 +Rsmallinverted;0281 +Rsmallinvertedsuperior;02B6 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Sacutedotaccent;1E64 +Sampigreek;03E0 +Scaron;0160 +Scarondotaccent;1E66 +Scaronsmall;F6FD +Scedilla;015E +Schwa;018F +Schwacyrillic;04D8 +Schwadieresiscyrillic;04DA +Scircle;24C8 +Scircumflex;015C +Scommaaccent;0218 +Sdotaccent;1E60 +Sdotbelow;1E62 +Sdotbelowdotaccent;1E68 +Seharmenian;054D +Sevenroman;2166 +Shaarmenian;0547 +Shacyrillic;0428 +Shchacyrillic;0429 +Sheicoptic;03E2 +Shhacyrillic;04BA +Shimacoptic;03EC +Sigma;03A3 +Sixroman;2165 +Smonospace;FF33 +Softsigncyrillic;042C +Ssmall;F773 +Stigmagreek;03DA +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcedilla;0162 +Tcircle;24C9 +Tcircumflexbelow;1E70 +Tcommaaccent;0162 +Tdotaccent;1E6A +Tdotbelow;1E6C +Tecyrillic;0422 +Tedescendercyrillic;04AC +Tenroman;2169 +Tetsecyrillic;04B4 +Theta;0398 +Thook;01AC +Thorn;00DE +Thornsmall;F7FE +Threeroman;2162 +Tildesmall;F6FE +Tiwnarmenian;054F +Tlinebelow;1E6E +Tmonospace;FF34 +Toarmenian;0539 +Tonefive;01BC +Tonesix;0184 +Tonetwo;01A7 +Tretroflexhook;01AE +Tsecyrillic;0426 +Tshecyrillic;040B +Tsmall;F774 +Twelveroman;216B +Tworoman;2161 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucaron;01D3 +Ucircle;24CA +Ucircumflex;00DB +Ucircumflexbelow;1E76 +Ucircumflexsmall;F7FB +Ucyrillic;0423 +Udblacute;0170 +Udblgrave;0214 +Udieresis;00DC +Udieresisacute;01D7 +Udieresisbelow;1E72 +Udieresiscaron;01D9 +Udieresiscyrillic;04F0 +Udieresisgrave;01DB +Udieresismacron;01D5 +Udieresissmall;F7FC +Udotbelow;1EE4 +Ugrave;00D9 +Ugravesmall;F7F9 +Uhookabove;1EE6 +Uhorn;01AF +Uhornacute;1EE8 +Uhorndotbelow;1EF0 +Uhorngrave;1EEA +Uhornhookabove;1EEC +Uhorntilde;1EEE +Uhungarumlaut;0170 +Uhungarumlautcyrillic;04F2 +Uinvertedbreve;0216 +Ukcyrillic;0478 +Umacron;016A +Umacroncyrillic;04EE +Umacrondieresis;1E7A +Umonospace;FF35 +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilonacutehooksymbolgreek;03D3 +Upsilonafrican;01B1 +Upsilondieresis;03AB +Upsilondieresishooksymbolgreek;03D4 +Upsilonhooksymbol;03D2 +Upsilontonos;038E +Uring;016E +Ushortcyrillic;040E +Usmall;F775 +Ustraightcyrillic;04AE +Ustraightstrokecyrillic;04B0 +Utilde;0168 +Utildeacute;1E78 +Utildebelow;1E74 +V;0056 +Vcircle;24CB +Vdotbelow;1E7E +Vecyrillic;0412 +Vewarmenian;054E +Vhook;01B2 +Vmonospace;FF36 +Voarmenian;0548 +Vsmall;F776 +Vtilde;1E7C +W;0057 +Wacute;1E82 +Wcircle;24CC +Wcircumflex;0174 +Wdieresis;1E84 +Wdotaccent;1E86 +Wdotbelow;1E88 +Wgrave;1E80 +Wmonospace;FF37 +Wsmall;F777 +X;0058 +Xcircle;24CD +Xdieresis;1E8C +Xdotaccent;1E8A +Xeharmenian;053D +Xi;039E +Xmonospace;FF38 +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Yatcyrillic;0462 +Ycircle;24CE +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ydotaccent;1E8E +Ydotbelow;1EF4 +Yericyrillic;042B +Yerudieresiscyrillic;04F8 +Ygrave;1EF2 +Yhook;01B3 +Yhookabove;1EF6 +Yiarmenian;0545 +Yicyrillic;0407 +Yiwnarmenian;0552 +Ymonospace;FF39 +Ysmall;F779 +Ytilde;1EF8 +Yusbigcyrillic;046A +Yusbigiotifiedcyrillic;046C +Yuslittlecyrillic;0466 +Yuslittleiotifiedcyrillic;0468 +Z;005A +Zaarmenian;0536 +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zcircle;24CF +Zcircumflex;1E90 +Zdot;017B +Zdotaccent;017B +Zdotbelow;1E92 +Zecyrillic;0417 +Zedescendercyrillic;0498 +Zedieresiscyrillic;04DE +Zeta;0396 +Zhearmenian;053A +Zhebrevecyrillic;04C1 +Zhecyrillic;0416 +Zhedescendercyrillic;0496 +Zhedieresiscyrillic;04DC +Zlinebelow;1E94 +Zmonospace;FF3A +Zsmall;F77A +Zstroke;01B5 +a;0061 +aabengali;0986 +aacute;00E1 +aadeva;0906 +aagujarati;0A86 +aagurmukhi;0A06 +aamatragurmukhi;0A3E +aarusquare;3303 +aavowelsignbengali;09BE +aavowelsigndeva;093E +aavowelsigngujarati;0ABE +abbreviationmarkarmenian;055F +abbreviationsigndeva;0970 +abengali;0985 +abopomofo;311A +abreve;0103 +abreveacute;1EAF +abrevecyrillic;04D1 +abrevedotbelow;1EB7 +abrevegrave;1EB1 +abrevehookabove;1EB3 +abrevetilde;1EB5 +acaron;01CE +acircle;24D0 +acircumflex;00E2 +acircumflexacute;1EA5 +acircumflexdotbelow;1EAD +acircumflexgrave;1EA7 +acircumflexhookabove;1EA9 +acircumflextilde;1EAB +acute;00B4 +acutebelowcmb;0317 +acutecmb;0301 +acutecomb;0301 +acutedeva;0954 +acutelowmod;02CF +acutetonecmb;0341 +acyrillic;0430 +adblgrave;0201 +addakgurmukhi;0A71 +adeva;0905 +adieresis;00E4 +adieresiscyrillic;04D3 +adieresismacron;01DF +adotbelow;1EA1 +adotmacron;01E1 +ae;00E6 +aeacute;01FD +aekorean;3150 +aemacron;01E3 +afii00208;2015 +afii08941;20A4 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +agujarati;0A85 +agurmukhi;0A05 +ahiragana;3042 +ahookabove;1EA3 +aibengali;0990 +aibopomofo;311E +aideva;0910 +aiecyrillic;04D5 +aigujarati;0A90 +aigurmukhi;0A10 +aimatragurmukhi;0A48 +ainarabic;0639 +ainfinalarabic;FECA +aininitialarabic;FECB +ainmedialarabic;FECC +ainvertedbreve;0203 +aivowelsignbengali;09C8 +aivowelsigndeva;0948 +aivowelsigngujarati;0AC8 +akatakana;30A2 +akatakanahalfwidth;FF71 +akorean;314F +alef;05D0 +alefarabic;0627 +alefdageshhebrew;FB30 +aleffinalarabic;FE8E +alefhamzaabovearabic;0623 +alefhamzaabovefinalarabic;FE84 +alefhamzabelowarabic;0625 +alefhamzabelowfinalarabic;FE88 +alefhebrew;05D0 +aleflamedhebrew;FB4F +alefmaddaabovearabic;0622 +alefmaddaabovefinalarabic;FE82 +alefmaksuraarabic;0649 +alefmaksurafinalarabic;FEF0 +alefmaksurainitialarabic;FEF3 +alefmaksuramedialarabic;FEF4 +alefpatahhebrew;FB2E +alefqamatshebrew;FB2F +aleph;2135 +allequal;224C +alpha;03B1 +alphatonos;03AC +amacron;0101 +amonospace;FF41 +ampersand;0026 +ampersandmonospace;FF06 +ampersandsmall;F726 +amsquare;33C2 +anbopomofo;3122 +angbopomofo;3124 +angkhankhuthai;0E5A +angle;2220 +anglebracketleft;3008 +anglebracketleftvertical;FE3F +anglebracketright;3009 +anglebracketrightvertical;FE40 +angleleft;2329 +angleright;232A +angstrom;212B +anoteleia;0387 +anudattadeva;0952 +anusvarabengali;0982 +anusvaradeva;0902 +anusvaragujarati;0A82 +aogonek;0105 +apaatosquare;3300 +aparen;249C +apostrophearmenian;055A +apostrophemod;02BC +apple;F8FF +approaches;2250 +approxequal;2248 +approxequalorimage;2252 +approximatelyequal;2245 +araeaekorean;318E +araeakorean;318D +arc;2312 +arighthalfring;1E9A +aring;00E5 +aringacute;01FB +aringbelow;1E01 +arrowboth;2194 +arrowdashdown;21E3 +arrowdashleft;21E0 +arrowdashright;21E2 +arrowdashup;21E1 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowdownleft;2199 +arrowdownright;2198 +arrowdownwhite;21E9 +arrowheaddownmod;02C5 +arrowheadleftmod;02C2 +arrowheadrightmod;02C3 +arrowheadupmod;02C4 +arrowhorizex;F8E7 +arrowleft;2190 +arrowleftdbl;21D0 +arrowleftdblstroke;21CD +arrowleftoverright;21C6 +arrowleftwhite;21E6 +arrowright;2192 +arrowrightdblstroke;21CF +arrowrightheavy;279E +arrowrightoverleft;21C4 +arrowrightwhite;21E8 +arrowtableft;21E4 +arrowtabright;21E5 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowupdownbase;21A8 +arrowupleft;2196 +arrowupleftofdown;21C5 +arrowupright;2197 +arrowupwhite;21E7 +arrowvertex;F8E6 +asciicircum;005E +asciicircummonospace;FF3E +asciitilde;007E +asciitildemonospace;FF5E +ascript;0251 +ascriptturned;0252 +asmallhiragana;3041 +asmallkatakana;30A1 +asmallkatakanahalfwidth;FF67 +asterisk;002A +asteriskaltonearabic;066D +asteriskarabic;066D +asteriskmath;2217 +asteriskmonospace;FF0A +asterisksmall;FE61 +asterism;2042 +asuperior;F6E9 +asymptoticallyequal;2243 +at;0040 +atilde;00E3 +atmonospace;FF20 +atsmall;FE6B +aturned;0250 +aubengali;0994 +aubopomofo;3120 +audeva;0914 +augujarati;0A94 +augurmukhi;0A14 +aulengthmarkbengali;09D7 +aumatragurmukhi;0A4C +auvowelsignbengali;09CC +auvowelsigndeva;094C +auvowelsigngujarati;0ACC +avagrahadeva;093D +aybarmenian;0561 +ayin;05E2 +ayinaltonehebrew;FB20 +ayinhebrew;05E2 +b;0062 +babengali;09AC +backslash;005C +backslashmonospace;FF3C +badeva;092C +bagujarati;0AAC +bagurmukhi;0A2C +bahiragana;3070 +bahtthai;0E3F +bakatakana;30D0 +bar;007C +barmonospace;FF5C +bbopomofo;3105 +bcircle;24D1 +bdotaccent;1E03 +bdotbelow;1E05 +beamedsixteenthnotes;266C +because;2235 +becyrillic;0431 +beharabic;0628 +behfinalarabic;FE90 +behinitialarabic;FE91 +behiragana;3079 +behmedialarabic;FE92 +behmeeminitialarabic;FC9F +behmeemisolatedarabic;FC08 +behnoonfinalarabic;FC6D +bekatakana;30D9 +benarmenian;0562 +bet;05D1 +beta;03B2 +betasymbolgreek;03D0 +betdagesh;FB31 +betdageshhebrew;FB31 +bethebrew;05D1 +betrafehebrew;FB4C +bhabengali;09AD +bhadeva;092D +bhagujarati;0AAD +bhagurmukhi;0A2D +bhook;0253 +bihiragana;3073 +bikatakana;30D3 +bilabialclick;0298 +bindigurmukhi;0A02 +birusquare;3331 +blackcircle;25CF +blackdiamond;25C6 +blackdownpointingtriangle;25BC +blackleftpointingpointer;25C4 +blackleftpointingtriangle;25C0 +blacklenticularbracketleft;3010 +blacklenticularbracketleftvertical;FE3B +blacklenticularbracketright;3011 +blacklenticularbracketrightvertical;FE3C +blacklowerlefttriangle;25E3 +blacklowerrighttriangle;25E2 +blackrectangle;25AC +blackrightpointingpointer;25BA +blackrightpointingtriangle;25B6 +blacksmallsquare;25AA +blacksmilingface;263B +blacksquare;25A0 +blackstar;2605 +blackupperlefttriangle;25E4 +blackupperrighttriangle;25E5 +blackuppointingsmalltriangle;25B4 +blackuppointingtriangle;25B2 +blank;2423 +blinebelow;1E07 +block;2588 +bmonospace;FF42 +bobaimaithai;0E1A +bohiragana;307C +bokatakana;30DC +bparen;249D +bqsquare;33C3 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +braceleftmonospace;FF5B +braceleftsmall;FE5B +bracelefttp;F8F1 +braceleftvertical;FE37 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerightmonospace;FF5D +bracerightsmall;FE5C +bracerighttp;F8FC +bracerightvertical;FE38 +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketleftmonospace;FF3B +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrightmonospace;FF3D +bracketrighttp;F8F9 +breve;02D8 +brevebelowcmb;032E +brevecmb;0306 +breveinvertedbelowcmb;032F +breveinvertedcmb;0311 +breveinverteddoublecmb;0361 +bridgebelowcmb;032A +bridgeinvertedbelowcmb;033A +brokenbar;00A6 +bstroke;0180 +bsuperior;F6EA +btopbar;0183 +buhiragana;3076 +bukatakana;30D6 +bullet;2022 +bulletinverse;25D8 +bulletoperator;2219 +bullseye;25CE +c;0063 +caarmenian;056E +cabengali;099A +cacute;0107 +cadeva;091A +cagujarati;0A9A +cagurmukhi;0A1A +calsquare;3388 +candrabindubengali;0981 +candrabinducmb;0310 +candrabindudeva;0901 +candrabindugujarati;0A81 +capslock;21EA +careof;2105 +caron;02C7 +caronbelowcmb;032C +caroncmb;030C +carriagereturn;21B5 +cbopomofo;3118 +ccaron;010D +ccedilla;00E7 +ccedillaacute;1E09 +ccircle;24D2 +ccircumflex;0109 +ccurl;0255 +cdot;010B +cdotaccent;010B +cdsquare;33C5 +cedilla;00B8 +cedillacmb;0327 +cent;00A2 +centigrade;2103 +centinferior;F6DF +centmonospace;FFE0 +centoldstyle;F7A2 +centsuperior;F6E0 +chaarmenian;0579 +chabengali;099B +chadeva;091B +chagujarati;0A9B +chagurmukhi;0A1B +chbopomofo;3114 +cheabkhasiancyrillic;04BD +checkmark;2713 +checyrillic;0447 +chedescenderabkhasiancyrillic;04BF +chedescendercyrillic;04B7 +chedieresiscyrillic;04F5 +cheharmenian;0573 +chekhakassiancyrillic;04CC +cheverticalstrokecyrillic;04B9 +chi;03C7 +chieuchacirclekorean;3277 +chieuchaparenkorean;3217 +chieuchcirclekorean;3269 +chieuchkorean;314A +chieuchparenkorean;3209 +chochangthai;0E0A +chochanthai;0E08 +chochingthai;0E09 +chochoethai;0E0C +chook;0188 +cieucacirclekorean;3276 +cieucaparenkorean;3216 +cieuccirclekorean;3268 +cieuckorean;3148 +cieucparenkorean;3208 +cieucuparenkorean;321C +circle;25CB +circlemultiply;2297 +circleot;2299 +circleplus;2295 +circlepostalmark;3036 +circlewithlefthalfblack;25D0 +circlewithrighthalfblack;25D1 +circumflex;02C6 +circumflexbelowcmb;032D +circumflexcmb;0302 +clear;2327 +clickalveolar;01C2 +clickdental;01C0 +clicklateral;01C1 +clickretroflex;01C3 +club;2663 +clubsuitblack;2663 +clubsuitwhite;2667 +cmcubedsquare;33A4 +cmonospace;FF43 +cmsquaredsquare;33A0 +coarmenian;0581 +colon;003A +colonmonetary;20A1 +colonmonospace;FF1A +colonsign;20A1 +colonsmall;FE55 +colontriangularhalfmod;02D1 +colontriangularmod;02D0 +comma;002C +commaabovecmb;0313 +commaaboverightcmb;0315 +commaaccent;F6C3 +commaarabic;060C +commaarmenian;055D +commainferior;F6E1 +commamonospace;FF0C +commareversedabovecmb;0314 +commareversedmod;02BD +commasmall;FE50 +commasuperior;F6E2 +commaturnedabovecmb;0312 +commaturnedmod;02BB +compass;263C +congruent;2245 +contourintegral;222E +control;2303 +controlACK;0006 +controlBEL;0007 +controlBS;0008 +controlCAN;0018 +controlCR;000D +controlDC1;0011 +controlDC2;0012 +controlDC3;0013 +controlDC4;0014 +controlDEL;007F +controlDLE;0010 +controlEM;0019 +controlENQ;0005 +controlEOT;0004 +controlESC;001B +controlETB;0017 +controlETX;0003 +controlFF;000C +controlFS;001C +controlGS;001D +controlHT;0009 +controlLF;000A +controlNAK;0015 +controlRS;001E +controlSI;000F +controlSO;000E +controlSOT;0002 +controlSTX;0001 +controlSUB;001A +controlSYN;0016 +controlUS;001F +controlVT;000B +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +cornerbracketleft;300C +cornerbracketlefthalfwidth;FF62 +cornerbracketleftvertical;FE41 +cornerbracketright;300D +cornerbracketrighthalfwidth;FF63 +cornerbracketrightvertical;FE42 +corporationsquare;337F +cosquare;33C7 +coverkgsquare;33C6 +cparen;249E +cruzeiro;20A2 +cstretched;0297 +curlyand;22CF +curlyor;22CE +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +daarmenian;0564 +dabengali;09A6 +dadarabic;0636 +dadeva;0926 +dadfinalarabic;FEBE +dadinitialarabic;FEBF +dadmedialarabic;FEC0 +dagesh;05BC +dageshhebrew;05BC +dagger;2020 +daggerdbl;2021 +dagujarati;0AA6 +dagurmukhi;0A26 +dahiragana;3060 +dakatakana;30C0 +dalarabic;062F +dalet;05D3 +daletdagesh;FB33 +daletdageshhebrew;FB33 +dalethatafpatah;05D3 05B2 +dalethatafpatahhebrew;05D3 05B2 +dalethatafsegol;05D3 05B1 +dalethatafsegolhebrew;05D3 05B1 +dalethebrew;05D3 +dalethiriq;05D3 05B4 +dalethiriqhebrew;05D3 05B4 +daletholam;05D3 05B9 +daletholamhebrew;05D3 05B9 +daletpatah;05D3 05B7 +daletpatahhebrew;05D3 05B7 +daletqamats;05D3 05B8 +daletqamatshebrew;05D3 05B8 +daletqubuts;05D3 05BB +daletqubutshebrew;05D3 05BB +daletsegol;05D3 05B6 +daletsegolhebrew;05D3 05B6 +daletsheva;05D3 05B0 +daletshevahebrew;05D3 05B0 +dalettsere;05D3 05B5 +dalettserehebrew;05D3 05B5 +dalfinalarabic;FEAA +dammaarabic;064F +dammalowarabic;064F +dammatanaltonearabic;064C +dammatanarabic;064C +danda;0964 +dargahebrew;05A7 +dargalefthebrew;05A7 +dasiapneumatacyrilliccmb;0485 +dblGrave;F6D3 +dblanglebracketleft;300A +dblanglebracketleftvertical;FE3D +dblanglebracketright;300B +dblanglebracketrightvertical;FE3E +dblarchinvertedbelowcmb;032B +dblarrowleft;21D4 +dblarrowright;21D2 +dbldanda;0965 +dblgrave;F6D6 +dblgravecmb;030F +dblintegral;222C +dbllowline;2017 +dbllowlinecmb;0333 +dbloverlinecmb;033F +dblprimemod;02BA +dblverticalbar;2016 +dblverticallineabovecmb;030E +dbopomofo;3109 +dbsquare;33C8 +dcaron;010F +dcedilla;1E11 +dcircle;24D3 +dcircumflexbelow;1E13 +dcroat;0111 +ddabengali;09A1 +ddadeva;0921 +ddagujarati;0AA1 +ddagurmukhi;0A21 +ddalarabic;0688 +ddalfinalarabic;FB89 +dddhadeva;095C +ddhabengali;09A2 +ddhadeva;0922 +ddhagujarati;0AA2 +ddhagurmukhi;0A22 +ddotaccent;1E0B +ddotbelow;1E0D +decimalseparatorarabic;066B +decimalseparatorpersian;066B +decyrillic;0434 +degree;00B0 +dehihebrew;05AD +dehiragana;3067 +deicoptic;03EF +dekatakana;30C7 +deleteleft;232B +deleteright;2326 +delta;03B4 +deltaturned;018D +denominatorminusonenumeratorbengali;09F8 +dezh;02A4 +dhabengali;09A7 +dhadeva;0927 +dhagujarati;0AA7 +dhagurmukhi;0A27 +dhook;0257 +dialytikatonos;0385 +dialytikatonoscmb;0344 +diamond;2666 +diamondsuitwhite;2662 +dieresis;00A8 +dieresisacute;F6D7 +dieresisbelowcmb;0324 +dieresiscmb;0308 +dieresisgrave;F6D8 +dieresistonos;0385 +dihiragana;3062 +dikatakana;30C2 +dittomark;3003 +divide;00F7 +divides;2223 +divisionslash;2215 +djecyrillic;0452 +dkshade;2593 +dlinebelow;1E0F +dlsquare;3397 +dmacron;0111 +dmonospace;FF44 +dnblock;2584 +dochadathai;0E0E +dodekthai;0E14 +dohiragana;3069 +dokatakana;30C9 +dollar;0024 +dollarinferior;F6E3 +dollarmonospace;FF04 +dollaroldstyle;F724 +dollarsmall;FE69 +dollarsuperior;F6E4 +dong;20AB +dorusquare;3326 +dotaccent;02D9 +dotaccentcmb;0307 +dotbelowcmb;0323 +dotbelowcomb;0323 +dotkatakana;30FB +dotlessi;0131 +dotlessj;F6BE +dotlessjstrokehook;0284 +dotmath;22C5 +dottedcircle;25CC +doubleyodpatah;FB1F +doubleyodpatahhebrew;FB1F +downtackbelowcmb;031E +downtackmod;02D5 +dparen;249F +dsuperior;F6EB +dtail;0256 +dtopbar;018C +duhiragana;3065 +dukatakana;30C5 +dz;01F3 +dzaltone;02A3 +dzcaron;01C6 +dzcurl;02A5 +dzeabkhasiancyrillic;04E1 +dzecyrillic;0455 +dzhecyrillic;045F +e;0065 +eacute;00E9 +earth;2641 +ebengali;098F +ebopomofo;311C +ebreve;0115 +ecandradeva;090D +ecandragujarati;0A8D +ecandravowelsigndeva;0945 +ecandravowelsigngujarati;0AC5 +ecaron;011B +ecedillabreve;1E1D +echarmenian;0565 +echyiwnarmenian;0587 +ecircle;24D4 +ecircumflex;00EA +ecircumflexacute;1EBF +ecircumflexbelow;1E19 +ecircumflexdotbelow;1EC7 +ecircumflexgrave;1EC1 +ecircumflexhookabove;1EC3 +ecircumflextilde;1EC5 +ecyrillic;0454 +edblgrave;0205 +edeva;090F +edieresis;00EB +edot;0117 +edotaccent;0117 +edotbelow;1EB9 +eegurmukhi;0A0F +eematragurmukhi;0A47 +efcyrillic;0444 +egrave;00E8 +egujarati;0A8F +eharmenian;0567 +ehbopomofo;311D +ehiragana;3048 +ehookabove;1EBB +eibopomofo;311F +eight;0038 +eightarabic;0668 +eightbengali;09EE +eightcircle;2467 +eightcircleinversesansserif;2791 +eightdeva;096E +eighteencircle;2471 +eighteenparen;2485 +eighteenperiod;2499 +eightgujarati;0AEE +eightgurmukhi;0A6E +eighthackarabic;0668 +eighthangzhou;3028 +eighthnotebeamed;266B +eightideographicparen;3227 +eightinferior;2088 +eightmonospace;FF18 +eightoldstyle;F738 +eightparen;247B +eightperiod;248F +eightpersian;06F8 +eightroman;2177 +eightsuperior;2078 +eightthai;0E58 +einvertedbreve;0207 +eiotifiedcyrillic;0465 +ekatakana;30A8 +ekatakanahalfwidth;FF74 +ekonkargurmukhi;0A74 +ekorean;3154 +elcyrillic;043B +element;2208 +elevencircle;246A +elevenparen;247E +elevenperiod;2492 +elevenroman;217A +ellipsis;2026 +ellipsisvertical;22EE +emacron;0113 +emacronacute;1E17 +emacrongrave;1E15 +emcyrillic;043C +emdash;2014 +emdashvertical;FE31 +emonospace;FF45 +emphasismarkarmenian;055B +emptyset;2205 +enbopomofo;3123 +encyrillic;043D +endash;2013 +endashvertical;FE32 +endescendercyrillic;04A3 +eng;014B +engbopomofo;3125 +enghecyrillic;04A5 +enhookcyrillic;04C8 +enspace;2002 +eogonek;0119 +eokorean;3153 +eopen;025B +eopenclosed;029A +eopenreversed;025C +eopenreversedclosed;025E +eopenreversedhook;025D +eparen;24A0 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equalmonospace;FF1D +equalsmall;FE66 +equalsuperior;207C +equivalence;2261 +erbopomofo;3126 +ercyrillic;0440 +ereversed;0258 +ereversedcyrillic;044D +escyrillic;0441 +esdescendercyrillic;04AB +esh;0283 +eshcurl;0286 +eshortdeva;090E +eshortvowelsigndeva;0946 +eshreversedloop;01AA +eshsquatreversed;0285 +esmallhiragana;3047 +esmallkatakana;30A7 +esmallkatakanahalfwidth;FF6A +estimated;212E +esuperior;F6EC +eta;03B7 +etarmenian;0568 +etatonos;03AE +eth;00F0 +etilde;1EBD +etildebelow;1E1B +etnahtafoukhhebrew;0591 +etnahtafoukhlefthebrew;0591 +etnahtahebrew;0591 +etnahtalefthebrew;0591 +eturned;01DD +eukorean;3161 +euro;20AC +evowelsignbengali;09C7 +evowelsigndeva;0947 +evowelsigngujarati;0AC7 +exclam;0021 +exclamarmenian;055C +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclammonospace;FF01 +exclamsmall;F721 +existential;2203 +ezh;0292 +ezhcaron;01EF +ezhcurl;0293 +ezhreversed;01B9 +ezhtail;01BA +f;0066 +fadeva;095E +fagurmukhi;0A5E +fahrenheit;2109 +fathaarabic;064E +fathalowarabic;064E +fathatanarabic;064B +fbopomofo;3108 +fcircle;24D5 +fdotaccent;1E1F +feharabic;0641 +feharmenian;0586 +fehfinalarabic;FED2 +fehinitialarabic;FED3 +fehmedialarabic;FED4 +feicoptic;03E5 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +fifteencircle;246E +fifteenparen;2482 +fifteenperiod;2496 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +finalkaf;05DA +finalkafdagesh;FB3A +finalkafdageshhebrew;FB3A +finalkafhebrew;05DA +finalkafqamats;05DA 05B8 +finalkafqamatshebrew;05DA 05B8 +finalkafsheva;05DA 05B0 +finalkafshevahebrew;05DA 05B0 +finalmem;05DD +finalmemhebrew;05DD +finalnun;05DF +finalnunhebrew;05DF +finalpe;05E3 +finalpehebrew;05E3 +finaltsadi;05E5 +finaltsadihebrew;05E5 +firsttonechinese;02C9 +fisheye;25C9 +fitacyrillic;0473 +five;0035 +fivearabic;0665 +fivebengali;09EB +fivecircle;2464 +fivecircleinversesansserif;278E +fivedeva;096B +fiveeighths;215D +fivegujarati;0AEB +fivegurmukhi;0A6B +fivehackarabic;0665 +fivehangzhou;3025 +fiveideographicparen;3224 +fiveinferior;2085 +fivemonospace;FF15 +fiveoldstyle;F735 +fiveparen;2478 +fiveperiod;248C +fivepersian;06F5 +fiveroman;2174 +fivesuperior;2075 +fivethai;0E55 +fl;FB02 +florin;0192 +fmonospace;FF46 +fmsquare;3399 +fofanthai;0E1F +fofathai;0E1D +fongmanthai;0E4F +forall;2200 +four;0034 +fourarabic;0664 +fourbengali;09EA +fourcircle;2463 +fourcircleinversesansserif;278D +fourdeva;096A +fourgujarati;0AEA +fourgurmukhi;0A6A +fourhackarabic;0664 +fourhangzhou;3024 +fourideographicparen;3223 +fourinferior;2084 +fourmonospace;FF14 +fournumeratorbengali;09F7 +fouroldstyle;F734 +fourparen;2477 +fourperiod;248B +fourpersian;06F4 +fourroman;2173 +foursuperior;2074 +fourteencircle;246D +fourteenparen;2481 +fourteenperiod;2495 +fourthai;0E54 +fourthtonechinese;02CB +fparen;24A1 +fraction;2044 +franc;20A3 +g;0067 +gabengali;0997 +gacute;01F5 +gadeva;0917 +gafarabic;06AF +gaffinalarabic;FB93 +gafinitialarabic;FB94 +gafmedialarabic;FB95 +gagujarati;0A97 +gagurmukhi;0A17 +gahiragana;304C +gakatakana;30AC +gamma;03B3 +gammalatinsmall;0263 +gammasuperior;02E0 +gangiacoptic;03EB +gbopomofo;310D +gbreve;011F +gcaron;01E7 +gcedilla;0123 +gcircle;24D6 +gcircumflex;011D +gcommaaccent;0123 +gdot;0121 +gdotaccent;0121 +gecyrillic;0433 +gehiragana;3052 +gekatakana;30B2 +geometricallyequal;2251 +gereshaccenthebrew;059C +gereshhebrew;05F3 +gereshmuqdamhebrew;059D +germandbls;00DF +gershayimaccenthebrew;059E +gershayimhebrew;05F4 +getamark;3013 +ghabengali;0998 +ghadarmenian;0572 +ghadeva;0918 +ghagujarati;0A98 +ghagurmukhi;0A18 +ghainarabic;063A +ghainfinalarabic;FECE +ghaininitialarabic;FECF +ghainmedialarabic;FED0 +ghemiddlehookcyrillic;0495 +ghestrokecyrillic;0493 +gheupturncyrillic;0491 +ghhadeva;095A +ghhagurmukhi;0A5A +ghook;0260 +ghzsquare;3393 +gihiragana;304E +gikatakana;30AE +gimarmenian;0563 +gimel;05D2 +gimeldagesh;FB32 +gimeldageshhebrew;FB32 +gimelhebrew;05D2 +gjecyrillic;0453 +glottalinvertedstroke;01BE +glottalstop;0294 +glottalstopinverted;0296 +glottalstopmod;02C0 +glottalstopreversed;0295 +glottalstopreversedmod;02C1 +glottalstopreversedsuperior;02E4 +glottalstopstroke;02A1 +glottalstopstrokereversed;02A2 +gmacron;1E21 +gmonospace;FF47 +gohiragana;3054 +gokatakana;30B4 +gparen;24A2 +gpasquare;33AC +gradient;2207 +grave;0060 +gravebelowcmb;0316 +gravecmb;0300 +gravecomb;0300 +gravedeva;0953 +gravelowmod;02CE +gravemonospace;FF40 +gravetonecmb;0340 +greater;003E +greaterequal;2265 +greaterequalorless;22DB +greatermonospace;FF1E +greaterorequivalent;2273 +greaterorless;2277 +greateroverequal;2267 +greatersmall;FE65 +gscript;0261 +gstroke;01E5 +guhiragana;3050 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +gukatakana;30B0 +guramusquare;3318 +gysquare;33C9 +h;0068 +haabkhasiancyrillic;04A9 +haaltonearabic;06C1 +habengali;09B9 +hadescendercyrillic;04B3 +hadeva;0939 +hagujarati;0AB9 +hagurmukhi;0A39 +haharabic;062D +hahfinalarabic;FEA2 +hahinitialarabic;FEA3 +hahiragana;306F +hahmedialarabic;FEA4 +haitusquare;332A +hakatakana;30CF +hakatakanahalfwidth;FF8A +halantgurmukhi;0A4D +hamzaarabic;0621 +hamzadammaarabic;0621 064F +hamzadammatanarabic;0621 064C +hamzafathaarabic;0621 064E +hamzafathatanarabic;0621 064B +hamzalowarabic;0621 +hamzalowkasraarabic;0621 0650 +hamzalowkasratanarabic;0621 064D +hamzasukunarabic;0621 0652 +hangulfiller;3164 +hardsigncyrillic;044A +harpoonleftbarbup;21BC +harpoonrightbarbup;21C0 +hasquare;33CA +hatafpatah;05B2 +hatafpatah16;05B2 +hatafpatah23;05B2 +hatafpatah2f;05B2 +hatafpatahhebrew;05B2 +hatafpatahnarrowhebrew;05B2 +hatafpatahquarterhebrew;05B2 +hatafpatahwidehebrew;05B2 +hatafqamats;05B3 +hatafqamats1b;05B3 +hatafqamats28;05B3 +hatafqamats34;05B3 +hatafqamatshebrew;05B3 +hatafqamatsnarrowhebrew;05B3 +hatafqamatsquarterhebrew;05B3 +hatafqamatswidehebrew;05B3 +hatafsegol;05B1 +hatafsegol17;05B1 +hatafsegol24;05B1 +hatafsegol30;05B1 +hatafsegolhebrew;05B1 +hatafsegolnarrowhebrew;05B1 +hatafsegolquarterhebrew;05B1 +hatafsegolwidehebrew;05B1 +hbar;0127 +hbopomofo;310F +hbrevebelow;1E2B +hcedilla;1E29 +hcircle;24D7 +hcircumflex;0125 +hdieresis;1E27 +hdotaccent;1E23 +hdotbelow;1E25 +he;05D4 +heart;2665 +heartsuitblack;2665 +heartsuitwhite;2661 +hedagesh;FB34 +hedageshhebrew;FB34 +hehaltonearabic;06C1 +heharabic;0647 +hehebrew;05D4 +hehfinalaltonearabic;FBA7 +hehfinalalttwoarabic;FEEA +hehfinalarabic;FEEA +hehhamzaabovefinalarabic;FBA5 +hehhamzaaboveisolatedarabic;FBA4 +hehinitialaltonearabic;FBA8 +hehinitialarabic;FEEB +hehiragana;3078 +hehmedialaltonearabic;FBA9 +hehmedialarabic;FEEC +heiseierasquare;337B +hekatakana;30D8 +hekatakanahalfwidth;FF8D +hekutaarusquare;3336 +henghook;0267 +herutusquare;3339 +het;05D7 +hethebrew;05D7 +hhook;0266 +hhooksuperior;02B1 +hieuhacirclekorean;327B +hieuhaparenkorean;321B +hieuhcirclekorean;326D +hieuhkorean;314E +hieuhparenkorean;320D +hihiragana;3072 +hikatakana;30D2 +hikatakanahalfwidth;FF8B +hiriq;05B4 +hiriq14;05B4 +hiriq21;05B4 +hiriq2d;05B4 +hiriqhebrew;05B4 +hiriqnarrowhebrew;05B4 +hiriqquarterhebrew;05B4 +hiriqwidehebrew;05B4 +hlinebelow;1E96 +hmonospace;FF48 +hoarmenian;0570 +hohipthai;0E2B +hohiragana;307B +hokatakana;30DB +hokatakanahalfwidth;FF8E +holam;05B9 +holam19;05B9 +holam26;05B9 +holam32;05B9 +holamhebrew;05B9 +holamnarrowhebrew;05B9 +holamquarterhebrew;05B9 +holamwidehebrew;05B9 +honokhukthai;0E2E +hookabovecomb;0309 +hookcmb;0309 +hookpalatalizedbelowcmb;0321 +hookretroflexbelowcmb;0322 +hoonsquare;3342 +horicoptic;03E9 +horizontalbar;2015 +horncmb;031B +hotsprings;2668 +house;2302 +hparen;24A3 +hsuperior;02B0 +hturned;0265 +huhiragana;3075 +huiitosquare;3333 +hukatakana;30D5 +hukatakanahalfwidth;FF8C +hungarumlaut;02DD +hungarumlautcmb;030B +hv;0195 +hyphen;002D +hypheninferior;F6E5 +hyphenmonospace;FF0D +hyphensmall;FE63 +hyphensuperior;F6E6 +hyphentwo;2010 +i;0069 +iacute;00ED +iacyrillic;044F +ibengali;0987 +ibopomofo;3127 +ibreve;012D +icaron;01D0 +icircle;24D8 +icircumflex;00EE +icyrillic;0456 +idblgrave;0209 +ideographearthcircle;328F +ideographfirecircle;328B +ideographicallianceparen;323F +ideographiccallparen;323A +ideographiccentrecircle;32A5 +ideographicclose;3006 +ideographiccomma;3001 +ideographiccommaleft;FF64 +ideographiccongratulationparen;3237 +ideographiccorrectcircle;32A3 +ideographicearthparen;322F +ideographicenterpriseparen;323D +ideographicexcellentcircle;329D +ideographicfestivalparen;3240 +ideographicfinancialcircle;3296 +ideographicfinancialparen;3236 +ideographicfireparen;322B +ideographichaveparen;3232 +ideographichighcircle;32A4 +ideographiciterationmark;3005 +ideographiclaborcircle;3298 +ideographiclaborparen;3238 +ideographicleftcircle;32A7 +ideographiclowcircle;32A6 +ideographicmedicinecircle;32A9 +ideographicmetalparen;322E +ideographicmoonparen;322A +ideographicnameparen;3234 +ideographicperiod;3002 +ideographicprintcircle;329E +ideographicreachparen;3243 +ideographicrepresentparen;3239 +ideographicresourceparen;323E +ideographicrightcircle;32A8 +ideographicsecretcircle;3299 +ideographicselfparen;3242 +ideographicsocietyparen;3233 +ideographicspace;3000 +ideographicspecialparen;3235 +ideographicstockparen;3231 +ideographicstudyparen;323B +ideographicsunparen;3230 +ideographicsuperviseparen;323C +ideographicwaterparen;322C +ideographicwoodparen;322D +ideographiczero;3007 +ideographmetalcircle;328E +ideographmooncircle;328A +ideographnamecircle;3294 +ideographsuncircle;3290 +ideographwatercircle;328C +ideographwoodcircle;328D +ideva;0907 +idieresis;00EF +idieresisacute;1E2F +idieresiscyrillic;04E5 +idotbelow;1ECB +iebrevecyrillic;04D7 +iecyrillic;0435 +ieungacirclekorean;3275 +ieungaparenkorean;3215 +ieungcirclekorean;3267 +ieungkorean;3147 +ieungparenkorean;3207 +igrave;00EC +igujarati;0A87 +igurmukhi;0A07 +ihiragana;3044 +ihookabove;1EC9 +iibengali;0988 +iicyrillic;0438 +iideva;0908 +iigujarati;0A88 +iigurmukhi;0A08 +iimatragurmukhi;0A40 +iinvertedbreve;020B +iishortcyrillic;0439 +iivowelsignbengali;09C0 +iivowelsigndeva;0940 +iivowelsigngujarati;0AC0 +ij;0133 +ikatakana;30A4 +ikatakanahalfwidth;FF72 +ikorean;3163 +ilde;02DC +iluyhebrew;05AC +imacron;012B +imacroncyrillic;04E3 +imageorapproximatelyequal;2253 +imatragurmukhi;0A3F +imonospace;FF49 +increment;2206 +infinity;221E +iniarmenian;056B +integral;222B +integralbottom;2321 +integralbt;2321 +integralex;F8F5 +integraltop;2320 +integraltp;2320 +intersection;2229 +intisquare;3305 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iocyrillic;0451 +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotalatin;0269 +iotatonos;03AF +iparen;24A4 +irigurmukhi;0A72 +ismallhiragana;3043 +ismallkatakana;30A3 +ismallkatakanahalfwidth;FF68 +issharbengali;09FA +istroke;0268 +isuperior;F6ED +iterationhiragana;309D +iterationkatakana;30FD +itilde;0129 +itildebelow;1E2D +iubopomofo;3129 +iucyrillic;044E +ivowelsignbengali;09BF +ivowelsigndeva;093F +ivowelsigngujarati;0ABF +izhitsacyrillic;0475 +izhitsadblgravecyrillic;0477 +j;006A +jaarmenian;0571 +jabengali;099C +jadeva;091C +jagujarati;0A9C +jagurmukhi;0A1C +jbopomofo;3110 +jcaron;01F0 +jcircle;24D9 +jcircumflex;0135 +jcrossedtail;029D +jdotlessstroke;025F +jecyrillic;0458 +jeemarabic;062C +jeemfinalarabic;FE9E +jeeminitialarabic;FE9F +jeemmedialarabic;FEA0 +jeharabic;0698 +jehfinalarabic;FB8B +jhabengali;099D +jhadeva;091D +jhagujarati;0A9D +jhagurmukhi;0A1D +jheharmenian;057B +jis;3004 +jmonospace;FF4A +jparen;24A5 +jsuperior;02B2 +k;006B +kabashkircyrillic;04A1 +kabengali;0995 +kacute;1E31 +kacyrillic;043A +kadescendercyrillic;049B +kadeva;0915 +kaf;05DB +kafarabic;0643 +kafdagesh;FB3B +kafdageshhebrew;FB3B +kaffinalarabic;FEDA +kafhebrew;05DB +kafinitialarabic;FEDB +kafmedialarabic;FEDC +kafrafehebrew;FB4D +kagujarati;0A95 +kagurmukhi;0A15 +kahiragana;304B +kahookcyrillic;04C4 +kakatakana;30AB +kakatakanahalfwidth;FF76 +kappa;03BA +kappasymbolgreek;03F0 +kapyeounmieumkorean;3171 +kapyeounphieuphkorean;3184 +kapyeounpieupkorean;3178 +kapyeounssangpieupkorean;3179 +karoriisquare;330D +kashidaautoarabic;0640 +kashidaautonosidebearingarabic;0640 +kasmallkatakana;30F5 +kasquare;3384 +kasraarabic;0650 +kasratanarabic;064D +kastrokecyrillic;049F +katahiraprolongmarkhalfwidth;FF70 +kaverticalstrokecyrillic;049D +kbopomofo;310E +kcalsquare;3389 +kcaron;01E9 +kcedilla;0137 +kcircle;24DA +kcommaaccent;0137 +kdotbelow;1E33 +keharmenian;0584 +kehiragana;3051 +kekatakana;30B1 +kekatakanahalfwidth;FF79 +kenarmenian;056F +kesmallkatakana;30F6 +kgreenlandic;0138 +khabengali;0996 +khacyrillic;0445 +khadeva;0916 +khagujarati;0A96 +khagurmukhi;0A16 +khaharabic;062E +khahfinalarabic;FEA6 +khahinitialarabic;FEA7 +khahmedialarabic;FEA8 +kheicoptic;03E7 +khhadeva;0959 +khhagurmukhi;0A59 +khieukhacirclekorean;3278 +khieukhaparenkorean;3218 +khieukhcirclekorean;326A +khieukhkorean;314B +khieukhparenkorean;320A +khokhaithai;0E02 +khokhonthai;0E05 +khokhuatthai;0E03 +khokhwaithai;0E04 +khomutthai;0E5B +khook;0199 +khorakhangthai;0E06 +khzsquare;3391 +kihiragana;304D +kikatakana;30AD +kikatakanahalfwidth;FF77 +kiroguramusquare;3315 +kiromeetorusquare;3316 +kirosquare;3314 +kiyeokacirclekorean;326E +kiyeokaparenkorean;320E +kiyeokcirclekorean;3260 +kiyeokkorean;3131 +kiyeokparenkorean;3200 +kiyeoksioskorean;3133 +kjecyrillic;045C +klinebelow;1E35 +klsquare;3398 +kmcubedsquare;33A6 +kmonospace;FF4B +kmsquaredsquare;33A2 +kohiragana;3053 +kohmsquare;33C0 +kokaithai;0E01 +kokatakana;30B3 +kokatakanahalfwidth;FF7A +kooposquare;331E +koppacyrillic;0481 +koreanstandardsymbol;327F +koroniscmb;0343 +kparen;24A6 +kpasquare;33AA +ksicyrillic;046F +ktsquare;33CF +kturned;029E +kuhiragana;304F +kukatakana;30AF +kukatakanahalfwidth;FF78 +kvsquare;33B8 +kwsquare;33BE +l;006C +labengali;09B2 +lacute;013A +ladeva;0932 +lagujarati;0AB2 +lagurmukhi;0A32 +lakkhangyaothai;0E45 +lamaleffinalarabic;FEFC +lamalefhamzaabovefinalarabic;FEF8 +lamalefhamzaaboveisolatedarabic;FEF7 +lamalefhamzabelowfinalarabic;FEFA +lamalefhamzabelowisolatedarabic;FEF9 +lamalefisolatedarabic;FEFB +lamalefmaddaabovefinalarabic;FEF6 +lamalefmaddaaboveisolatedarabic;FEF5 +lamarabic;0644 +lambda;03BB +lambdastroke;019B +lamed;05DC +lameddagesh;FB3C +lameddageshhebrew;FB3C +lamedhebrew;05DC +lamedholam;05DC 05B9 +lamedholamdagesh;05DC 05B9 05BC +lamedholamdageshhebrew;05DC 05B9 05BC +lamedholamhebrew;05DC 05B9 +lamfinalarabic;FEDE +lamhahinitialarabic;FCCA +laminitialarabic;FEDF +lamjeeminitialarabic;FCC9 +lamkhahinitialarabic;FCCB +lamlamhehisolatedarabic;FDF2 +lammedialarabic;FEE0 +lammeemhahinitialarabic;FD88 +lammeeminitialarabic;FCCC +lammeemjeeminitialarabic;FEDF FEE4 FEA0 +lammeemkhahinitialarabic;FEDF FEE4 FEA8 +largecircle;25EF +lbar;019A +lbelt;026C +lbopomofo;310C +lcaron;013E +lcedilla;013C +lcircle;24DB +lcircumflexbelow;1E3D +lcommaaccent;013C +ldot;0140 +ldotaccent;0140 +ldotbelow;1E37 +ldotbelowmacron;1E39 +leftangleabovecmb;031A +lefttackbelowcmb;0318 +less;003C +lessequal;2264 +lessequalorgreater;22DA +lessmonospace;FF1C +lessorequivalent;2272 +lessorgreater;2276 +lessoverequal;2266 +lesssmall;FE64 +lezh;026E +lfblock;258C +lhookretroflex;026D +lira;20A4 +liwnarmenian;056C +lj;01C9 +ljecyrillic;0459 +ll;F6C0 +lladeva;0933 +llagujarati;0AB3 +llinebelow;1E3B +llladeva;0934 +llvocalicbengali;09E1 +llvocalicdeva;0961 +llvocalicvowelsignbengali;09E3 +llvocalicvowelsigndeva;0963 +lmiddletilde;026B +lmonospace;FF4C +lmsquare;33D0 +lochulathai;0E2C +logicaland;2227 +logicalnot;00AC +logicalnotreversed;2310 +logicalor;2228 +lolingthai;0E25 +longs;017F +lowlinecenterline;FE4E +lowlinecmb;0332 +lowlinedashed;FE4D +lozenge;25CA +lparen;24A7 +lslash;0142 +lsquare;2113 +lsuperior;F6EE +ltshade;2591 +luthai;0E26 +lvocalicbengali;098C +lvocalicdeva;090C +lvocalicvowelsignbengali;09E2 +lvocalicvowelsigndeva;0962 +lxsquare;33D3 +m;006D +mabengali;09AE +macron;00AF +macronbelowcmb;0331 +macroncmb;0304 +macronlowmod;02CD +macronmonospace;FFE3 +macute;1E3F +madeva;092E +magujarati;0AAE +magurmukhi;0A2E +mahapakhhebrew;05A4 +mahapakhlefthebrew;05A4 +mahiragana;307E +maichattawalowleftthai;F895 +maichattawalowrightthai;F894 +maichattawathai;0E4B +maichattawaupperleftthai;F893 +maieklowleftthai;F88C +maieklowrightthai;F88B +maiekthai;0E48 +maiekupperleftthai;F88A +maihanakatleftthai;F884 +maihanakatthai;0E31 +maitaikhuleftthai;F889 +maitaikhuthai;0E47 +maitholowleftthai;F88F +maitholowrightthai;F88E +maithothai;0E49 +maithoupperleftthai;F88D +maitrilowleftthai;F892 +maitrilowrightthai;F891 +maitrithai;0E4A +maitriupperleftthai;F890 +maiyamokthai;0E46 +makatakana;30DE +makatakanahalfwidth;FF8F +male;2642 +mansyonsquare;3347 +maqafhebrew;05BE +mars;2642 +masoracirclehebrew;05AF +masquare;3383 +mbopomofo;3107 +mbsquare;33D4 +mcircle;24DC +mcubedsquare;33A5 +mdotaccent;1E41 +mdotbelow;1E43 +meemarabic;0645 +meemfinalarabic;FEE2 +meeminitialarabic;FEE3 +meemmedialarabic;FEE4 +meemmeeminitialarabic;FCD1 +meemmeemisolatedarabic;FC48 +meetorusquare;334D +mehiragana;3081 +meizierasquare;337E +mekatakana;30E1 +mekatakanahalfwidth;FF92 +mem;05DE +memdagesh;FB3E +memdageshhebrew;FB3E +memhebrew;05DE +menarmenian;0574 +merkhahebrew;05A5 +merkhakefulahebrew;05A6 +merkhakefulalefthebrew;05A6 +merkhalefthebrew;05A5 +mhook;0271 +mhzsquare;3392 +middledotkatakanahalfwidth;FF65 +middot;00B7 +mieumacirclekorean;3272 +mieumaparenkorean;3212 +mieumcirclekorean;3264 +mieumkorean;3141 +mieumpansioskorean;3170 +mieumparenkorean;3204 +mieumpieupkorean;316E +mieumsioskorean;316F +mihiragana;307F +mikatakana;30DF +mikatakanahalfwidth;FF90 +minus;2212 +minusbelowcmb;0320 +minuscircle;2296 +minusmod;02D7 +minusplus;2213 +minute;2032 +miribaarusquare;334A +mirisquare;3349 +mlonglegturned;0270 +mlsquare;3396 +mmcubedsquare;33A3 +mmonospace;FF4D +mmsquaredsquare;339F +mohiragana;3082 +mohmsquare;33C1 +mokatakana;30E2 +mokatakanahalfwidth;FF93 +molsquare;33D6 +momathai;0E21 +moverssquare;33A7 +moverssquaredsquare;33A8 +mparen;24A8 +mpasquare;33AB +mssquare;33B3 +msuperior;F6EF +mturned;026F +mu;00B5 +mu1;00B5 +muasquare;3382 +muchgreater;226B +muchless;226A +mufsquare;338C +mugreek;03BC +mugsquare;338D +muhiragana;3080 +mukatakana;30E0 +mukatakanahalfwidth;FF91 +mulsquare;3395 +multiply;00D7 +mumsquare;339B +munahhebrew;05A3 +munahlefthebrew;05A3 +musicalnote;266A +musicalnotedbl;266B +musicflatsign;266D +musicsharpsign;266F +mussquare;33B2 +muvsquare;33B6 +muwsquare;33BC +mvmegasquare;33B9 +mvsquare;33B7 +mwmegasquare;33BF +mwsquare;33BD +n;006E +nabengali;09A8 +nabla;2207 +nacute;0144 +nadeva;0928 +nagujarati;0AA8 +nagurmukhi;0A28 +nahiragana;306A +nakatakana;30CA +nakatakanahalfwidth;FF85 +napostrophe;0149 +nasquare;3381 +nbopomofo;310B +nbspace;00A0 +ncaron;0148 +ncedilla;0146 +ncircle;24DD +ncircumflexbelow;1E4B +ncommaaccent;0146 +ndotaccent;1E45 +ndotbelow;1E47 +nehiragana;306D +nekatakana;30CD +nekatakanahalfwidth;FF88 +newsheqelsign;20AA +nfsquare;338B +ngabengali;0999 +ngadeva;0919 +ngagujarati;0A99 +ngagurmukhi;0A19 +ngonguthai;0E07 +nhiragana;3093 +nhookleft;0272 +nhookretroflex;0273 +nieunacirclekorean;326F +nieunaparenkorean;320F +nieuncieuckorean;3135 +nieuncirclekorean;3261 +nieunhieuhkorean;3136 +nieunkorean;3134 +nieunpansioskorean;3168 +nieunparenkorean;3201 +nieunsioskorean;3167 +nieuntikeutkorean;3166 +nihiragana;306B +nikatakana;30CB +nikatakanahalfwidth;FF86 +nikhahitleftthai;F899 +nikhahitthai;0E4D +nine;0039 +ninearabic;0669 +ninebengali;09EF +ninecircle;2468 +ninecircleinversesansserif;2792 +ninedeva;096F +ninegujarati;0AEF +ninegurmukhi;0A6F +ninehackarabic;0669 +ninehangzhou;3029 +nineideographicparen;3228 +nineinferior;2089 +ninemonospace;FF19 +nineoldstyle;F739 +nineparen;247C +nineperiod;2490 +ninepersian;06F9 +nineroman;2178 +ninesuperior;2079 +nineteencircle;2472 +nineteenparen;2486 +nineteenperiod;249A +ninethai;0E59 +nj;01CC +njecyrillic;045A +nkatakana;30F3 +nkatakanahalfwidth;FF9D +nlegrightlong;019E +nlinebelow;1E49 +nmonospace;FF4E +nmsquare;339A +nnabengali;09A3 +nnadeva;0923 +nnagujarati;0AA3 +nnagurmukhi;0A23 +nnnadeva;0929 +nohiragana;306E +nokatakana;30CE +nokatakanahalfwidth;FF89 +nonbreakingspace;00A0 +nonenthai;0E13 +nonuthai;0E19 +noonarabic;0646 +noonfinalarabic;FEE6 +noonghunnaarabic;06BA +noonghunnafinalarabic;FB9F +noonhehinitialarabic;FEE7 FEEC +nooninitialarabic;FEE7 +noonjeeminitialarabic;FCD2 +noonjeemisolatedarabic;FC4B +noonmedialarabic;FEE8 +noonmeeminitialarabic;FCD5 +noonmeemisolatedarabic;FC4E +noonnoonfinalarabic;FC8D +notcontains;220C +notelement;2209 +notelementof;2209 +notequal;2260 +notgreater;226F +notgreaternorequal;2271 +notgreaternorless;2279 +notidentical;2262 +notless;226E +notlessnorequal;2270 +notparallel;2226 +notprecedes;2280 +notsubset;2284 +notsucceeds;2281 +notsuperset;2285 +nowarmenian;0576 +nparen;24A9 +nssquare;33B1 +nsuperior;207F +ntilde;00F1 +nu;03BD +nuhiragana;306C +nukatakana;30CC +nukatakanahalfwidth;FF87 +nuktabengali;09BC +nuktadeva;093C +nuktagujarati;0ABC +nuktagurmukhi;0A3C +numbersign;0023 +numbersignmonospace;FF03 +numbersignsmall;FE5F +numeralsigngreek;0374 +numeralsignlowergreek;0375 +numero;2116 +nun;05E0 +nundagesh;FB40 +nundageshhebrew;FB40 +nunhebrew;05E0 +nvsquare;33B5 +nwsquare;33BB +nyabengali;099E +nyadeva;091E +nyagujarati;0A9E +nyagurmukhi;0A1E +o;006F +oacute;00F3 +oangthai;0E2D +obarred;0275 +obarredcyrillic;04E9 +obarreddieresiscyrillic;04EB +obengali;0993 +obopomofo;311B +obreve;014F +ocandradeva;0911 +ocandragujarati;0A91 +ocandravowelsigndeva;0949 +ocandravowelsigngujarati;0AC9 +ocaron;01D2 +ocircle;24DE +ocircumflex;00F4 +ocircumflexacute;1ED1 +ocircumflexdotbelow;1ED9 +ocircumflexgrave;1ED3 +ocircumflexhookabove;1ED5 +ocircumflextilde;1ED7 +ocyrillic;043E +odblacute;0151 +odblgrave;020D +odeva;0913 +odieresis;00F6 +odieresiscyrillic;04E7 +odotbelow;1ECD +oe;0153 +oekorean;315A +ogonek;02DB +ogonekcmb;0328 +ograve;00F2 +ogujarati;0A93 +oharmenian;0585 +ohiragana;304A +ohookabove;1ECF +ohorn;01A1 +ohornacute;1EDB +ohorndotbelow;1EE3 +ohorngrave;1EDD +ohornhookabove;1EDF +ohorntilde;1EE1 +ohungarumlaut;0151 +oi;01A3 +oinvertedbreve;020F +okatakana;30AA +okatakanahalfwidth;FF75 +okorean;3157 +olehebrew;05AB +omacron;014D +omacronacute;1E53 +omacrongrave;1E51 +omdeva;0950 +omega;03C9 +omega1;03D6 +omegacyrillic;0461 +omegalatinclosed;0277 +omegaroundcyrillic;047B +omegatitlocyrillic;047D +omegatonos;03CE +omgujarati;0AD0 +omicron;03BF +omicrontonos;03CC +omonospace;FF4F +one;0031 +onearabic;0661 +onebengali;09E7 +onecircle;2460 +onecircleinversesansserif;278A +onedeva;0967 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onegujarati;0AE7 +onegurmukhi;0A67 +onehackarabic;0661 +onehalf;00BD +onehangzhou;3021 +oneideographicparen;3220 +oneinferior;2081 +onemonospace;FF11 +onenumeratorbengali;09F4 +oneoldstyle;F731 +oneparen;2474 +oneperiod;2488 +onepersian;06F1 +onequarter;00BC +oneroman;2170 +onesuperior;00B9 +onethai;0E51 +onethird;2153 +oogonek;01EB +oogonekmacron;01ED +oogurmukhi;0A13 +oomatragurmukhi;0A4B +oopen;0254 +oparen;24AA +openbullet;25E6 +option;2325 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oshortdeva;0912 +oshortvowelsigndeva;094A +oslash;00F8 +oslashacute;01FF +osmallhiragana;3049 +osmallkatakana;30A9 +osmallkatakanahalfwidth;FF6B +ostrokeacute;01FF +osuperior;F6F0 +otcyrillic;047F +otilde;00F5 +otildeacute;1E4D +otildedieresis;1E4F +oubopomofo;3121 +overline;203E +overlinecenterline;FE4A +overlinecmb;0305 +overlinedashed;FE49 +overlinedblwavy;FE4C +overlinewavy;FE4B +overscore;00AF +ovowelsignbengali;09CB +ovowelsigndeva;094B +ovowelsigngujarati;0ACB +p;0070 +paampssquare;3380 +paasentosquare;332B +pabengali;09AA +pacute;1E55 +padeva;092A +pagedown;21DF +pageup;21DE +pagujarati;0AAA +pagurmukhi;0A2A +pahiragana;3071 +paiyannoithai;0E2F +pakatakana;30D1 +palatalizationcyrilliccmb;0484 +palochkacyrillic;04C0 +pansioskorean;317F +paragraph;00B6 +parallel;2225 +parenleft;0028 +parenleftaltonearabic;FD3E +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftmonospace;FF08 +parenleftsmall;FE59 +parenleftsuperior;207D +parenlefttp;F8EB +parenleftvertical;FE35 +parenright;0029 +parenrightaltonearabic;FD3F +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightmonospace;FF09 +parenrightsmall;FE5A +parenrightsuperior;207E +parenrighttp;F8F6 +parenrightvertical;FE36 +partialdiff;2202 +paseqhebrew;05C0 +pashtahebrew;0599 +pasquare;33A9 +patah;05B7 +patah11;05B7 +patah1d;05B7 +patah2a;05B7 +patahhebrew;05B7 +patahnarrowhebrew;05B7 +patahquarterhebrew;05B7 +patahwidehebrew;05B7 +pazerhebrew;05A1 +pbopomofo;3106 +pcircle;24DF +pdotaccent;1E57 +pe;05E4 +pecyrillic;043F +pedagesh;FB44 +pedageshhebrew;FB44 +peezisquare;333B +pefinaldageshhebrew;FB43 +peharabic;067E +peharmenian;057A +pehebrew;05E4 +pehfinalarabic;FB57 +pehinitialarabic;FB58 +pehiragana;307A +pehmedialarabic;FB59 +pekatakana;30DA +pemiddlehookcyrillic;04A7 +perafehebrew;FB4E +percent;0025 +percentarabic;066A +percentmonospace;FF05 +percentsmall;FE6A +period;002E +periodarmenian;0589 +periodcentered;00B7 +periodhalfwidth;FF61 +periodinferior;F6E7 +periodmonospace;FF0E +periodsmall;FE52 +periodsuperior;F6E8 +perispomenigreekcmb;0342 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +pfsquare;338A +phabengali;09AB +phadeva;092B +phagujarati;0AAB +phagurmukhi;0A2B +phi;03C6 +phi1;03D5 +phieuphacirclekorean;327A +phieuphaparenkorean;321A +phieuphcirclekorean;326C +phieuphkorean;314D +phieuphparenkorean;320C +philatin;0278 +phinthuthai;0E3A +phisymbolgreek;03D5 +phook;01A5 +phophanthai;0E1E +phophungthai;0E1C +phosamphaothai;0E20 +pi;03C0 +pieupacirclekorean;3273 +pieupaparenkorean;3213 +pieupcieuckorean;3176 +pieupcirclekorean;3265 +pieupkiyeokkorean;3172 +pieupkorean;3142 +pieupparenkorean;3205 +pieupsioskiyeokkorean;3174 +pieupsioskorean;3144 +pieupsiostikeutkorean;3175 +pieupthieuthkorean;3177 +pieuptikeutkorean;3173 +pihiragana;3074 +pikatakana;30D4 +pisymbolgreek;03D6 +piwrarmenian;0583 +plus;002B +plusbelowcmb;031F +pluscircle;2295 +plusminus;00B1 +plusmod;02D6 +plusmonospace;FF0B +plussmall;FE62 +plussuperior;207A +pmonospace;FF50 +pmsquare;33D8 +pohiragana;307D +pointingindexdownwhite;261F +pointingindexleftwhite;261C +pointingindexrightwhite;261E +pointingindexupwhite;261D +pokatakana;30DD +poplathai;0E1B +postalmark;3012 +postalmarkface;3020 +pparen;24AB +precedes;227A +prescription;211E +primemod;02B9 +primereversed;2035 +product;220F +projective;2305 +prolongedkana;30FC +propellor;2318 +propersubset;2282 +propersuperset;2283 +proportion;2237 +proportional;221D +psi;03C8 +psicyrillic;0471 +psilipneumatacyrilliccmb;0486 +pssquare;33B0 +puhiragana;3077 +pukatakana;30D7 +pvsquare;33B4 +pwsquare;33BA +q;0071 +qadeva;0958 +qadmahebrew;05A8 +qafarabic;0642 +qaffinalarabic;FED6 +qafinitialarabic;FED7 +qafmedialarabic;FED8 +qamats;05B8 +qamats10;05B8 +qamats1a;05B8 +qamats1c;05B8 +qamats27;05B8 +qamats29;05B8 +qamats33;05B8 +qamatsde;05B8 +qamatshebrew;05B8 +qamatsnarrowhebrew;05B8 +qamatsqatanhebrew;05B8 +qamatsqatannarrowhebrew;05B8 +qamatsqatanquarterhebrew;05B8 +qamatsqatanwidehebrew;05B8 +qamatsquarterhebrew;05B8 +qamatswidehebrew;05B8 +qarneyparahebrew;059F +qbopomofo;3111 +qcircle;24E0 +qhook;02A0 +qmonospace;FF51 +qof;05E7 +qofdagesh;FB47 +qofdageshhebrew;FB47 +qofhatafpatah;05E7 05B2 +qofhatafpatahhebrew;05E7 05B2 +qofhatafsegol;05E7 05B1 +qofhatafsegolhebrew;05E7 05B1 +qofhebrew;05E7 +qofhiriq;05E7 05B4 +qofhiriqhebrew;05E7 05B4 +qofholam;05E7 05B9 +qofholamhebrew;05E7 05B9 +qofpatah;05E7 05B7 +qofpatahhebrew;05E7 05B7 +qofqamats;05E7 05B8 +qofqamatshebrew;05E7 05B8 +qofqubuts;05E7 05BB +qofqubutshebrew;05E7 05BB +qofsegol;05E7 05B6 +qofsegolhebrew;05E7 05B6 +qofsheva;05E7 05B0 +qofshevahebrew;05E7 05B0 +qoftsere;05E7 05B5 +qoftserehebrew;05E7 05B5 +qparen;24AC +quarternote;2669 +qubuts;05BB +qubuts18;05BB +qubuts25;05BB +qubuts31;05BB +qubutshebrew;05BB +qubutsnarrowhebrew;05BB +qubutsquarterhebrew;05BB +qubutswidehebrew;05BB +question;003F +questionarabic;061F +questionarmenian;055E +questiondown;00BF +questiondownsmall;F7BF +questiongreek;037E +questionmonospace;FF1F +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblmonospace;FF02 +quotedblprime;301E +quotedblprimereversed;301D +quotedblright;201D +quoteleft;2018 +quoteleftreversed;201B +quotereversed;201B +quoteright;2019 +quoterightn;0149 +quotesinglbase;201A +quotesingle;0027 +quotesinglemonospace;FF07 +r;0072 +raarmenian;057C +rabengali;09B0 +racute;0155 +radeva;0930 +radical;221A +radicalex;F8E5 +radoverssquare;33AE +radoverssquaredsquare;33AF +radsquare;33AD +rafe;05BF +rafehebrew;05BF +ragujarati;0AB0 +ragurmukhi;0A30 +rahiragana;3089 +rakatakana;30E9 +rakatakanahalfwidth;FF97 +ralowerdiagonalbengali;09F1 +ramiddlediagonalbengali;09F0 +ramshorn;0264 +ratio;2236 +rbopomofo;3116 +rcaron;0159 +rcedilla;0157 +rcircle;24E1 +rcommaaccent;0157 +rdblgrave;0211 +rdotaccent;1E59 +rdotbelow;1E5B +rdotbelowmacron;1E5D +referencemark;203B +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +reharabic;0631 +reharmenian;0580 +rehfinalarabic;FEAE +rehiragana;308C +rehyehaleflamarabic;0631 FEF3 FE8E 0644 +rekatakana;30EC +rekatakanahalfwidth;FF9A +resh;05E8 +reshdageshhebrew;FB48 +reshhatafpatah;05E8 05B2 +reshhatafpatahhebrew;05E8 05B2 +reshhatafsegol;05E8 05B1 +reshhatafsegolhebrew;05E8 05B1 +reshhebrew;05E8 +reshhiriq;05E8 05B4 +reshhiriqhebrew;05E8 05B4 +reshholam;05E8 05B9 +reshholamhebrew;05E8 05B9 +reshpatah;05E8 05B7 +reshpatahhebrew;05E8 05B7 +reshqamats;05E8 05B8 +reshqamatshebrew;05E8 05B8 +reshqubuts;05E8 05BB +reshqubutshebrew;05E8 05BB +reshsegol;05E8 05B6 +reshsegolhebrew;05E8 05B6 +reshsheva;05E8 05B0 +reshshevahebrew;05E8 05B0 +reshtsere;05E8 05B5 +reshtserehebrew;05E8 05B5 +reversedtilde;223D +reviahebrew;0597 +reviamugrashhebrew;0597 +revlogicalnot;2310 +rfishhook;027E +rfishhookreversed;027F +rhabengali;09DD +rhadeva;095D +rho;03C1 +rhook;027D +rhookturned;027B +rhookturnedsuperior;02B5 +rhosymbolgreek;03F1 +rhotichookmod;02DE +rieulacirclekorean;3271 +rieulaparenkorean;3211 +rieulcirclekorean;3263 +rieulhieuhkorean;3140 +rieulkiyeokkorean;313A +rieulkiyeoksioskorean;3169 +rieulkorean;3139 +rieulmieumkorean;313B +rieulpansioskorean;316C +rieulparenkorean;3203 +rieulphieuphkorean;313F +rieulpieupkorean;313C +rieulpieupsioskorean;316B +rieulsioskorean;313D +rieulthieuthkorean;313E +rieultikeutkorean;316A +rieulyeorinhieuhkorean;316D +rightangle;221F +righttackbelowcmb;0319 +righttriangle;22BF +rihiragana;308A +rikatakana;30EA +rikatakanahalfwidth;FF98 +ring;02DA +ringbelowcmb;0325 +ringcmb;030A +ringhalfleft;02BF +ringhalfleftarmenian;0559 +ringhalfleftbelowcmb;031C +ringhalfleftcentered;02D3 +ringhalfright;02BE +ringhalfrightbelowcmb;0339 +ringhalfrightcentered;02D2 +rinvertedbreve;0213 +rittorusquare;3351 +rlinebelow;1E5F +rlongleg;027C +rlonglegturned;027A +rmonospace;FF52 +rohiragana;308D +rokatakana;30ED +rokatakanahalfwidth;FF9B +roruathai;0E23 +rparen;24AD +rrabengali;09DC +rradeva;0931 +rragurmukhi;0A5C +rreharabic;0691 +rrehfinalarabic;FB8D +rrvocalicbengali;09E0 +rrvocalicdeva;0960 +rrvocalicgujarati;0AE0 +rrvocalicvowelsignbengali;09C4 +rrvocalicvowelsigndeva;0944 +rrvocalicvowelsigngujarati;0AC4 +rsuperior;F6F1 +rtblock;2590 +rturned;0279 +rturnedsuperior;02B4 +ruhiragana;308B +rukatakana;30EB +rukatakanahalfwidth;FF99 +rupeemarkbengali;09F2 +rupeesignbengali;09F3 +rupiah;F6DD +ruthai;0E24 +rvocalicbengali;098B +rvocalicdeva;090B +rvocalicgujarati;0A8B +rvocalicvowelsignbengali;09C3 +rvocalicvowelsigndeva;0943 +rvocalicvowelsigngujarati;0AC3 +s;0073 +sabengali;09B8 +sacute;015B +sacutedotaccent;1E65 +sadarabic;0635 +sadeva;0938 +sadfinalarabic;FEBA +sadinitialarabic;FEBB +sadmedialarabic;FEBC +sagujarati;0AB8 +sagurmukhi;0A38 +sahiragana;3055 +sakatakana;30B5 +sakatakanahalfwidth;FF7B +sallallahoualayhewasallamarabic;FDFA +samekh;05E1 +samekhdagesh;FB41 +samekhdageshhebrew;FB41 +samekhhebrew;05E1 +saraaathai;0E32 +saraaethai;0E41 +saraaimaimalaithai;0E44 +saraaimaimuanthai;0E43 +saraamthai;0E33 +saraathai;0E30 +saraethai;0E40 +saraiileftthai;F886 +saraiithai;0E35 +saraileftthai;F885 +saraithai;0E34 +saraothai;0E42 +saraueeleftthai;F888 +saraueethai;0E37 +saraueleftthai;F887 +sarauethai;0E36 +sarauthai;0E38 +sarauuthai;0E39 +sbopomofo;3119 +scaron;0161 +scarondotaccent;1E67 +scedilla;015F +schwa;0259 +schwacyrillic;04D9 +schwadieresiscyrillic;04DB +schwahook;025A +scircle;24E2 +scircumflex;015D +scommaaccent;0219 +sdotaccent;1E61 +sdotbelow;1E63 +sdotbelowdotaccent;1E69 +seagullbelowcmb;033C +second;2033 +secondtonechinese;02CA +section;00A7 +seenarabic;0633 +seenfinalarabic;FEB2 +seeninitialarabic;FEB3 +seenmedialarabic;FEB4 +segol;05B6 +segol13;05B6 +segol1f;05B6 +segol2c;05B6 +segolhebrew;05B6 +segolnarrowhebrew;05B6 +segolquarterhebrew;05B6 +segoltahebrew;0592 +segolwidehebrew;05B6 +seharmenian;057D +sehiragana;305B +sekatakana;30BB +sekatakanahalfwidth;FF7E +semicolon;003B +semicolonarabic;061B +semicolonmonospace;FF1B +semicolonsmall;FE54 +semivoicedmarkkana;309C +semivoicedmarkkanahalfwidth;FF9F +sentisquare;3322 +sentosquare;3323 +seven;0037 +sevenarabic;0667 +sevenbengali;09ED +sevencircle;2466 +sevencircleinversesansserif;2790 +sevendeva;096D +seveneighths;215E +sevengujarati;0AED +sevengurmukhi;0A6D +sevenhackarabic;0667 +sevenhangzhou;3027 +sevenideographicparen;3226 +seveninferior;2087 +sevenmonospace;FF17 +sevenoldstyle;F737 +sevenparen;247A +sevenperiod;248E +sevenpersian;06F7 +sevenroman;2176 +sevensuperior;2077 +seventeencircle;2470 +seventeenparen;2484 +seventeenperiod;2498 +seventhai;0E57 +sfthyphen;00AD +shaarmenian;0577 +shabengali;09B6 +shacyrillic;0448 +shaddaarabic;0651 +shaddadammaarabic;FC61 +shaddadammatanarabic;FC5E +shaddafathaarabic;FC60 +shaddafathatanarabic;0651 064B +shaddakasraarabic;FC62 +shaddakasratanarabic;FC5F +shade;2592 +shadedark;2593 +shadelight;2591 +shademedium;2592 +shadeva;0936 +shagujarati;0AB6 +shagurmukhi;0A36 +shalshelethebrew;0593 +shbopomofo;3115 +shchacyrillic;0449 +sheenarabic;0634 +sheenfinalarabic;FEB6 +sheeninitialarabic;FEB7 +sheenmedialarabic;FEB8 +sheicoptic;03E3 +sheqel;20AA +sheqelhebrew;20AA +sheva;05B0 +sheva115;05B0 +sheva15;05B0 +sheva22;05B0 +sheva2e;05B0 +shevahebrew;05B0 +shevanarrowhebrew;05B0 +shevaquarterhebrew;05B0 +shevawidehebrew;05B0 +shhacyrillic;04BB +shimacoptic;03ED +shin;05E9 +shindagesh;FB49 +shindageshhebrew;FB49 +shindageshshindot;FB2C +shindageshshindothebrew;FB2C +shindageshsindot;FB2D +shindageshsindothebrew;FB2D +shindothebrew;05C1 +shinhebrew;05E9 +shinshindot;FB2A +shinshindothebrew;FB2A +shinsindot;FB2B +shinsindothebrew;FB2B +shook;0282 +sigma;03C3 +sigma1;03C2 +sigmafinal;03C2 +sigmalunatesymbolgreek;03F2 +sihiragana;3057 +sikatakana;30B7 +sikatakanahalfwidth;FF7C +siluqhebrew;05BD +siluqlefthebrew;05BD +similar;223C +sindothebrew;05C2 +siosacirclekorean;3274 +siosaparenkorean;3214 +sioscieuckorean;317E +sioscirclekorean;3266 +sioskiyeokkorean;317A +sioskorean;3145 +siosnieunkorean;317B +siosparenkorean;3206 +siospieupkorean;317D +siostikeutkorean;317C +six;0036 +sixarabic;0666 +sixbengali;09EC +sixcircle;2465 +sixcircleinversesansserif;278F +sixdeva;096C +sixgujarati;0AEC +sixgurmukhi;0A6C +sixhackarabic;0666 +sixhangzhou;3026 +sixideographicparen;3225 +sixinferior;2086 +sixmonospace;FF16 +sixoldstyle;F736 +sixparen;2479 +sixperiod;248D +sixpersian;06F6 +sixroman;2175 +sixsuperior;2076 +sixteencircle;246F +sixteencurrencydenominatorbengali;09F9 +sixteenparen;2483 +sixteenperiod;2497 +sixthai;0E56 +slash;002F +slashmonospace;FF0F +slong;017F +slongdotaccent;1E9B +smileface;263A +smonospace;FF53 +sofpasuqhebrew;05C3 +softhyphen;00AD +softsigncyrillic;044C +sohiragana;305D +sokatakana;30BD +sokatakanahalfwidth;FF7F +soliduslongoverlaycmb;0338 +solidusshortoverlaycmb;0337 +sorusithai;0E29 +sosalathai;0E28 +sosothai;0E0B +sosuathai;0E2A +space;0020 +spacehackarabic;0020 +spade;2660 +spadesuitblack;2660 +spadesuitwhite;2664 +sparen;24AE +squarebelowcmb;033B +squarecc;33C4 +squarecm;339D +squarediagonalcrosshatchfill;25A9 +squarehorizontalfill;25A4 +squarekg;338F +squarekm;339E +squarekmcapital;33CE +squareln;33D1 +squarelog;33D2 +squaremg;338E +squaremil;33D5 +squaremm;339C +squaremsquared;33A1 +squareorthogonalcrosshatchfill;25A6 +squareupperlefttolowerrightfill;25A7 +squareupperrighttolowerleftfill;25A8 +squareverticalfill;25A5 +squarewhitewithsmallblack;25A3 +srsquare;33DB +ssabengali;09B7 +ssadeva;0937 +ssagujarati;0AB7 +ssangcieuckorean;3149 +ssanghieuhkorean;3185 +ssangieungkorean;3180 +ssangkiyeokkorean;3132 +ssangnieunkorean;3165 +ssangpieupkorean;3143 +ssangsioskorean;3146 +ssangtikeutkorean;3138 +ssuperior;F6F2 +sterling;00A3 +sterlingmonospace;FFE1 +strokelongoverlaycmb;0336 +strokeshortoverlaycmb;0335 +subset;2282 +subsetnotequal;228A +subsetorequal;2286 +succeeds;227B +suchthat;220B +suhiragana;3059 +sukatakana;30B9 +sukatakanahalfwidth;FF7D +sukunarabic;0652 +summation;2211 +sun;263C +superset;2283 +supersetnotequal;228B +supersetorequal;2287 +svsquare;33DC +syouwaerasquare;337C +t;0074 +tabengali;09A4 +tackdown;22A4 +tackleft;22A3 +tadeva;0924 +tagujarati;0AA4 +tagurmukhi;0A24 +taharabic;0637 +tahfinalarabic;FEC2 +tahinitialarabic;FEC3 +tahiragana;305F +tahmedialarabic;FEC4 +taisyouerasquare;337D +takatakana;30BF +takatakanahalfwidth;FF80 +tatweelarabic;0640 +tau;03C4 +tav;05EA +tavdages;FB4A +tavdagesh;FB4A +tavdageshhebrew;FB4A +tavhebrew;05EA +tbar;0167 +tbopomofo;310A +tcaron;0165 +tccurl;02A8 +tcedilla;0163 +tcheharabic;0686 +tchehfinalarabic;FB7B +tchehinitialarabic;FB7C +tchehmedialarabic;FB7D +tchehmeeminitialarabic;FB7C FEE4 +tcircle;24E3 +tcircumflexbelow;1E71 +tcommaaccent;0163 +tdieresis;1E97 +tdotaccent;1E6B +tdotbelow;1E6D +tecyrillic;0442 +tedescendercyrillic;04AD +teharabic;062A +tehfinalarabic;FE96 +tehhahinitialarabic;FCA2 +tehhahisolatedarabic;FC0C +tehinitialarabic;FE97 +tehiragana;3066 +tehjeeminitialarabic;FCA1 +tehjeemisolatedarabic;FC0B +tehmarbutaarabic;0629 +tehmarbutafinalarabic;FE94 +tehmedialarabic;FE98 +tehmeeminitialarabic;FCA4 +tehmeemisolatedarabic;FC0E +tehnoonfinalarabic;FC73 +tekatakana;30C6 +tekatakanahalfwidth;FF83 +telephone;2121 +telephoneblack;260E +telishagedolahebrew;05A0 +telishaqetanahebrew;05A9 +tencircle;2469 +tenideographicparen;3229 +tenparen;247D +tenperiod;2491 +tenroman;2179 +tesh;02A7 +tet;05D8 +tetdagesh;FB38 +tetdageshhebrew;FB38 +tethebrew;05D8 +tetsecyrillic;04B5 +tevirhebrew;059B +tevirlefthebrew;059B +thabengali;09A5 +thadeva;0925 +thagujarati;0AA5 +thagurmukhi;0A25 +thalarabic;0630 +thalfinalarabic;FEAC +thanthakhatlowleftthai;F898 +thanthakhatlowrightthai;F897 +thanthakhatthai;0E4C +thanthakhatupperleftthai;F896 +theharabic;062B +thehfinalarabic;FE9A +thehinitialarabic;FE9B +thehmedialarabic;FE9C +thereexists;2203 +therefore;2234 +theta;03B8 +theta1;03D1 +thetasymbolgreek;03D1 +thieuthacirclekorean;3279 +thieuthaparenkorean;3219 +thieuthcirclekorean;326B +thieuthkorean;314C +thieuthparenkorean;320B +thirteencircle;246C +thirteenparen;2480 +thirteenperiod;2494 +thonangmonthothai;0E11 +thook;01AD +thophuthaothai;0E12 +thorn;00FE +thothahanthai;0E17 +thothanthai;0E10 +thothongthai;0E18 +thothungthai;0E16 +thousandcyrillic;0482 +thousandsseparatorarabic;066C +thousandsseparatorpersian;066C +three;0033 +threearabic;0663 +threebengali;09E9 +threecircle;2462 +threecircleinversesansserif;278C +threedeva;0969 +threeeighths;215C +threegujarati;0AE9 +threegurmukhi;0A69 +threehackarabic;0663 +threehangzhou;3023 +threeideographicparen;3222 +threeinferior;2083 +threemonospace;FF13 +threenumeratorbengali;09F6 +threeoldstyle;F733 +threeparen;2476 +threeperiod;248A +threepersian;06F3 +threequarters;00BE +threequartersemdash;F6DE +threeroman;2172 +threesuperior;00B3 +threethai;0E53 +thzsquare;3394 +tihiragana;3061 +tikatakana;30C1 +tikatakanahalfwidth;FF81 +tikeutacirclekorean;3270 +tikeutaparenkorean;3210 +tikeutcirclekorean;3262 +tikeutkorean;3137 +tikeutparenkorean;3202 +tilde;02DC +tildebelowcmb;0330 +tildecmb;0303 +tildecomb;0303 +tildedoublecmb;0360 +tildeoperator;223C +tildeoverlaycmb;0334 +tildeverticalcmb;033E +timescircle;2297 +tipehahebrew;0596 +tipehalefthebrew;0596 +tippigurmukhi;0A70 +titlocyrilliccmb;0483 +tiwnarmenian;057F +tlinebelow;1E6F +tmonospace;FF54 +toarmenian;0569 +tohiragana;3068 +tokatakana;30C8 +tokatakanahalfwidth;FF84 +tonebarextrahighmod;02E5 +tonebarextralowmod;02E9 +tonebarhighmod;02E6 +tonebarlowmod;02E8 +tonebarmidmod;02E7 +tonefive;01BD +tonesix;0185 +tonetwo;01A8 +tonos;0384 +tonsquare;3327 +topatakthai;0E0F +tortoiseshellbracketleft;3014 +tortoiseshellbracketleftsmall;FE5D +tortoiseshellbracketleftvertical;FE39 +tortoiseshellbracketright;3015 +tortoiseshellbracketrightsmall;FE5E +tortoiseshellbracketrightvertical;FE3A +totaothai;0E15 +tpalatalhook;01AB +tparen;24AF +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +tretroflexhook;0288 +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +ts;02A6 +tsadi;05E6 +tsadidagesh;FB46 +tsadidageshhebrew;FB46 +tsadihebrew;05E6 +tsecyrillic;0446 +tsere;05B5 +tsere12;05B5 +tsere1e;05B5 +tsere2b;05B5 +tserehebrew;05B5 +tserenarrowhebrew;05B5 +tserequarterhebrew;05B5 +tserewidehebrew;05B5 +tshecyrillic;045B +tsuperior;F6F3 +ttabengali;099F +ttadeva;091F +ttagujarati;0A9F +ttagurmukhi;0A1F +tteharabic;0679 +ttehfinalarabic;FB67 +ttehinitialarabic;FB68 +ttehmedialarabic;FB69 +tthabengali;09A0 +tthadeva;0920 +tthagujarati;0AA0 +tthagurmukhi;0A20 +tturned;0287 +tuhiragana;3064 +tukatakana;30C4 +tukatakanahalfwidth;FF82 +tusmallhiragana;3063 +tusmallkatakana;30C3 +tusmallkatakanahalfwidth;FF6F +twelvecircle;246B +twelveparen;247F +twelveperiod;2493 +twelveroman;217B +twentycircle;2473 +twentyhangzhou;5344 +twentyparen;2487 +twentyperiod;249B +two;0032 +twoarabic;0662 +twobengali;09E8 +twocircle;2461 +twocircleinversesansserif;278B +twodeva;0968 +twodotenleader;2025 +twodotleader;2025 +twodotleadervertical;FE30 +twogujarati;0AE8 +twogurmukhi;0A68 +twohackarabic;0662 +twohangzhou;3022 +twoideographicparen;3221 +twoinferior;2082 +twomonospace;FF12 +twonumeratorbengali;09F5 +twooldstyle;F732 +twoparen;2475 +twoperiod;2489 +twopersian;06F2 +tworoman;2171 +twostroke;01BB +twosuperior;00B2 +twothai;0E52 +twothirds;2154 +u;0075 +uacute;00FA +ubar;0289 +ubengali;0989 +ubopomofo;3128 +ubreve;016D +ucaron;01D4 +ucircle;24E4 +ucircumflex;00FB +ucircumflexbelow;1E77 +ucyrillic;0443 +udattadeva;0951 +udblacute;0171 +udblgrave;0215 +udeva;0909 +udieresis;00FC +udieresisacute;01D8 +udieresisbelow;1E73 +udieresiscaron;01DA +udieresiscyrillic;04F1 +udieresisgrave;01DC +udieresismacron;01D6 +udotbelow;1EE5 +ugrave;00F9 +ugujarati;0A89 +ugurmukhi;0A09 +uhiragana;3046 +uhookabove;1EE7 +uhorn;01B0 +uhornacute;1EE9 +uhorndotbelow;1EF1 +uhorngrave;1EEB +uhornhookabove;1EED +uhorntilde;1EEF +uhungarumlaut;0171 +uhungarumlautcyrillic;04F3 +uinvertedbreve;0217 +ukatakana;30A6 +ukatakanahalfwidth;FF73 +ukcyrillic;0479 +ukorean;315C +umacron;016B +umacroncyrillic;04EF +umacrondieresis;1E7B +umatragurmukhi;0A41 +umonospace;FF55 +underscore;005F +underscoredbl;2017 +underscoremonospace;FF3F +underscorevertical;FE33 +underscorewavy;FE4F +union;222A +universal;2200 +uogonek;0173 +uparen;24B0 +upblock;2580 +upperdothebrew;05C4 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilonlatin;028A +upsilontonos;03CD +uptackbelowcmb;031D +uptackmod;02D4 +uragurmukhi;0A73 +uring;016F +ushortcyrillic;045E +usmallhiragana;3045 +usmallkatakana;30A5 +usmallkatakanahalfwidth;FF69 +ustraightcyrillic;04AF +ustraightstrokecyrillic;04B1 +utilde;0169 +utildeacute;1E79 +utildebelow;1E75 +uubengali;098A +uudeva;090A +uugujarati;0A8A +uugurmukhi;0A0A +uumatragurmukhi;0A42 +uuvowelsignbengali;09C2 +uuvowelsigndeva;0942 +uuvowelsigngujarati;0AC2 +uvowelsignbengali;09C1 +uvowelsigndeva;0941 +uvowelsigngujarati;0AC1 +v;0076 +vadeva;0935 +vagujarati;0AB5 +vagurmukhi;0A35 +vakatakana;30F7 +vav;05D5 +vavdagesh;FB35 +vavdagesh65;FB35 +vavdageshhebrew;FB35 +vavhebrew;05D5 +vavholam;FB4B +vavholamhebrew;FB4B +vavvavhebrew;05F0 +vavyodhebrew;05F1 +vcircle;24E5 +vdotbelow;1E7F +vecyrillic;0432 +veharabic;06A4 +vehfinalarabic;FB6B +vehinitialarabic;FB6C +vehmedialarabic;FB6D +vekatakana;30F9 +venus;2640 +verticalbar;007C +verticallineabovecmb;030D +verticallinebelowcmb;0329 +verticallinelowmod;02CC +verticallinemod;02C8 +vewarmenian;057E +vhook;028B +vikatakana;30F8 +viramabengali;09CD +viramadeva;094D +viramagujarati;0ACD +visargabengali;0983 +visargadeva;0903 +visargagujarati;0A83 +vmonospace;FF56 +voarmenian;0578 +voicediterationhiragana;309E +voicediterationkatakana;30FE +voicedmarkkana;309B +voicedmarkkanahalfwidth;FF9E +vokatakana;30FA +vparen;24B1 +vtilde;1E7D +vturned;028C +vuhiragana;3094 +vukatakana;30F4 +w;0077 +wacute;1E83 +waekorean;3159 +wahiragana;308F +wakatakana;30EF +wakatakanahalfwidth;FF9C +wakorean;3158 +wasmallhiragana;308E +wasmallkatakana;30EE +wattosquare;3357 +wavedash;301C +wavyunderscorevertical;FE34 +wawarabic;0648 +wawfinalarabic;FEEE +wawhamzaabovearabic;0624 +wawhamzaabovefinalarabic;FE86 +wbsquare;33DD +wcircle;24E6 +wcircumflex;0175 +wdieresis;1E85 +wdotaccent;1E87 +wdotbelow;1E89 +wehiragana;3091 +weierstrass;2118 +wekatakana;30F1 +wekorean;315E +weokorean;315D +wgrave;1E81 +whitebullet;25E6 +whitecircle;25CB +whitecircleinverse;25D9 +whitecornerbracketleft;300E +whitecornerbracketleftvertical;FE43 +whitecornerbracketright;300F +whitecornerbracketrightvertical;FE44 +whitediamond;25C7 +whitediamondcontainingblacksmalldiamond;25C8 +whitedownpointingsmalltriangle;25BF +whitedownpointingtriangle;25BD +whiteleftpointingsmalltriangle;25C3 +whiteleftpointingtriangle;25C1 +whitelenticularbracketleft;3016 +whitelenticularbracketright;3017 +whiterightpointingsmalltriangle;25B9 +whiterightpointingtriangle;25B7 +whitesmallsquare;25AB +whitesmilingface;263A +whitesquare;25A1 +whitestar;2606 +whitetelephone;260F +whitetortoiseshellbracketleft;3018 +whitetortoiseshellbracketright;3019 +whiteuppointingsmalltriangle;25B5 +whiteuppointingtriangle;25B3 +wihiragana;3090 +wikatakana;30F0 +wikorean;315F +wmonospace;FF57 +wohiragana;3092 +wokatakana;30F2 +wokatakanahalfwidth;FF66 +won;20A9 +wonmonospace;FFE6 +wowaenthai;0E27 +wparen;24B2 +wring;1E98 +wsuperior;02B7 +wturned;028D +wynn;01BF +x;0078 +xabovecmb;033D +xbopomofo;3112 +xcircle;24E7 +xdieresis;1E8D +xdotaccent;1E8B +xeharmenian;056D +xi;03BE +xmonospace;FF58 +xparen;24B3 +xsuperior;02E3 +y;0079 +yaadosquare;334E +yabengali;09AF +yacute;00FD +yadeva;092F +yaekorean;3152 +yagujarati;0AAF +yagurmukhi;0A2F +yahiragana;3084 +yakatakana;30E4 +yakatakanahalfwidth;FF94 +yakorean;3151 +yamakkanthai;0E4E +yasmallhiragana;3083 +yasmallkatakana;30E3 +yasmallkatakanahalfwidth;FF6C +yatcyrillic;0463 +ycircle;24E8 +ycircumflex;0177 +ydieresis;00FF +ydotaccent;1E8F +ydotbelow;1EF5 +yeharabic;064A +yehbarreearabic;06D2 +yehbarreefinalarabic;FBAF +yehfinalarabic;FEF2 +yehhamzaabovearabic;0626 +yehhamzaabovefinalarabic;FE8A +yehhamzaaboveinitialarabic;FE8B +yehhamzaabovemedialarabic;FE8C +yehinitialarabic;FEF3 +yehmedialarabic;FEF4 +yehmeeminitialarabic;FCDD +yehmeemisolatedarabic;FC58 +yehnoonfinalarabic;FC94 +yehthreedotsbelowarabic;06D1 +yekorean;3156 +yen;00A5 +yenmonospace;FFE5 +yeokorean;3155 +yeorinhieuhkorean;3186 +yerahbenyomohebrew;05AA +yerahbenyomolefthebrew;05AA +yericyrillic;044B +yerudieresiscyrillic;04F9 +yesieungkorean;3181 +yesieungpansioskorean;3183 +yesieungsioskorean;3182 +yetivhebrew;059A +ygrave;1EF3 +yhook;01B4 +yhookabove;1EF7 +yiarmenian;0575 +yicyrillic;0457 +yikorean;3162 +yinyang;262F +yiwnarmenian;0582 +ymonospace;FF59 +yod;05D9 +yoddagesh;FB39 +yoddageshhebrew;FB39 +yodhebrew;05D9 +yodyodhebrew;05F2 +yodyodpatahhebrew;FB1F +yohiragana;3088 +yoikorean;3189 +yokatakana;30E8 +yokatakanahalfwidth;FF96 +yokorean;315B +yosmallhiragana;3087 +yosmallkatakana;30E7 +yosmallkatakanahalfwidth;FF6E +yotgreek;03F3 +yoyaekorean;3188 +yoyakorean;3187 +yoyakthai;0E22 +yoyingthai;0E0D +yparen;24B4 +ypogegrammeni;037A +ypogegrammenigreekcmb;0345 +yr;01A6 +yring;1E99 +ysuperior;02B8 +ytilde;1EF9 +yturned;028E +yuhiragana;3086 +yuikorean;318C +yukatakana;30E6 +yukatakanahalfwidth;FF95 +yukorean;3160 +yusbigcyrillic;046B +yusbigiotifiedcyrillic;046D +yuslittlecyrillic;0467 +yuslittleiotifiedcyrillic;0469 +yusmallhiragana;3085 +yusmallkatakana;30E5 +yusmallkatakanahalfwidth;FF6D +yuyekorean;318B +yuyeokorean;318A +yyabengali;09DF +yyadeva;095F +z;007A +zaarmenian;0566 +zacute;017A +zadeva;095B +zagurmukhi;0A5B +zaharabic;0638 +zahfinalarabic;FEC6 +zahinitialarabic;FEC7 +zahiragana;3056 +zahmedialarabic;FEC8 +zainarabic;0632 +zainfinalarabic;FEB0 +zakatakana;30B6 +zaqefgadolhebrew;0595 +zaqefqatanhebrew;0594 +zarqahebrew;0598 +zayin;05D6 +zayindagesh;FB36 +zayindageshhebrew;FB36 +zayinhebrew;05D6 +zbopomofo;3117 +zcaron;017E +zcircle;24E9 +zcircumflex;1E91 +zcurl;0291 +zdot;017C +zdotaccent;017C +zdotbelow;1E93 +zecyrillic;0437 +zedescendercyrillic;0499 +zedieresiscyrillic;04DF +zehiragana;305C +zekatakana;30BC +zero;0030 +zeroarabic;0660 +zerobengali;09E6 +zerodeva;0966 +zerogujarati;0AE6 +zerogurmukhi;0A66 +zerohackarabic;0660 +zeroinferior;2080 +zeromonospace;FF10 +zerooldstyle;F730 +zeropersian;06F0 +zerosuperior;2070 +zerothai;0E50 +zerowidthjoiner;FEFF +zerowidthnonjoiner;200C +zerowidthspace;200B +zeta;03B6 +zhbopomofo;3113 +zhearmenian;056A +zhebrevecyrillic;04C2 +zhecyrillic;0436 +zhedescendercyrillic;0497 +zhedieresiscyrillic;04DD +zihiragana;3058 +zikatakana;30B8 +zinorhebrew;05AE +zlinebelow;1E95 +zmonospace;FF5A +zohiragana;305E +zokatakana;30BE +zparen;24B5 +zretroflexhook;0290 +zstroke;01B6 +zuhiragana;305A +zukatakana;30BA +a100;275E +a101;2761 +a102;2762 +a103;2763 +a104;2764 +a105;2710 +a106;2765 +a107;2766 +a108;2767 +a109;2660 +a10;2721 +a110;2665 +a111;2666 +a112;2663 +a117;2709 +a118;2708 +a119;2707 +a11;261B +a120;2460 +a121;2461 +a122;2462 +a123;2463 +a124;2464 +a125;2465 +a126;2466 +a127;2467 +a128;2468 +a129;2469 +a12;261E +a130;2776 +a131;2777 +a132;2778 +a133;2779 +a134;277A +a135;277B +a136;277C +a137;277D +a138;277E +a139;277F +a13;270C +a140;2780 +a141;2781 +a142;2782 +a143;2783 +a144;2784 +a145;2785 +a146;2786 +a147;2787 +a148;2788 +a149;2789 +a14;270D +a150;278A +a151;278B +a152;278C +a153;278D +a154;278E +a155;278F +a156;2790 +a157;2791 +a158;2792 +a159;2793 +a15;270E +a160;2794 +a161;2192 +a162;27A3 +a163;2194 +a164;2195 +a165;2799 +a166;279B +a167;279C +a168;279D +a169;279E +a16;270F +a170;279F +a171;27A0 +a172;27A1 +a173;27A2 +a174;27A4 +a175;27A5 +a176;27A6 +a177;27A7 +a178;27A8 +a179;27A9 +a17;2711 +a180;27AB +a181;27AD +a182;27AF +a183;27B2 +a184;27B3 +a185;27B5 +a186;27B8 +a187;27BA +a188;27BB +a189;27BC +a18;2712 +a190;27BD +a191;27BE +a192;279A +a193;27AA +a194;27B6 +a195;27B9 +a196;2798 +a197;27B4 +a198;27B7 +a199;27AC +a19;2713 +a1;2701 +a200;27AE +a201;27B1 +a202;2703 +a203;2750 +a204;2752 +a205;276E +a206;2770 +a20;2714 +a21;2715 +a22;2716 +a23;2717 +a24;2718 +a25;2719 +a26;271A +a27;271B +a28;271C +a29;2722 +a2;2702 +a30;2723 +a31;2724 +a32;2725 +a33;2726 +a34;2727 +a35;2605 +a36;2729 +a37;272A +a38;272B +a39;272C +a3;2704 +a40;272D +a41;272E +a42;272F +a43;2730 +a44;2731 +a45;2732 +a46;2733 +a47;2734 +a48;2735 +a49;2736 +a4;260E +a50;2737 +a51;2738 +a52;2739 +a53;273A +a54;273B +a55;273C +a56;273D +a57;273E +a58;273F +a59;2740 +a5;2706 +a60;2741 +a61;2742 +a62;2743 +a63;2744 +a64;2745 +a65;2746 +a66;2747 +a67;2748 +a68;2749 +a69;274A +a6;271D +a70;274B +a71;25CF +a72;274D +a73;25A0 +a74;274F +a75;2751 +a76;25B2 +a77;25BC +a78;25C6 +a79;2756 +a7;271E +a81;25D7 +a82;2758 +a83;2759 +a84;275A +a85;276F +a86;2771 +a87;2772 +a88;2773 +a89;2768 +a8;271F +a90;2769 +a91;276C +a92;276D +a93;276A +a94;276B +a95;2774 +a96;2775 +a97;275B +a98;275C +a99;275D +a9;2720 +""" + + +# string table management +# +class StringTable: + def __init__(self, name_list, master_table_name): + self.names = name_list + self.master_table = master_table_name + self.indices = {} + index = 0 + + for name in name_list: + self.indices[name] = index + index += len(name) + 1 + + self.total = index + + def dump(self, file): + write = file.write + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const char " + self.master_table + + "[" + repr(self.total) + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = "" + for name in self.names: + line += " '" + line += "','".join(list(name)) + line += "', 0,\n" + + write(line) + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + def dump_sublist(self, file, table_name, macro_name, sublist): + write = file.write + write("#define " + macro_name + " " + repr(len(sublist)) + "\n\n") + + write(" /* Values are offsets into the `" + + self.master_table + "' table */\n\n") + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const short " + table_name + + "[" + macro_name + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = " " + comma = "" + col = 0 + + for name in sublist: + line += comma + line += "%4d" % self.indices[name] + col += 1 + comma = "," + if col == 14: + col = 0 + comma = ",\n " + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +# We now store the Adobe Glyph List in compressed form. The list is put +# into a data structure called `trie' (because it has a tree-like +# appearance). Consider, for example, that you want to store the +# following name mapping: +# +# A => 1 +# Aacute => 6 +# Abalon => 2 +# Abstract => 4 +# +# It is possible to store the entries as follows. +# +# A => 1 +# | +# +-acute => 6 +# | +# +-b +# | +# +-alon => 2 +# | +# +-stract => 4 +# +# We see that each node in the trie has: +# +# - one or more `letters' +# - an optional value +# - zero or more child nodes +# +# The first step is to call +# +# root = StringNode( "", 0 ) +# for word in map.values(): +# root.add( word, map[word] ) +# +# which creates a large trie where each node has only one children. +# +# Executing +# +# root = root.optimize() +# +# optimizes the trie by merging the letters of successive nodes whenever +# possible. +# +# Each node of the trie is stored as follows. +# +# - First the node's letter, according to the following scheme. We +# use the fact that in the AGL no name contains character codes > 127. +# +# name bitsize description +# ---------------------------------------------------------------- +# notlast 1 Set to 1 if this is not the last letter +# in the word. +# ascii 7 The letter's ASCII value. +# +# - The letter is followed by a children count and the value of the +# current key (if any). Again we can do some optimization because all +# AGL entries are from the BMP; this means that 16 bits are sufficient +# to store its Unicode values. Additionally, no node has more than +# 127 children. +# +# name bitsize description +# ----------------------------------------- +# hasvalue 1 Set to 1 if a 16-bit Unicode value follows. +# num_children 7 Number of children. Can be 0 only if +# `hasvalue' is set to 1. +# value 16 Optional Unicode value. +# +# - A node is finished by a list of 16bit absolute offsets to the +# children, which must be sorted in increasing order of their first +# letter. +# +# For simplicity, all 16bit quantities are stored in big-endian order. +# +# The root node has first letter = 0, and no value. +# +class StringNode: + def __init__(self, letter, value): + self.letter = letter + self.value = value + self.children = {} + + def __cmp__(self, other): + return ord(self.letter[0]) - ord(other.letter[0]) + + def __lt__(self, other): + return self.letter[0] < other.letter[0] + + def add(self, word, value): + if len(word) == 0: + self.value = value + return + + letter = word[0] + word = word[1:] + + if letter in self.children: + child = self.children[letter] + else: + child = StringNode(letter, 0) + self.children[letter] = child + + child.add(word, value) + + def optimize(self): + # optimize all children first + children = list(self.children.values()) + self.children = {} + + for child in children: + self.children[child.letter[0]] = child.optimize() + + # don't optimize if there's a value, + # if we don't have any child or if we + # have more than one child + if (self.value != 0) or (not children) or len(children) > 1: + return self + + child = children[0] + + self.letter += child.letter + self.value = child.value + self.children = child.children + + return self + + def dump_debug(self, write, margin): + # this is used during debugging + line = margin + "+-" + if len(self.letter) == 0: + line += "" + else: + line += self.letter + + if self.value: + line += " => " + repr(self.value) + + write(line + "\n") + + if self.children: + margin += "| " + for child in self.children.values(): + child.dump_debug(write, margin) + + def locate(self, index): + self.index = index + if len(self.letter) > 0: + index += len(self.letter) + 1 + else: + index += 2 + + if self.value != 0: + index += 2 + + children = list(self.children.values()) + children.sort() + + index += 2 * len(children) + for child in children: + index = child.locate(index) + + return index + + def store(self, storage): + # write the letters + length = len(self.letter) + if length == 0: + storage += struct.pack("B", 0) + else: + for n in range(length): + val = ord(self.letter[n]) + if n < length - 1: + val += 128 + storage += struct.pack("B", val) + + # write the count + children = list(self.children.values()) + children.sort() + + count = len(children) + + if self.value != 0: + storage += struct.pack("!BH", count + 128, self.value) + else: + storage += struct.pack("B", count) + + for child in children: + storage += struct.pack("!H", child.index) + + for child in children: + storage = child.store(storage) + + return storage + + +def adobe_glyph_values(): + """return the list of glyph names and their unicode values""" + + lines = adobe_glyph_list.split("\n") + glyphs = [] + values = [] + + for line in lines: + if line: + fields = line.split(';') + # print fields[1] + ' - ' + fields[0] + subfields = fields[1].split(' ') + if len(subfields) == 1: + glyphs.append(fields[0]) + values.append(fields[1]) + + return glyphs, values + + +def filter_glyph_names(alist, filter): + """filter `alist' by taking _out_ all glyph names that are in `filter'""" + + count = 0 + extras = [] + + for name in alist: + try: + filtered_index = filter.index(name) + except: + extras.append(name) + + return extras + + +def dump_encoding(file, encoding_name, encoding_list): + """dump a given encoding""" + + write = file.write + write(" /* the following are indices into the SID name table */\n") + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const unsigned short " + encoding_name + + "[" + repr(len(encoding_list)) + "]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = " " + comma = "" + col = 0 + for value in encoding_list: + line += comma + line += "%3d" % value + comma = "," + col += 1 + if col == 16: + col = 0 + comma = ",\n " + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +def dump_array(the_array, write, array_name): + """dumps a given encoding""" + + write("#ifndef DEFINE_PS_TABLES_DATA\n") + write("#ifdef __cplusplus\n") + write(' extern "C"\n') + write("#else\n") + write(" extern\n") + write("#endif\n") + write("#endif\n") + write(" const unsigned char " + array_name + + "[" + repr(len(the_array)) + "L]\n") + write("#ifdef DEFINE_PS_TABLES_DATA\n") + write(" =\n") + write(" {\n") + + line = "" + comma = " " + col = 0 + + for value in the_array: + line += comma + line += "%3d" % value + comma = "," + col += 1 + + if col == 16: + col = 0 + comma = ",\n " + + if len(line) > 1024: + write(line) + line = "" + + write(line) + write("\n") + write(" }\n") + write("#endif /* DEFINE_PS_TABLES_DATA */\n") + write(" ;\n\n\n") + + +def main(): + """main program body""" + + if len(sys.argv) != 2: + print(__doc__ % sys.argv[0]) + sys.exit(1) + + file = open(sys.argv[1], "w") + write = file.write + + count_sid = len(sid_standard_names) + + # `mac_extras' contains the list of glyph names in the Macintosh standard + # encoding which are not in the SID Standard Names. + # + mac_extras = filter_glyph_names(mac_standard_names, sid_standard_names) + + # `base_list' contains the names of our final glyph names table. + # It consists of the `mac_extras' glyph names, followed by the SID + # standard names. + # + mac_extras_count = len(mac_extras) + base_list = mac_extras + sid_standard_names + + write("/*\n") + write(" *\n") + write(" * %-71s\n" % os.path.basename(sys.argv[1])) + write(" *\n") + write(" * PostScript glyph names.\n") + write(" *\n") + write(" * Copyright 2005-2022 by\n") + write(" * David Turner, Robert Wilhelm, and Werner Lemberg.\n") + write(" *\n") + write(" * This file is part of the FreeType project, and may only be " + "used,\n") + write(" * modified, and distributed under the terms of the FreeType " + "project\n") + write(" * license, LICENSE.TXT. By continuing to use, modify, or " + "distribute\n") + write(" * this file you indicate that you have read the license and\n") + write(" * understand and accept it fully.\n") + write(" *\n") + write(" */\n") + write("\n") + write("\n") + write(" /* This file has been generated automatically -- do not edit! */" + "\n") + write("\n") + write("\n") + + # dump final glyph list (mac extras + sid standard names) + # + st = StringTable(base_list, "ft_standard_glyph_names") + + st.dump(file) + st.dump_sublist(file, "ft_mac_names", + "FT_NUM_MAC_NAMES", mac_standard_names) + st.dump_sublist(file, "ft_sid_names", + "FT_NUM_SID_NAMES", sid_standard_names) + + dump_encoding(file, "t1_standard_encoding", t1_standard_encoding) + dump_encoding(file, "t1_expert_encoding", t1_expert_encoding) + + # dump the AGL in its compressed form + # + agl_glyphs, agl_values = adobe_glyph_values() + dictionary = StringNode("", 0) + + for g in range(len(agl_glyphs)): + dictionary.add(agl_glyphs[g], eval("0x" + agl_values[g])) + + dictionary = dictionary.optimize() + dict_len = dictionary.locate(0) + dict_array = dictionary.store(b"") + + write("""\ + /* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + +#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + +""") + + dump_array(dict_array, write, "ft_adobe_glyph_list") + + # write the lookup routine now + # + write("""\ +#ifdef DEFINE_PS_TABLES + /* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + + + if ( name == 0 || name >= limit ) + goto NotFound; + + c = *name++; + count = p[1]; + p += 2; + + min = 0; + max = count; + + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + + + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + + Found: + for (;;) + { + /* assert (*p & 127) == c */ + + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + + continue; + } + + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + + p++; + + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + + NextIter: + ; + } + + NotFound: + return 0; + } +#endif /* DEFINE_PS_TABLES */ + +#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ + +""") + + if 0: # generate unit test, or don't + # + # now write the unit test to check that everything works OK + # + write("#ifdef TEST\n\n") + + write("static const char* const the_names[] = {\n") + for name in agl_glyphs: + write(' "' + name + '",\n') + write(" 0\n};\n") + + write("static const unsigned long the_values[] = {\n") + for val in agl_values: + write(' 0x' + val + ',\n') + write(" 0\n};\n") + + write(""" +#include +#include +#include + +int +main( void ) +{ +int result = 0; +const char* const* names = the_names; +const unsigned long* values = the_values; + + +for ( ; *names; names++, values++ ) +{ + const char* name = *names; + unsigned long reference = *values; + unsigned long value; + + + value = ft_get_adobe_glyph_index( name, name + strlen( name ) ); + if ( value != reference ) + { + result = 1; + fprintf( stderr, "name '%s' => %04x instead of %04x\\n", + name, value, reference ); + } +} + +return result; +} +""") + + write("#endif /* TEST */\n") + + write("\n/* END */\n") + + +# Now run the main routine +# +main() + +# END diff --git a/Dependencies/freetype/freetype/src/tools/make_distribution_archives.py b/Dependencies/freetype/freetype/src/tools/make_distribution_archives.py new file mode 100644 index 00000000..f29eb128 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/make_distribution_archives.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 +"""Generate distribution archives for a given FreeType 2 release.""" + +from __future__ import print_function + +import argparse +import atexit +import os +import shutil +import subprocess +import sys +import tempfile + +_TOP_DIR = os.path.abspath(os.path.join(__file__, "..", "..", "..")) +_SCRIPT_DIR = os.path.dirname(os.path.join(_TOP_DIR, "builds", "meson", "")) + + +def get_cmd_output(cmd, cwd=None): + """Run a command and return its output as a string.""" + if cwd is not None: + out = subprocess.check_output(cmd, cwd=cwd) + else: + out = subprocess.check_output(cmd) + return out.decode("utf-8").rstrip() + + +def is_git_dir_clean(git_dir): + """Return True iff |git_dir| is a git directory in clean state.""" + out = get_cmd_output(["git", "status", "--porcelain"], cwd=git_dir) + return len(out) == 0 + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + + parser.add_argument( + "--source_dir", default=_TOP_DIR, help="Source directory path." + ) + + parser.add_argument( + "--version", + help=( + "Specify alternate FreeType version (it is otherwise extracted" + " from current sources by default)." + ), + ) + + parser.add_argument( + "--gnu-config-dir", + help=( + "Path of input directory containing recent `config.guess` and" + " `config.sub` files from GNU config." + ), + ) + + parser.add_argument( + "--build-dir", + help="Specify build directory. Only used for debugging this script.", + ) + + parser.add_argument( + "--ignore-clean-check", + action="store_true", + help=( + "Do not check for a clean source git repository. Only used for" + " debugging this script." + ), + ) + + parser.add_argument( + "output_dir", help="Output directory for generated archives." + ) + + args = parser.parse_args() + + git_dir = args.source_dir if args.source_dir else _TOP_DIR + if not args.ignore_clean_check and not is_git_dir_clean(git_dir): + sys.stderr.write( + "ERROR: Your git repository is not in a clean state: %s\n" + % git_dir + ) + return 1 + + if args.version: + version = args.version + else: + # Extract FreeType version from sources. + version = get_cmd_output( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "extract_freetype_version.py"), + os.path.join(_TOP_DIR, "include", "freetype", "freetype.h"), + ] + ) + + # Determine the build directory. This will be a temporary file that is + # cleaned up on script exit by default, unless --build-dir=DIR is used, + # in which case we only create and empty the directory, but never remove + # its content on exit. + if args.build_dir: + build_dir = args.build_dir + if not os.path.exists(build_dir): + os.makedirs(build_dir) + else: + # Remove anything from the build directory, if any. + for item in os.listdir(build_dir): + file_path = os.path.join(build_dir, item) + if os.path.isdir(file_path): + shutil.rmtree(file_path) + else: + os.unlink(file_path) + else: + # Create a temporary directory, and ensure it is removed on exit. + build_dir = tempfile.mkdtemp(prefix="freetype-dist-") + + def clean_build_dir(): + shutil.rmtree(build_dir) + + atexit.register(clean_build_dir) + + # Copy all source files known to git into $BUILD_DIR/freetype-$VERSION + # with the exception of .gitignore and .mailmap files. + source_files = [ + f + for f in get_cmd_output(["git", "ls-files"], cwd=git_dir).split("\n") + if os.path.basename(f) not in (".gitignore", ".mailmap") + ] + + freetype_dir = "freetype-" + version + tmp_src_dir = os.path.join(build_dir, freetype_dir) + os.makedirs(tmp_src_dir) + + for src in source_files: + dst = os.path.join(tmp_src_dir, src) + dst_dir = os.path.dirname(dst) + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + shutil.copy(os.path.join(git_dir, src), dst) + + # Run autogen.sh in directory. + subprocess.check_call(["/bin/sh", "autogen.sh"], cwd=tmp_src_dir) + shutil.rmtree( + os.path.join(tmp_src_dir, "builds", "unix", "autom4te.cache") + ) + + # Copy config.guess and config.sub if possible! + if args.gnu_config_dir: + for f in ("config.guess", "config.sub"): + shutil.copy( + os.path.join(args.gnu_config_dir, f), + os.path.join(tmp_src_dir, "builds", "unix", f), + ) + + # Generate reference documentation under docs/ + subprocess.check_call( + [ + sys.executable, + os.path.join(_SCRIPT_DIR, "generate_reference_docs.py"), + "--input-dir", + tmp_src_dir, + "--version", + version, + "--output-dir", + os.path.join(tmp_src_dir, "docs"), + ] + ) + + shutil.rmtree(os.path.join(tmp_src_dir, "docs", "markdown")) + os.unlink(os.path.join(tmp_src_dir, "docs", "mkdocs.yml")) + + # Generate our archives + freetype_tar = freetype_dir + ".tar" + + subprocess.check_call( + ["tar", "-H", "ustar", "-chf", freetype_tar, freetype_dir], + cwd=build_dir, + ) + + subprocess.check_call( + ["gzip", "-9", "--keep", freetype_tar], cwd=build_dir + ) + + subprocess.check_call(["xz", "--keep", freetype_tar], cwd=build_dir) + + ftwinversion = "ft" + "".join(version.split(".")) + subprocess.check_call( + ["zip", "-qlr9", ftwinversion + ".zip", freetype_dir], cwd=build_dir + ) + + # Copy file to output directory now. + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + + for f in ( + freetype_tar + ".gz", + freetype_tar + ".xz", + ftwinversion + ".zip", + ): + shutil.copy( + os.path.join(build_dir, f), os.path.join(args.output_dir, f) + ) + + # Done! + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Dependencies/freetype/freetype/src/tools/no-copyright b/Dependencies/freetype/freetype/src/tools/no-copyright new file mode 100644 index 00000000..e171b76f --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/no-copyright @@ -0,0 +1,66 @@ +# Files that don't get a copyright, or which are taken from elsewhere. +# +# All lines in this file are patterns (relative to the top-level directory), +# including the comment lines; this means that e.g. `FTL.TXT' matches all +# files that have this string in the file name (including the path relative +# to the current directory, always starting with `./'). +# +# Don't put empty lines into this file! +# +builds/unix/pkg.m4 +# +docs/FTL.TXT +docs/GPLv2.TXT +# +include/freetype/internal/fthash.h +# +src/base/fthash.c +src/base/md5.c +src/base/md5.h +# +src/bdf/bdf.c +src/bdf/bdf.h +src/bdf/bdfdrivr.c +src/bdf/bdfdrivr.h +src/bdf/bdferror.h +src/bdf/bdflib.c +src/bdf/module.mk +src/bdf/README +src/bdf/rules.mk +# +src/pcf/module.mk +src/pcf/pcf.c +src/pcf/pcf.h +src/pcf/pcfdrivr.c +src/pcf/pcfdrivr.h +src/pcf/pcferror.h +src/pcf/pcfread.c +src/pcf/pcfread.h +src/pcf/pcfutil.c +src/pcf/pcfutil.h +src/pcf/README +src/pcf/rules.mk +# +src/gzip/adler32.c +src/gzip/ftzconf.c +src/gzip/infblock.c +src/gzip/infblock.h +src/gzip/infcodes.c +src/gzip/infcodes.h +src/gzip/inffixed.h +src/gzip/inflate.c +src/gzip/inftrees.c +src/gzip/inftrees.h +src/gzip/infutil.c +src/gzip/infutil.h +src/gzip/zconf.h +src/gzip/zlib.h +src/gzip/zutil.c +src/gzip/zutil.h +# +src/tools/apinames.c +src/tools/ftrandom/ftrandom.c +# +subprojects/dlg +# +# EOF diff --git a/Dependencies/freetype/freetype/src/tools/test_afm.c b/Dependencies/freetype/freetype/src/tools/test_afm.c new file mode 100644 index 00000000..a4b22689 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/test_afm.c @@ -0,0 +1,156 @@ +/* + * gcc -DFT2_BUILD_LIBRARY -I../../include -o test_afm test_afm.c \ + * -L../../objs/.libs -lfreetype -lz -static + */ +#include +#include +#include + + void dump_fontinfo( AFM_FontInfo fi ) + { + FT_UInt i; + + + printf( "This AFM is for %sCID font.\n\n", + ( fi->IsCIDFont ) ? "" : "non-" ); + + printf( "FontBBox: %.2f %.2f %.2f %.2f\n", fi->FontBBox.xMin / 65536., + fi->FontBBox.yMin / 65536., + fi->FontBBox.xMax / 65536., + fi->FontBBox.yMax / 65536. ); + printf( "Ascender: %.2f\n", fi->Ascender / 65536. ); + printf( "Descender: %.2f\n\n", fi->Descender / 65536. ); + + if ( fi->NumTrackKern ) + printf( "There are %d sets of track kernings:\n", + fi->NumTrackKern ); + else + printf( "There is no track kerning.\n" ); + + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + + + printf( "\t%2d: %5.2f %5.2f %5.2f %5.2f\n", tk->degree, + tk->min_ptsize / 65536., + tk->min_kern / 65536., + tk->max_ptsize / 65536., + tk->max_kern / 65536. ); + } + + printf( "\n" ); + + if ( fi->NumKernPair ) + printf( "There are %d kerning pairs:\n", + fi->NumKernPair ); + else + printf( "There is no kerning pair.\n" ); + + for ( i = 0; i < fi->NumKernPair; i++ ) + { + AFM_KernPair kp = fi->KernPairs + i; + + + printf( "\t%3d + %3d => (%4d, %4d)\n", kp->index1, + kp->index2, + kp->x, + kp->y ); + } + + } + + int + dummy_get_index( const char* name, + FT_Offset len, + void* user_data ) + { + if ( len ) + return name[0]; + else + return 0; + } + + FT_Error + parse_afm( FT_Library library, + FT_Stream stream, + AFM_FontInfo fi ) + { + PSAux_Service psaux; + AFM_ParserRec parser; + FT_Error error = FT_Err_Ok; + + + psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" ); + if ( !psaux || !psaux->afm_parser_funcs ) + return -1; + + error = FT_Stream_EnterFrame( stream, stream->size ); + if ( error ) + return error; + + error = psaux->afm_parser_funcs->init( &parser, + library->memory, + stream->cursor, + stream->limit ); + if ( error ) + return error; + + parser.FontInfo = fi; + parser.get_index = dummy_get_index; + + error = psaux->afm_parser_funcs->parse( &parser ); + + psaux->afm_parser_funcs->done( &parser ); + + return error; + } + + + int main( int argc, + char** argv ) + { + FT_Library library; + FT_StreamRec stream; + FT_Error error = FT_Err_Ok; + AFM_FontInfoRec fi; + + + if ( argc < 2 ) + return FT_ERR( Invalid_Argument ); + + error = FT_Init_FreeType( &library ); + if ( error ) + return error; + + FT_ZERO( &stream ); + error = FT_Stream_Open( &stream, argv[1] ); + if ( error ) + goto Exit; + stream.memory = library->memory; + + FT_ZERO( &fi ); + error = parse_afm( library, &stream, &fi ); + + if ( !error ) + { + FT_Memory memory = library->memory; + + + dump_fontinfo( &fi ); + + if ( fi.KernPairs ) + FT_FREE( fi.KernPairs ); + if ( fi.TrackKerns ) + FT_FREE( fi.TrackKerns ); + } + else + printf( "parse error\n" ); + + FT_Stream_Close( &stream ); + + Exit: + FT_Done_FreeType( library ); + + return error; + } diff --git a/Dependencies/freetype/freetype/src/tools/test_bbox.c b/Dependencies/freetype/freetype/src/tools/test_bbox.c new file mode 100644 index 00000000..d9fd9329 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/test_bbox.c @@ -0,0 +1,187 @@ +#include +#include + + +#include /* for clock() */ + +/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include */ +/* to get the HZ macro which is the equivalent. */ +#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4) +#include +#define CLOCKS_PER_SEC HZ +#endif + + static long + get_time( void ) + { + return clock() * 10000L / CLOCKS_PER_SEC; + } + + + + + /* test bbox computations */ + +#define XSCALE 65536 +#define XX(x) ((FT_Pos)(x*XSCALE)) +#define XVEC(x,y) { XX(x), XX(y) } +#define XVAL(x) ((x)/(1.0*XSCALE)) + + /* dummy outline #1 */ + static FT_Vector dummy_vec_1[4] = + { +#if 1 + XVEC( 408.9111, 535.3164 ), + XVEC( 455.8887, 634.396 ), + XVEC( -37.8765, 786.2207 ), + XVEC( 164.6074, 535.3164 ) +#else + { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL }, /* 408.9111, 535.3164 */ + { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L }, /* 455.8887, 634.3960 */ + { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL }, /* -37.8765, 786.2207 */ + { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL } /* 164.6074, 535.3164 */ +#endif + }; + + static char dummy_tag_1[4] = + { + FT_CURVE_TAG_ON, + FT_CURVE_TAG_CUBIC, + FT_CURVE_TAG_CUBIC, + FT_CURVE_TAG_ON + }; + + static short dummy_contour_1[1] = + { + 3 + }; + + static FT_Outline dummy_outline_1 = + { + 1, + 4, + dummy_vec_1, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + /* dummy outline #2 */ + static FT_Vector dummy_vec_2[4] = + { + XVEC( 100.0, 100.0 ), + XVEC( 100.0, 200.0 ), + XVEC( 200.0, 200.0 ), + XVEC( 200.0, 133.0 ) + }; + + static FT_Outline dummy_outline_2 = + { + 1, + 4, + dummy_vec_2, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + /* dummy outline #3 with bbox of [0 100 128 128] precisely */ + static FT_Vector dummy_vec_3[4] = + { + XVEC( 100.0, 127.0 ), + XVEC( 200.0, 127.0 ), + XVEC( 0.0, 136.0 ), + XVEC( 0.0, 100.0 ) + }; + + static FT_Outline dummy_outline_3 = + { + 1, + 4, + dummy_vec_3, + dummy_tag_1, + dummy_contour_1, + 0 + }; + + + static void + dump_outline( FT_Outline* outline ) + { + FT_BBox bbox; + + /* compute and display cbox */ + FT_Outline_Get_CBox( outline, &bbox ); + printf( "cbox = [%.2f %.2f %.2f %.2f]\n", + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + + /* compute and display bbox */ + FT_Outline_Get_BBox( outline, &bbox ); + printf( "bbox = [%.2f %.2f %.2f %.2f]\n", + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + } + + + + static void + profile_outline( FT_Outline* outline, + long repeat ) + { + FT_BBox bbox; + long count; + long time0; + + time0 = get_time(); + for ( count = repeat; count > 0; count-- ) + FT_Outline_Get_CBox( outline, &bbox ); + + time0 = get_time() - time0; + printf( "time = %6.3f cbox = [%8.4f %8.4f %8.4f %8.4f]\n", + ((double)time0/10000.0), + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + printf( "cbox_hex = [%08X %08X %08X %08X]\n", + bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax ); + + + time0 = get_time(); + for ( count = repeat; count > 0; count-- ) + FT_Outline_Get_BBox( outline, &bbox ); + + time0 = get_time() - time0; + printf( "time = %6.3f bbox = [%8.4f %8.4f %8.4f %8.4f]\n", + ((double)time0/10000.0), + XVAL( bbox.xMin ), + XVAL( bbox.yMin ), + XVAL( bbox.xMax ), + XVAL( bbox.yMax ) ); + printf( "bbox_hex = [%08X %08X %08X %08X]\n", + bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax ); + } + +#define REPEAT 1000000L + + int main( int argc, char** argv ) + { + printf( "outline #1\n" ); + profile_outline( &dummy_outline_1, REPEAT ); + + printf( "outline #2\n" ); + profile_outline( &dummy_outline_2, REPEAT ); + + printf( "outline #3\n" ); + profile_outline( &dummy_outline_3, REPEAT ); + + return 0; + } + diff --git a/Dependencies/freetype/freetype/src/tools/test_trig.c b/Dependencies/freetype/freetype/src/tools/test_trig.c new file mode 100644 index 00000000..4f3410ab --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/test_trig.c @@ -0,0 +1,257 @@ +#include +#include + +#include +#include + +#define PI 3.14159265358979323846 +#define SPI (PI/FT_ANGLE_PI) + +/* the precision in 16.16 fixed-point checks. Expect between 2 and 5 */ +/* noise LSB bits during operations, due to rounding errors.. */ +#define THRESHOLD 64 + + static error = 0; + + static void + test_cos( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Cos(i); + d2 = cos( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Cos[%3d] = %.7f cos[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_sin( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Sin(i); + d2 = sin( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Sin[%3d] = %.7f sin[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_tan( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_PI2 - 0x2000000L; i += 0x10000L ) + { + FT_Fixed f1, f2; + double d2; + + + f1 = FT_Tan(i); + d2 = tan( i*SPI ); + f2 = (FT_Fixed)(d2*65536.0); + + if ( abs( f2-f1 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Tan[%3d] = %.7f tan[%3d] = %.7f\n", + (i >> 16), f1/65536.0, (i >> 16), d2 ); + } + } + } + + + static void + test_atan2( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed c2, s2; + double l, a, c1, s1; + int j; + + + l = 5.0; + a = i*SPI; + + c1 = l * cos(a); + s1 = l * sin(a); + + c2 = (FT_Fixed)(c1*65536.0); + s2 = (FT_Fixed)(s1*65536.0); + + j = FT_Atan2( c2, s2 ); + if ( j < 0 ) + j += FT_ANGLE_2PI; + + if ( abs( i - j ) > 1 ) + { + printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n", + c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 ); + } + } + } + + + static void + test_unit( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Vector v; + double a, c1, s1; + FT_Fixed c2, s2; + + + FT_Vector_Unit( &v, i ); + a = ( i*SPI ); + c1 = cos(a); + s1 = sin(a); + c2 = (FT_Fixed)(c1*65536.0); + s2 = (FT_Fixed)(s1*65536.0); + + if ( abs( v.x-c2 ) > THRESHOLD || + abs( v.y-s2 ) > THRESHOLD ) + { + error = 1; + printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f ) vec = ( %.7f, %.7f )\n", + (i >> 16), + v.x/65536.0, v.y/65536.0, + c1, s1 ); + } + } + } + + + static void + test_length( void ) + { + int i; + + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Vector v; + FT_Fixed l, l2; + + + l = (FT_Fixed)(500.0*65536.0); + v.x = (FT_Fixed)( l * cos( i*SPI ) ); + v.y = (FT_Fixed)( l * sin( i*SPI ) ); + l2 = FT_Vector_Length( &v ); + + if ( abs( l2-l ) > THRESHOLD ) + { + error = 1; + printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n", + v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 ); + } + } + } + + + static void + test_rotate( void ) + { + int rotate; + + + for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000L ) + { + double ra, cra, sra; + int i; + + + ra = rotate*SPI; + cra = cos( ra ); + sra = sin( ra ); + + for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000L ) + { + FT_Fixed c2, s2, c4, s4; + FT_Vector v; + double l, a, c1, s1, c3, s3; + + + l = 500.0; + a = i*SPI; + + c1 = l * cos(a); + s1 = l * sin(a); + + v.x = c2 = (FT_Fixed)(c1*65536.0); + v.y = s2 = (FT_Fixed)(s1*65536.0); + + FT_Vector_Rotate( &v, rotate ); + + c3 = c1 * cra - s1 * sra; + s3 = c1 * sra + s1 * cra; + + c4 = (FT_Fixed)(c3*65536.0); + s4 = (FT_Fixed)(s3*65536.0); + + if ( abs( c4 - v.x ) > THRESHOLD || + abs( s4 - v.y ) > THRESHOLD ) + { + error = 1; + printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n", + c1, s1, ra, + c2/65536.0, s2/65536.0, + c4/65536.0, s4/65536.0 ); + } + } + } + } + + + int main( void ) + { + test_cos(); + test_sin(); + test_tan(); + test_atan2(); + test_unit(); + test_length(); + test_rotate(); + + if (!error) + printf( "trigonometry test ok !\n" ); + + return !error; + } diff --git a/Dependencies/freetype/freetype/src/tools/update-copyright b/Dependencies/freetype/freetype/src/tools/update-copyright new file mode 100644 index 00000000..674823ce --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/update-copyright @@ -0,0 +1,14 @@ +#!/bin/sh + +# Run the `update-copyright-year' script on all files in the git repository, +# taking care of exceptions stored in file `no-copyright'. + +topdir=`git rev-parse --show-toplevel` +toolsdir=`dirname $0` + +git ls-files --full-name $topdir \ +| sed "s|^|$topdir/|" \ +| grep -vFf $toolsdir/no-copyright \ +| xargs $toolsdir/update-copyright-year + +# EOF diff --git a/Dependencies/freetype/freetype/src/tools/update-copyright-year b/Dependencies/freetype/freetype/src/tools/update-copyright-year new file mode 100644 index 00000000..6b359ff6 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/update-copyright-year @@ -0,0 +1,157 @@ +eval '(exit $?0)' && eval 'exec perl -wS -i "$0" ${1+"$@"}' + & eval 'exec perl -wS -i "$0" $argv:q' + if 0; + +# Copyright (C) 2015-2024 by +# Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + +# [Note: This script is expected to be called by the shell, which in turn +# calls perl automatically. The nifty start-up code above is based on +# gnulib's `update-copyright' script; it is a more portable replacement for +# the shebang, using the first `perl' program in the shell's path instead.] + +# Usage: +# +# update-copyright-year file1 [file2 ...] + + +# This script handles copyright entries like +# +# Copyright 2000 by +# foobar +# +# or +# +# /* Copyright (c) 2000, 2001, 2004-2007 by */ +# /* foobar */ +# +# and replaces them uniformly with +# +# Copyright (C) 2000-2021 +# foobar +# +# and +# +# /* Copyright (C) 2000-2021 by */ +# /* foobar */ +# +# (assuming that the current year is 2021). As can be seen, the line length +# is retained if there is non-whitespace after the word `by' on the same +# line. + +use strict; + + +my (undef, undef, undef, + undef, undef, $year, + undef, undef, undef) = localtime(time); +$year += 1900; + +my $replaced = 0; + + +# Loop over all input files; option `-i' (issued at the very beginning of +# this script) makes perl edit them in-place. +while (<>) +{ + # Only handle the first copyright notice in a file. + if (!$replaced) + { + # First try: Search multiple copyright years. + s { + (?.*) + Copyright + (?(\ + + | \ +\(C\)\ +)) + (?[12][0-9][0-9][0-9]) + (?.+) + (?[12][0-9][0-9][0-9]) + (?\ +) + by + (?\ *) + (?.*) + } + { + # Fill line to the same length (if appropriate); we skip the middle + # part but insert `(C)', three spaces, and `-'. + my $space = length($+{space1}) + + length($+{middle}) + + length($+{space2}) + + length($+{space3}) + - (length("(C)") + 3 + 1); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}-$year\ by"; + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + }ex + || + # Second try: Search a single copyright year. + s { + (?.*) + Copyright + (?(\ + + | \ +\(C\)\ +)) + (?[12][0-9][0-9][0-9]) + (?\ +) + by + (?\ *) + (?.*) + } + { + if ($+{first} < $year) + { + # Fill line to the same length (if appropriate); we insert three + # spaces, the string `(C)', a `-', and the current year. + my $space = length($+{space1}) + + length($+{space2}) + + length($+{space3}) + - (length($year) + length("(C)") + 3 + 1); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}-$year\ by"; + # If $space is negative this inserts nothing. + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + } + else + { + # Fill line to the same length (if appropriate); we insert three + # spaces and the string `(C)'. + my $space = length($+{space1}) + + length($+{space2}) + + length($+{space3}) + - (length("(C)") + 3); + + print "$+{begin}"; + print "Copyright\ (C)\ $+{first}\ by"; + # If $space is negative this inserts nothing. + print ' ' x $space if length($+{end}); + print "$+{end}\n"; + $replaced = 1; + } + }ex + || + # Otherwise print line unaltered. + print; + } + else + { + print; + } +} +continue +{ + # Reset $replaced before processing the next file. + $replaced = 0 if eof; +} + +# EOF diff --git a/Dependencies/freetype/freetype/src/tools/vms_shorten_symbol.c b/Dependencies/freetype/freetype/src/tools/vms_shorten_symbol.c new file mode 100644 index 00000000..81f2a718 --- /dev/null +++ b/Dependencies/freetype/freetype/src/tools/vms_shorten_symbol.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010, 2017 Craig A. Berry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* vms_shorten_symbol + * + * This program provides shortening of long symbols (> 31 characters) using the + * same mechanism as the OpenVMS C compiler. The basic procedure is to compute + * an AUTODIN II checksum of the entire symbol, encode the checksum in base32, + * and glue together a shortened symbol from the first 23 characters of the + * original symbol plus the encoded checksum appended. The output format is + * the same used in the name mangler database, stored by default in + * [.CXX_REPOSITORY]CXX$DEMANGLER_DB. + * + * To obtain the same result as CC/NAMES=SHORTENED, run like so: + * + * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" + * PLEASE_FORGIVE_THIS_ABS1ARO4QU$Please_forgive_this_absurdly_long_symbol_name + * + * To obtain the same result as CC/NAMES=(SHORTENED,AS_IS), pass a non-zero + * value as the second argument, like so: + * + * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" 1 + * Please_forgive_this_abs3rv8rnn$Please_forgive_this_absurdly_long_symbol_name + */ + +#include +#include +#include +#include + +#ifdef __VMS +#define UINT32 unsigned int +#else +#include +#define UINT32 uint32_t +#endif + +extern UINT32 crc32(const char *input_string); +extern int u32_to_base32(UINT32 input, char *output); +extern int vms_shorten_symbol(const char *symbol, char *shortened, char as_is_flag); + +/* + * This routine implements the AUTODIN II polynomial. + */ + +UINT32 +crc32(const char *input_string) +{ + +/* + * CRC code and data based partly on FreeBSD implementation, which + * notes: + * + * The crc32 functions and data was originally written by Spencer + * Garrett and was cleaned from the PostgreSQL source + * tree via the files contrib/ltree/crc32.[ch]. No license was + * included, therefore it is assumed that this code is public + * domain. Attribution still noted. + * + * (I think they mean "gleaned" not "cleaned".) + */ + + static const UINT32 autodin_ii_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + }; + + UINT32 crc = ~0U; + char *c; + for (c = (char *)input_string; *c; ++c) + crc = (crc >> 8) ^ autodin_ii_table[(crc ^ *c) & 0xff]; + return ~crc; +} + +/* + * This is the RFC2938 variant of base32, not RFC3548, Crockford's, or + * other newer variant. It produces an 8-byte encoded character string + * (plus trailing null) from a 32-bit integer input. + */ + +int +u32_to_base32(UINT32 input, char *output) +{ + static const char base32hex_table[32] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v' + }; + int i; + + /* + * Grab lowest 5 bits and look up conversion in table. Lather, rinse, + * repeat for a total of 7, 5-bit chunks to accommodate 32 bits of input. + */ + for (i = 0; i < 7; i++) { + output[6 - i] = base32hex_table[input & 0x1f]; + input >>= 5; /* position to look at next 5 */ + } + output[7] = '$'; /* It's DEC, so use '$' not '=' to pad. */ + output[8] = '\0'; + return 0; +} + +/* + * Take an input symbol name of arbitrary length and produce a symbol shortened + * to 31 characters. The shortened symbol consists of the first 23 characters + * of the original symbol plus the 8 characters of the encoded checksum. The + * third argument is a boolean indicating whether to emulate the compiler's + * /NAMES=AS_IS option. When false (the compiler's default), the shortened + * symbol will be upper cased. When the original symbol is 31 characters or + * fewer in length, no checksum will be appended and the original symbol is + * returned verbatim (though upper cased if the as_is_flag is false). + */ + +int +vms_shorten_symbol(const char *input_symbol, char *shortened, char as_is_flag) +{ + char b32str[9]; + UINT32 crc; + char *c, *symbol; + int symlen; + + symlen = strlen(input_symbol); + symbol = (char *)malloc(symlen + 1); + if (symbol == NULL) + return -1; + + strncpy(symbol, input_symbol, symlen); + symbol[symlen] = '\0'; + + if (!as_is_flag) { + for (c = symbol; *c; c++) + *c = toupper(*c); + } + + if (symlen <= 31) { + strncpy(shortened, symbol, symlen); + shortened[symlen] = '\0'; + free(symbol); + return 0; + } + + /* + * Compute the checksum on the whole symbol. + */ + + crc = crc32(symbol); + + /* The compiler does not use the inverted checksum, so we invert it + * back before encoding in base32. + */ + + if (u32_to_base32(~crc, (char *)&b32str) == -1) { + free(symbol); + return -1; + } + + if (!as_is_flag) { + for (c = (char *)&b32str; *c; c++) + *c = toupper(*c); + } + + sprintf(shortened, "%.23s%.8s", symbol, b32str); + shortened[31] = '\0'; + free(symbol); + return 0; +} + +#ifdef TEST_MAIN +int +main(int argc, char **argv) +{ + char short_symbol[32]; + char as_is_flag = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s []\n", argv[0]); + exit(EXIT_FAILURE); + } + if (argc > 2) + as_is_flag = 1; + + if (vms_shorten_symbol(argv[1], (char *)&short_symbol, as_is_flag) == -1) { + fprintf(stderr, "Symbol shortening failed\n"); + exit(EXIT_FAILURE); + } + + printf("%s%s\n", (char *)&short_symbol, argv[1]); +} +#endif diff --git a/Dependencies/freetype/freetype/src/truetype/truetype.c b/Dependencies/freetype/freetype/src/truetype/truetype.c new file mode 100644 index 00000000..fe9cb924 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/truetype.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * truetype.c + * + * FreeType TrueType driver component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "ttdriver.c" /* driver interface */ +#include "ttgload.c" /* glyph loader */ +#include "ttgxvar.c" /* gx distortable font */ +#include "ttinterp.c" +#include "ttobjs.c" /* object manager */ +#include "ttpload.c" /* tables loader */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttdriver.c b/Dependencies/freetype/freetype/src/truetype/ttdriver.c new file mode 100644 index 00000000..4ab68eb9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttdriver.c @@ -0,0 +1,704 @@ +/**************************************************************************** + * + * ttdriver.c + * + * TrueType font driver implementation (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "ttdriver.h" +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttdriver + + + /* + * PROPERTY SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) + tt_property_set( FT_Module module, /* TT_Driver */ + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + TT_Driver driver = (TT_Driver)module; + +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + + + if ( !ft_strcmp( property_name, "interpreter-version" ) ) + { + FT_UInt interpreter_version; + + +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + interpreter_version = (FT_UInt)ft_strtol( s, NULL, 10 ); + } + else +#endif + { + FT_UInt* iv = (FT_UInt*)value; + + + interpreter_version = *iv; + } + + switch ( interpreter_version ) + { + case TT_INTERPRETER_VERSION_35: + driver->interpreter_version = TT_INTERPRETER_VERSION_35; + break; + + case TT_INTERPRETER_VERSION_38: + case TT_INTERPRETER_VERSION_40: +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + driver->interpreter_version = TT_INTERPRETER_VERSION_40; + break; +#endif + + default: + error = FT_ERR( Unimplemented_Feature ); + } + + return error; + } + + FT_TRACE2(( "tt_property_set: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_property_get( FT_Module module, /* TT_Driver */ + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + TT_Driver driver = (TT_Driver)module; + + FT_UInt interpreter_version = driver->interpreter_version; + + + if ( !ft_strcmp( property_name, "interpreter-version" ) ) + { + FT_UInt* val = (FT_UInt*)value; + + + *val = interpreter_version; + + return error; + } + + FT_TRACE2(( "tt_property_get: missing property `%s'\n", + property_name )); + return FT_THROW( Missing_Property ); + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + tt_service_properties, + + tt_property_set, /* FT_Properties_SetFunc set_property */ + tt_property_get /* FT_Properties_GetFunc get_property */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** F A C E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * @Function: + * tt_get_kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings, are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + FT_CALLBACK_DEF( FT_Error ) + tt_get_kerning( FT_Face face, /* TT_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + + kerning->x = 0; + kerning->y = 0; + + if ( sfnt ) + { + /* Use 'kern' table if available since that can be faster; otherwise */ + /* use GPOS kerning pairs if available. */ + if ( ttface->kern_avail_bits != 0 ) + kerning->x = sfnt->get_kerning( ttface, + left_glyph, + right_glyph ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + else if ( ttface->gpos_kerning_available ) + kerning->x = sfnt->get_gpos_kerning( ttface, + left_glyph, + right_glyph ); +#endif + } + + return 0; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_get_advances( FT_Face face, /* TT_Face */ + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed *advances ) + { + FT_UInt nn; + TT_Face ttface = (TT_Face)face; + + + /* XXX: TODO: check for sbits */ + + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + for ( nn = 0; nn < count; nn++ ) + { + FT_Short tsb; + FT_UShort ah; + + + /* since we don't need `tsb', we use zero for `yMax' parameter */ + TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah ); + advances[nn] = ah; + } + } + else + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + + for ( nn = 0; nn < count; nn++ ) + { + FT_Short lsb; + FT_UShort aw; + + + TT_Get_HMetrics( ttface, start + nn, &lsb, &aw ); + advances[nn] = aw; + } + } + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** S I Z E S ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + FT_CALLBACK_DEF( FT_Error ) + tt_size_select( FT_Size size, + FT_ULong strike_index ) + { + TT_Face ttface = (TT_Face)size->face; + TT_Size ttsize = (TT_Size)size; + FT_Error error = FT_Err_Ok; + + + ttsize->strike_index = strike_index; + + if ( FT_IS_SCALABLE( size->face ) ) + { + /* use the scaled metrics, even when tt_size_reset fails */ + FT_Select_Metrics( size->face, strike_index ); + + tt_size_reset( ttsize ); /* ignore return value */ + } + else + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + FT_Size_Metrics* size_metrics = &size->metrics; + + + error = sfnt->load_strike_metrics( ttface, + strike_index, + size_metrics ); + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + FT_CALLBACK_DEF( FT_Error ) + tt_size_request( FT_Size size, + FT_Size_Request req ) + { + TT_Size ttsize = (TT_Size)size; + FT_Error error = FT_Err_Ok; + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + TT_Face ttface = (TT_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + FT_ULong strike_index; + + + error = sfnt->set_sbit_strike( ttface, req, &strike_index ); + + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + else + return tt_size_select( size, strike_index ); + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + { + FT_Error err = FT_Request_Metrics( size->face, req ); + + + if ( err ) + { + error = err; + goto Exit; + } + } + + if ( FT_IS_SCALABLE( size->face ) ) + { + error = tt_size_reset( ttsize ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* for the `MPS' bytecode instruction we need the point size */ + if ( !error ) + { + FT_UInt resolution = + ttsize->metrics->x_ppem > ttsize->metrics->y_ppem + ? req->horiResolution + : req->vertResolution; + + + /* if we don't have a resolution value, assume 72dpi */ + if ( req->type == FT_SIZE_REQUEST_TYPE_SCALES || + !resolution ) + resolution = 72; + + ttsize->point_size = FT_MulDiv( ttsize->ttmetrics.ppem, + 64 * 72, + resolution ); + } +#endif + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_glyph_load + * + * @Description: + * A driver method used to load a glyph within a given glyph slot. + * + * @Input: + * slot :: + * A handle to the target slot object where the glyph + * will be loaded. + * + * size :: + * A handle to the source face size at which the glyph + * must be scaled, loaded, etc. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_XXX constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_CALLBACK_DEF( FT_Error ) + tt_glyph_load( FT_GlyphSlot slot, /* TT_GlyphSlot */ + FT_Size size, /* TT_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_GlyphSlot ttslot = (TT_GlyphSlot)slot; + TT_Size ttsize = (TT_Size)size; + FT_Face face = ttslot->face; + FT_Error error; + + + if ( !slot ) + return FT_THROW( Invalid_Slot_Handle ); + + if ( !size ) + return FT_THROW( Invalid_Size_Handle ); + + if ( !face ) + return FT_THROW( Invalid_Face_Handle ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_index >= (FT_UInt)face->num_glyphs && + !face->internal->incremental_interface ) +#else + if ( glyph_index >= (FT_UInt)face->num_glyphs ) +#endif + return FT_THROW( Invalid_Argument ); + + if ( load_flags & FT_LOAD_NO_HINTING ) + { + /* both FT_LOAD_NO_HINTING and FT_LOAD_NO_AUTOHINT */ + /* are necessary to disable hinting for tricky fonts */ + + if ( FT_IS_TRICKY( face ) ) + load_flags &= ~FT_LOAD_NO_HINTING; + + if ( load_flags & FT_LOAD_NO_AUTOHINT ) + load_flags |= FT_LOAD_NO_HINTING; + } + + if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) ) + { + load_flags |= FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE; + + if ( !FT_IS_TRICKY( face ) ) + load_flags |= FT_LOAD_NO_HINTING; + } + + /* use hinted metrics only if we load a glyph with hinting */ + ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING ) + ? &size->metrics + : &ttsize->hinted_metrics; + + /* now fill in the glyph slot with outline/bitmap/layered */ + error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags ); + + /* force drop-out mode to 2 - irrelevant now */ + /* slot->outline.dropout_mode = 2; */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** D R I V E R I N T E R F A C E ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + FT_DEFINE_SERVICE_MULTIMASTERSREC( + tt_service_gx_multi_masters, + + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + TT_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + TT_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + TT_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + TT_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + TT_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func set_named_instance */ + TT_Get_Default_Named_Instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + NULL, /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + NULL, /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + + tt_construct_ps_name, /* FT_Construct_PS_Name_Func construct_ps_name */ + tt_var_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + tt_var_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + tt_var_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + tt_var_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + tt_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + tt_done_blend /* FT_Done_Blend_Func done_blend */ + ) + + FT_DEFINE_SERVICE_METRICSVARIATIONSREC( + tt_service_metrics_variations, + + tt_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ + + tt_vadvance_adjust, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ + + tt_apply_mvar, /* FT_Metrics_Adjust_Func metrics_adjust */ + tt_size_reset_height /* FT_Size_Reset_Func size_reset */ + ) + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_TRUETYPE_ENGINE_TYPE_PATENTED + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_TRUETYPE_ENGINE_TYPE_NONE + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + }; + + + FT_DEFINE_SERVICE_TTGLYFREC( + tt_service_truetype_glyf, + + (TT_Glyf_GetLocationFunc)tt_face_get_location /* get_location */ + ) + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC6( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_MULTI_MASTERS, &tt_service_gx_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &tt_service_metrics_variations, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#else + FT_DEFINE_SERVICEDESCREC4( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#endif + + + FT_CALLBACK_DEF( FT_Module_Interface ) + tt_get_interface( FT_Module driver, /* TT_Driver */ + const char* tt_interface ) + { + FT_Library library; + FT_Module_Interface result; + FT_Module sfntd; + SFNT_Service sfnt; + + + result = ft_service_list_lookup( tt_services, tt_interface ); + if ( result ) + return result; + + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; + + /* only return the default interface from the SFNT module */ + sfntd = FT_Get_Module( library, "sfnt" ); + if ( sfntd ) + { + sfnt = (SFNT_Service)( sfntd->clazz->module_interface ); + if ( sfnt ) + return sfnt->get_interface( driver, tt_interface ); + } + + return 0; + } + + + /* The FT_DriverInterface structure is defined in ftdriver.h. */ + +#ifdef TT_USE_BYTECODE_INTERPRETER +#define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER +#else +#define TT_HINTER_FLAG 0 +#endif + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#define TT_SIZE_SELECT tt_size_select +#else +#define TT_SIZE_SELECT 0 +#endif + + FT_DEFINE_DRIVER( + tt_driver_class, + + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + TT_HINTER_FLAG, + + sizeof ( TT_DriverRec ), + + "truetype", /* driver name */ + 0x10000L, /* driver version == 1.0 */ + 0x20000L, /* driver requires FreeType 2.0 or above */ + + NULL, /* module-specific interface */ + + tt_driver_init, /* FT_Module_Constructor module_init */ + tt_driver_done, /* FT_Module_Destructor module_done */ + tt_get_interface, /* FT_Module_Requester get_interface */ + + sizeof ( TT_FaceRec ), + sizeof ( TT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + tt_face_init, /* FT_Face_InitFunc init_face */ + tt_face_done, /* FT_Face_DoneFunc done_face */ + tt_size_init, /* FT_Size_InitFunc init_size */ + tt_size_done, /* FT_Size_DoneFunc done_size */ + tt_slot_init, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + tt_glyph_load, /* FT_Slot_LoadFunc load_glyph */ + + tt_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + tt_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ + + tt_size_request, /* FT_Size_RequestFunc request_size */ + TT_SIZE_SELECT /* FT_Size_SelectFunc select_size */ + ) + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttdriver.h b/Dependencies/freetype/freetype/src/truetype/ttdriver.h new file mode 100644 index 00000000..3e1cf234 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttdriver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * ttdriver.h + * + * High-level TrueType driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTDRIVER_H_ +#define TTDRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_DRIVER( tt_driver_class ) + +FT_END_HEADER + +#endif /* TTDRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/tterrors.h b/Dependencies/freetype/freetype/src/truetype/tterrors.h new file mode 100644 index 00000000..7ad937bd --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/tterrors.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * tterrors.h + * + * TrueType error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the TrueType error enumeration + * constants. + * + */ + +#ifndef TTERRORS_H_ +#define TTERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX TT_Err_ +#define FT_ERR_BASE FT_Mod_Err_TrueType + +#include + +#endif /* TTERRORS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttgload.c b/Dependencies/freetype/freetype/src/truetype/ttgload.c new file mode 100644 index 00000000..b656ccf0 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttgload.c @@ -0,0 +1,2740 @@ +/**************************************************************************** + * + * ttgload.c + * + * TrueType Glyph Loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include +#include +#include + +#include "ttgload.h" +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttgload + + + /************************************************************************** + * + * Simple glyph flags. + */ +#define ON_CURVE_POINT 0x01 /* same value as FT_CURVE_TAG_ON */ +#define X_SHORT_VECTOR 0x02 +#define Y_SHORT_VECTOR 0x04 +#define REPEAT_FLAG 0x08 +#define X_POSITIVE 0x10 /* two meanings depending on X_SHORT_VECTOR */ +#define SAME_X 0x10 +#define Y_POSITIVE 0x20 /* two meanings depending on Y_SHORT_VECTOR */ +#define SAME_Y 0x20 +#define OVERLAP_SIMPLE 0x40 /* retained as FT_OUTLINE_OVERLAP */ + + + /************************************************************************** + * + * Composite glyph flags. + */ +#define ARGS_ARE_WORDS 0x0001 +#define ARGS_ARE_XY_VALUES 0x0002 +#define ROUND_XY_TO_GRID 0x0004 +#define WE_HAVE_A_SCALE 0x0008 +/* reserved 0x0010 */ +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_XY_SCALE 0x0040 +#define WE_HAVE_A_2X2 0x0080 +#define WE_HAVE_INSTR 0x0100 +#define USE_MY_METRICS 0x0200 +#define OVERLAP_COMPOUND 0x0400 /* retained as FT_OUTLINE_OVERLAP */ +#define SCALED_COMPONENT_OFFSET 0x0800 +#define UNSCALED_COMPONENT_OFFSET 0x1000 + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + + + /************************************************************************** + * + * Return the horizontal metrics in font units for a given glyph. + */ + FT_LOCAL_DEF( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ) + { + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); + + FT_TRACE5(( " advance width (font units): %d\n", *aw )); + FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); + } + + + /************************************************************************** + * + * Return the vertical metrics in font units for a given glyph. + * See function `tt_loader_set_pp' below for explanations. + */ + FT_LOCAL_DEF( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Pos yMax, + FT_Short* tsb, + FT_UShort* ah ) + { + if ( face->vertical_info ) + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); + + else if ( face->os2.version != 0xFFFFU ) + { + *tsb = (FT_Short)( face->os2.sTypoAscender - yMax ); + *ah = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + } + + else + { + *tsb = (FT_Short)( face->horizontal.Ascender - yMax ); + *ah = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !face->vertical_info ) + FT_TRACE5(( " [vertical metrics missing, computing values]\n" )); +#endif + + FT_TRACE5(( " advance height (font units): %d\n", *ah )); + FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); + } + + + static FT_Error + tt_get_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + + FT_Error error; + FT_Stream stream = loader->stream; + + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + /* we must preserve the stream position */ + /* (which gets altered by the metrics functions) */ + FT_ULong pos = FT_STREAM_POS(); + + + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + loader->bbox.yMax, + &top_bearing, + &advance_height ); + + if ( FT_STREAM_SEEK( pos ) ) + return error; + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* With the incremental interface, these values are set by */ + /* a call to `tt_get_metrics_incremental'. */ + if ( face->root.internal->incremental_interface == NULL ) +#endif + { + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + + return FT_Err_Ok; + } + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + static void + tt_get_metrics_incremental( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + + /* If this is an incrementally loaded font check whether there are */ + /* overriding metrics for this glyph. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec incr_metrics; + FT_Error error; + + + incr_metrics.bearing_x = loader->left_bearing; + incr_metrics.bearing_y = 0; + incr_metrics.advance = loader->advance; + incr_metrics.advance_v = 0; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &incr_metrics ); + if ( error ) + goto Exit; + + left_bearing = (FT_Short)incr_metrics.bearing_x; + advance_width = (FT_UShort)incr_metrics.advance; + +#if 0 + + /* GWW: Do I do the same for vertical metrics? */ + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = loader->top_bearing; + incr_metrics.advance = loader->vadvance; + + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, TRUE, &incr_metrics ); + if ( error ) + goto Exit; + + top_bearing = (FT_Short)incr_metrics.bearing_y; + advance_height = (FT_UShort)incr_metrics.advance; + +#endif /* 0 */ + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + + Exit: + return; + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + + /************************************************************************** + * + * The following functions are used by default with TrueType fonts. + * However, they can be replaced by alternatives if we need to support + * TrueType-compressed formats (like MicroType) in the future. + * + */ + + FT_CALLBACK_DEF( FT_Error ) + TT_Access_Glyph_Frame( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ) + { + FT_Error error; + FT_Stream stream = loader->stream; + + FT_UNUSED( glyph_index ); + + + /* the following line sets the `error' variable through macros! */ + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) + return error; + + loader->cursor = stream->cursor; + loader->limit = stream->limit; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( void ) + TT_Forget_Glyph_Frame( TT_Loader loader ) + { + FT_Stream stream = loader->stream; + + + FT_FRAME_EXIT(); + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Glyph_Header( TT_Loader loader ) + { + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + + + if ( p + 10 > limit ) + return FT_THROW( Invalid_Outline ); + + loader->n_contours = FT_NEXT_SHORT( p ); + + loader->bbox.xMin = FT_NEXT_SHORT( p ); + loader->bbox.yMin = FT_NEXT_SHORT( p ); + loader->bbox.xMax = FT_NEXT_SHORT( p ); + loader->bbox.yMax = FT_NEXT_SHORT( p ); + + FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); + FT_TRACE5(( " xMin: %4ld xMax: %4ld\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE5(( " yMin: %4ld yMax: %4ld\n", loader->bbox.yMin, + loader->bbox.yMax )); + loader->cursor = p; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Simple_Glyph( TT_Loader load ) + { + FT_Error error; + FT_Byte* p = load->cursor; + FT_Byte* limit = load->limit; + FT_GlyphLoader gloader = load->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_Int n_contours = load->n_contours; + FT_Int n_points; + FT_UShort n_ins; + + FT_Byte *flag, *flag_limit; + FT_Byte c, count; + FT_Vector *vec, *vec_limit; + FT_Pos x, y; + FT_UShort *cont, *cont_limit; + FT_Int last; + + + /* check that we can add the contours to the glyph */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours ); + if ( error ) + goto Fail; + + /* check space for contours array + instructions count */ + if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit ) + goto Invalid_Outline; + + /* reading the contours' endpoints & number of points */ + cont = outline->contours; + cont_limit = cont + n_contours; + + last = -1; + for ( ; cont < cont_limit; cont++ ) + { + *cont = FT_NEXT_USHORT( p ); + + if ( *cont <= last ) + goto Invalid_Outline; + + last = *cont; + } + + n_points = last + 1; + + FT_TRACE5(( " # of points: %d\n", n_points )); + + /* note that we will add four phantom points later */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); + if ( error ) + goto Fail; + + /* space checked above */ + n_ins = FT_NEXT_USHORT( p ); + + FT_TRACE5(( " Instructions size: %u\n", n_ins )); + + /* check instructions size */ + if ( p + n_ins > limit ) + { + FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" )); + error = FT_THROW( Too_Many_Hints ); + goto Fail; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( IS_HINTED( load->load_flags ) ) + { + TT_ExecContext exec = load->exec; + FT_Memory memory = exec->memory; + + + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ + /* and thus allocate the bytecode array size by ourselves */ + if ( n_ins ) + { + if ( FT_DUP( exec->glyphIns, p, n_ins ) ) + return error; + + exec->glyphSize = n_ins; + } + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + p += n_ins; + + /* reading the point tags */ + flag = outline->tags; + flag_limit = flag + n_points; + + FT_ASSERT( flag ); + + while ( flag < flag_limit ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + *flag++ = c = FT_NEXT_BYTE( p ); + if ( c & REPEAT_FLAG ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + count = FT_NEXT_BYTE( p ); + if ( flag + (FT_Int)count > flag_limit ) + goto Invalid_Outline; + + for ( ; count > 0; count-- ) + *flag++ = c; + } + } + + /* retain the overlap flag */ + if ( n_points && outline->tags[0] & OVERLAP_SIMPLE ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; + + /* reading the X coordinates */ + + vec = outline->points; + vec_limit = vec + n_points; + flag = outline->tags; + x = 0; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos delta = 0; + FT_Byte f = *flag; + + + if ( f & X_SHORT_VECTOR ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_BYTE( p ); + if ( !( f & X_POSITIVE ) ) + delta = -delta; + } + else if ( !( f & SAME_X ) ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_SHORT( p ); + } + + x += delta; + vec->x = x; + } + + /* reading the Y coordinates */ + + vec = outline->points; + vec_limit = vec + n_points; + flag = outline->tags; + y = 0; + + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos delta = 0; + FT_Byte f = *flag; + + + if ( f & Y_SHORT_VECTOR ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_BYTE( p ); + if ( !( f & Y_POSITIVE ) ) + delta = -delta; + } + else if ( !( f & SAME_Y ) ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + + delta = (FT_Pos)FT_NEXT_SHORT( p ); + } + + y += delta; + vec->y = y; + + /* the cast is for stupid compilers */ + *flag = (FT_Byte)( f & ON_CURVE_POINT ); + } + + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_UShort)n_contours; + + load->cursor = p; + + Fail: + return error; + + Invalid_Outline: + error = FT_THROW( Invalid_Outline ); + goto Fail; + } + + + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Composite_Glyph( TT_Loader loader ) + { + FT_Error error; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + FT_GlyphLoader gloader = loader->gloader; + FT_Long num_glyphs = loader->face->root.num_glyphs; + FT_SubGlyph subglyph; + FT_UInt num_subglyphs; + + + num_subglyphs = 0; + + do + { + FT_Fixed xx, xy, yy, yx; + FT_UInt count; + + + /* check that we can load a new subglyph */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 ); + if ( error ) + goto Fail; + + /* check space */ + if ( p + 4 > limit ) + goto Invalid_Composite; + + subglyph = gloader->current.subglyphs + num_subglyphs; + + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = FT_NEXT_USHORT( p ); + subglyph->index = FT_NEXT_USHORT( p ); + + /* we reject composites that have components */ + /* with invalid glyph indices */ + if ( subglyph->index >= num_glyphs ) + goto Invalid_Composite; + + /* check space */ + count = 2; + if ( subglyph->flags & ARGS_ARE_WORDS ) + count += 2; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + count += 2; + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + count += 4; + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + count += 8; + + if ( p + count > limit ) + goto Invalid_Composite; + + /* read arguments */ + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = FT_NEXT_SHORT( p ); + subglyph->arg2 = FT_NEXT_SHORT( p ); + } + else + { + subglyph->arg1 = FT_NEXT_CHAR( p ); + subglyph->arg2 = FT_NEXT_CHAR( p ); + } + } + else + { + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = (FT_Int)FT_NEXT_USHORT( p ); + subglyph->arg2 = (FT_Int)FT_NEXT_USHORT( p ); + } + else + { + subglyph->arg1 = (FT_Int)FT_NEXT_BYTE( p ); + subglyph->arg2 = (FT_Int)FT_NEXT_BYTE( p ); + } + } + + /* read transform */ + xx = yy = 0x10000L; + xy = yx = 0; + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = xx; + } + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + } + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + xy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4; + } + + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + + num_subglyphs++; + + } while ( subglyph->flags & MORE_COMPONENTS ); + + gloader->current.num_subglyphs = num_subglyphs; + FT_TRACE5(( " %d component%s\n", + num_subglyphs, + num_subglyphs > 1 ? "s" : "" )); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < num_subglyphs; i++ ) + { + if ( num_subglyphs > 1 ) + FT_TRACE7(( " subglyph %d:\n", i )); + + FT_TRACE7(( " glyph index: %d\n", subglyph->index )); + + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + FT_TRACE7(( " offset: x=%d, y=%d\n", + subglyph->arg1, + subglyph->arg2 )); + else + FT_TRACE7(( " matching points: base=%d, component=%d\n", + subglyph->arg1, + subglyph->arg2 )); + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + FT_TRACE7(( " scaling: %f\n", + (double)subglyph->transform.xx / 65536 )); + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + FT_TRACE7(( " scaling: x=%f, y=%f\n", + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yy / 65536 )); + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + FT_TRACE7(( " scaling: xx=%f, yx=%f\n", + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yx / 65536 )); + FT_TRACE7(( " xy=%f, yy=%f\n", + (double)subglyph->transform.xy / 65536, + (double)subglyph->transform.yy / 65536 )); + } + + subglyph++; + } + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + FT_Stream stream = loader->stream; + + + /* we must undo the FT_FRAME_ENTER in order to point */ + /* to the composite instructions, if we find some. */ + /* We will process them later. */ + /* */ + loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + + p - limit ); + } + +#endif + + loader->cursor = p; + + Fail: + return error; + + Invalid_Composite: + error = FT_THROW( Invalid_Composite ); + goto Fail; + } + + + FT_LOCAL_DEF( void ) + TT_Init_Glyph_Loading( TT_Face face ) + { + face->access_glyph_frame = TT_Access_Glyph_Frame; + face->read_glyph_header = TT_Load_Glyph_Header; + face->read_simple_glyph = TT_Load_Simple_Glyph; + face->read_composite_glyph = TT_Load_Composite_Glyph; + face->forget_glyph_frame = TT_Forget_Glyph_Frame; + } + + + static void + tt_prepare_zone( TT_GlyphZone zone, + FT_GlyphLoad load, + FT_UInt start_point, + FT_UInt start_contour ) + { + zone->n_points = load->outline.n_points + 4 - (FT_UShort)start_point; + zone->n_contours = load->outline.n_contours - (FT_UShort)start_contour; + zone->org = load->extra_points + start_point; + zone->cur = load->outline.points + start_point; + zone->orus = load->extra_points2 + start_point; + zone->tags = load->outline.tags + start_point; + zone->contours = load->outline.contours + start_contour; + zone->first_point = (FT_UShort)start_point; + } + + + /************************************************************************** + * + * @Function: + * TT_Hint_Glyph + * + * @Description: + * Hint the glyph using the zone prepared by the caller. Note that + * the zone is supposed to include four phantom points. + */ + static FT_Error + TT_Hint_Glyph( TT_Loader loader, + FT_Bool is_composite ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + TT_Face face = loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#endif + + TT_GlyphZone zone = &loader->zone; + +#ifdef TT_USE_BYTECODE_INTERPRETER + TT_ExecContext exec = loader->exec; + FT_Long n_ins = exec->glyphSize; +#else + FT_UNUSED( is_composite ); +#endif + + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* save original point positions in `org' array */ + if ( n_ins > 0 ) + FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); + + /* Reset graphics state. */ + exec->GS = loader->size->GS; + + /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ + /* completely refer to the (already) hinted subglyphs. */ + if ( is_composite ) + { + exec->metrics.x_scale = 1 << 16; + exec->metrics.y_scale = 1 << 16; + + FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points ); + } + else + { + exec->metrics.x_scale = loader->size->metrics->x_scale; + exec->metrics.y_scale = loader->size->metrics->y_scale; + } +#endif + + /* round phantom points */ + zone->cur[zone->n_points - 4].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 4].x ); + zone->cur[zone->n_points - 3].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); + zone->cur[zone->n_points - 2].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 2].y ); + zone->cur[zone->n_points - 1].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( n_ins > 0 ) + { + FT_Error error; + + + TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins ); + + exec->is_composite = is_composite; + exec->pts = *zone; + + error = TT_Run_Context( exec ); + if ( error && exec->pedantic_hinting ) + return error; + + /* store drop-out mode in bits 5-7; set bit 2 also as a marker */ + loader->gloader->current.outline.tags[0] |= + ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; + } + +#endif + + /* Save possibly modified glyph phantom points unless in v40 backward */ + /* compatibility mode, where no movement on the x axis means no reason */ + /* to change bearings or advance widths. */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + exec->backward_compatibility ) + return FT_Err_Ok; +#endif + + loader->pp1 = zone->cur[zone->n_points - 4]; + loader->pp2 = zone->cur[zone->n_points - 3]; + loader->pp3 = zone->cur[zone->n_points - 2]; + loader->pp4 = zone->cur[zone->n_points - 1]; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Simple_Glyph + * + * @Description: + * Once a simple glyph has been loaded, it needs to be processed. + * Usually, this means scaling and hinting through bytecode + * interpretation. + */ + static FT_Error + TT_Process_Simple_Glyph( TT_Loader loader ) + { + FT_Error error = FT_Err_Ok; + FT_GlyphLoader gloader = loader->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_Int n_points = outline->n_points; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_Memory memory = loader->face->root.memory; + FT_Vector* unrounded = NULL; +#endif + + + /* set phantom points */ + outline->points[n_points ] = loader->pp1; + outline->points[n_points + 1] = loader->pp2; + outline->points[n_points + 2] = loader->pp3; + outline->points[n_points + 3] = loader->pp4; + + n_points += 4; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) + { + if ( FT_QNEW_ARRAY( unrounded, n_points ) ) + goto Exit; + + /* Deltas apply to the unscaled data. */ + error = TT_Vary_Apply_Glyph_Deltas( loader, + outline, + unrounded ); + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + if ( IS_HINTED( loader->load_flags ) ) + { + tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); + + FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, + loader->zone.n_points ); + } + + { + FT_Vector* vec = outline->points; + FT_Vector* limit = outline->points + n_points; + + FT_Fixed x_scale = 0; /* pacify compiler */ + FT_Fixed y_scale = 0; + + FT_Bool do_scale = FALSE; + + + { + /* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; + + do_scale = TRUE; + } + } + + if ( do_scale ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) + { + FT_Vector* u = unrounded; + + + for ( ; vec < limit; vec++, u++ ) + { + vec->x = ADD_LONG( FT_MulFix( u->x, x_scale ), 32 ) >> 6; + vec->y = ADD_LONG( FT_MulFix( u->y, y_scale ), 32 ) >> 6; + } + } + else +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + { + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a HVAR table, `pp1' and/or `pp2' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + } + else +#endif + { + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a VVAR table, `pp3' and/or `pp4' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + else +#endif + { + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + } + } + + if ( IS_HINTED( loader->load_flags ) ) + error = TT_Hint_Glyph( loader, 0 ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + Exit: + FT_FREE( unrounded ); +#endif + + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Composite_Component + * + * @Description: + * Once a composite component has been loaded, it needs to be + * processed. Usually, this means transforming and translating. + */ + static FT_Error + TT_Process_Composite_Component( TT_Loader loader, + FT_SubGlyph subglyph, + FT_UInt start_point, + FT_UInt num_base_points ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Outline current; + FT_Bool have_scale; + FT_Pos x, y; + + + current.points = gloader->base.outline.points + + num_base_points; + current.n_points = gloader->base.outline.n_points - + (FT_UShort)num_base_points; + + have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ); + + /* perform the transform required for this subglyph */ + if ( have_scale ) + FT_Outline_Transform( ¤t, &subglyph->transform ); + + /* get offset */ + if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) + { + FT_UInt num_points = gloader->base.outline.n_points; + FT_UInt k = (FT_UInt)subglyph->arg1; + FT_UInt l = (FT_UInt)subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + /* match l-th point of the newly loaded component to the k-th point */ + /* of the previously loaded components. */ + + /* change to the point numbers used by our outline */ + k += start_point; + l += num_base_points; + if ( k >= num_base_points || + l >= num_points ) + return FT_THROW( Invalid_Composite ); + + p1 = gloader->base.outline.points + k; + p2 = gloader->base.outline.points + l; + + x = SUB_LONG( p1->x, p2->x ); + y = SUB_LONG( p1->y, p2->y ); + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + + if ( !x && !y ) + return FT_Err_Ok; + + /* Use a default value dependent on */ + /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old */ + /* TT fonts which don't set the xxx_COMPONENT_OFFSET bit. */ + + if ( have_scale && +#ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) ) +#else + ( subglyph->flags & SCALED_COMPONENT_OFFSET ) ) +#endif + { + +#if 0 + + /******************************************************************** + * + * This algorithm is what Apple documents. But it doesn't work. + */ + int a = subglyph->transform.xx > 0 ? subglyph->transform.xx + : -subglyph->transform.xx; + int b = subglyph->transform.yx > 0 ? subglyph->transform.yx + : -subglyph->transform.yx; + int c = subglyph->transform.xy > 0 ? subglyph->transform.xy + : -subglyph->transform.xy; + int d = subglyph->transform.yy > 0 ? subglyph->transform.yy + : -subglyph->transform.yy; + int m = a > b ? a : b; + int n = c > d ? c : d; + + + if ( a - b <= 33 && a - b >= -33 ) + m *= 2; + if ( c - d <= 33 && c - d >= -33 ) + n *= 2; + x = FT_MulFix( x, m ); + y = FT_MulFix( y, n ); + +#else /* 1 */ + + /******************************************************************** + * + * This algorithm is a guess and works much better than the above. + */ + FT_Fixed mac_xscale = FT_Hypot( subglyph->transform.xx, + subglyph->transform.xy ); + FT_Fixed mac_yscale = FT_Hypot( subglyph->transform.yy, + subglyph->transform.yx ); + + + x = FT_MulFix( x, mac_xscale ); + y = FT_MulFix( y, mac_yscale ); + +#endif /* 1 */ + + } + + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + FT_Fixed x_scale = loader->size->metrics->x_scale; + FT_Fixed y_scale = loader->size->metrics->y_scale; + + + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + TT_Face face = loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + + if ( IS_HINTED( loader->load_flags ) ) + { + /* + * We round the horizontal offset only if there is hinting along + * the x axis; this corresponds to integer advance width values. + * + * Theoretically, a glyph's bytecode can toggle ClearType's + * `backward compatibility' mode, which would allow modification + * of the advance width. In reality, however, applications + * neither allow nor expect modified advance widths if subpixel + * rendering is active. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 ) + x = FT_PIX_ROUND( x ); + + y = FT_PIX_ROUND( y ); + } + } + } + } + + if ( x || y ) + FT_Outline_Translate( ¤t, x, y ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Process_Composite_Glyph + * + * @Description: + * This is slightly different from TT_Process_Simple_Glyph, in that + * its sole purpose is to hint the glyph. Thus this function is + * only available when bytecode interpreter is enabled. + */ + static FT_Error + TT_Process_Composite_Glyph( TT_Loader loader, + FT_UInt start_point, + FT_UInt start_contour ) + { + FT_Error error; + FT_Outline* outline = &loader->gloader->base.outline; + FT_Stream stream = loader->stream; + FT_UShort n_ins; + FT_UInt i; + + + /* make room for phantom points */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, + outline->n_points + 4, + 0 ); + if ( error ) + return error; + + outline->points[outline->n_points ] = loader->pp1; + outline->points[outline->n_points + 1] = loader->pp2; + outline->points[outline->n_points + 2] = loader->pp3; + outline->points[outline->n_points + 3] = loader->pp4; + +#ifdef TT_USE_BYTECODE_INTERPRETER + + { + TT_ExecContext exec = loader->exec; + FT_Memory memory = exec->memory; + + + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + /* TT_Load_Composite_Glyph only gives us the offset of instructions */ + /* so we read them here */ + if ( FT_STREAM_SEEK( loader->ins_pos ) || + FT_READ_USHORT( n_ins ) ) + return error; + + FT_TRACE5(( " Instructions size = %hu\n", n_ins )); + + if ( !n_ins ) + return FT_Err_Ok; + + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ + if ( n_ins > loader->byte_len ) + { + FT_TRACE1(( "TT_Process_Composite_Glyph:" + " too many instructions (%hu) for glyph with length %u\n", + n_ins, loader->byte_len )); + return FT_THROW( Too_Many_Hints ); + } + + if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) || + FT_STREAM_READ( exec->glyphIns, n_ins ) ) + return error; + + exec->glyphSize = n_ins; + } + +#endif + + tt_prepare_zone( &loader->zone, &loader->gloader->base, + start_point, start_contour ); + + /* Some points are likely touched during execution of */ + /* instructions on components. So let's untouch them. */ + for ( i = 0; i < loader->zone.n_points - 4U; i++ ) + loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; + + return TT_Hint_Glyph( loader, 1 ); + } + + + /* + * Calculate the phantom points + * + * Defining the right side bearing (rsb) as + * + * rsb = aw - (lsb + xmax - xmin) + * + * (with `aw' the advance width, `lsb' the left side bearing, and `xmin' + * and `xmax' the glyph's minimum and maximum x value), the OpenType + * specification defines the initial position of horizontal phantom points + * as + * + * pp1 = (round(xmin - lsb), 0) , + * pp2 = (round(pp1 + aw), 0) . + * + * Note that the rounding to the grid (in the device space) is not + * documented currently in the specification. + * + * However, the specification lacks the precise definition of vertical + * phantom points. Greg Hitchcock provided the following explanation. + * + * - a `vmtx' table is present + * + * For any glyph, the minimum and maximum y values (`ymin' and `ymax') + * are given in the `glyf' table, the top side bearing (tsb) and advance + * height (ah) are given in the `vmtx' table. The bottom side bearing + * (bsb) is then calculated as + * + * bsb = ah - (tsb + ymax - ymin) , + * + * and the initial position of vertical phantom points is + * + * pp3 = (x, round(ymax + tsb)) , + * pp4 = (x, round(pp3 - ah)) . + * + * See below for value `x'. + * + * - no `vmtx' table in the font + * + * If there is an `OS/2' table, we set + * + * DefaultAscender = sTypoAscender , + * DefaultDescender = sTypoDescender , + * + * otherwise we use data from the `hhea' table: + * + * DefaultAscender = Ascender , + * DefaultDescender = Descender . + * + * With these two variables we can now set + * + * ah = DefaultAscender - sDefaultDescender , + * tsb = DefaultAscender - yMax , + * + * and proceed as if a `vmtx' table was present. + * + * Usually we have + * + * x = aw / 2 , (1) + * + * but there is one compatibility case where it can be set to + * + * x = -DefaultDescender - + * ((DefaultAscender - DefaultDescender - aw) / 2) . (2) + * + * and another one with + * + * x = 0 . (3) + * + * In Windows, the history of those values is quite complicated, + * depending on the hinting engine (that is, the graphics framework). + * + * framework from to formula + * ---------------------------------------------------------- + * GDI Windows 98 current (1) + * (Windows 2000 for NT) + * GDI+ Windows XP Windows 7 (2) + * GDI+ Windows 8 current (3) + * DWrite Windows 7 current (3) + * + * For simplicity, FreeType uses (1) for grayscale subpixel hinting and + * (3) for everything else. + * + */ + static void + tt_loader_set_pp( TT_Loader loader ) + { + loader->pp1.x = loader->bbox.xMin - loader->left_bearing; + loader->pp1.y = 0; + loader->pp2.x = loader->pp1.x + loader->advance; + loader->pp2.y = 0; + + loader->pp3.x = 0; + loader->pp3.y = loader->bbox.yMax + loader->top_bearing; + loader->pp4.x = 0; + loader->pp4.y = loader->pp3.y - loader->vadvance; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + { + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face ); + + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + loader->exec && + loader->exec->subpixel_hinting_lean && + loader->exec->grayscale_cleartype ) + { + loader->pp3.x = loader->advance / 2; + loader->pp4.x = loader->advance / 2; + } + } +#endif + } + + + /* a utility function to retrieve i-th node from given FT_List */ + static FT_ListNode + ft_list_get_node_at( FT_List list, + FT_UInt idx ) + { + FT_ListNode cur; + + + if ( !list ) + return NULL; + + for ( cur = list->head; cur; cur = cur->next ) + { + if ( !idx ) + return cur; + + idx--; + } + + return NULL; + } + + + /************************************************************************** + * + * @Function: + * load_truetype_glyph + * + * @Description: + * Loads a given truetype glyph. Handles composites and uses a + * TT_Loader object. + */ + static FT_Error + load_truetype_glyph( TT_Loader loader, + FT_UInt glyph_index, + FT_UInt recurse_count, + FT_Bool header_only ) + { + FT_Error error = FT_Err_Ok; + FT_Fixed x_scale, y_scale; + FT_ULong offset; + TT_Face face = loader->face; + FT_GlyphLoader gloader = loader->gloader; + + FT_Bool opened_frame = 0; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_StreamRec inc_stream; + FT_Data glyph_data; + FT_Bool glyph_data_loaded = 0; +#endif + + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( recurse_count ) + FT_TRACE5(( " nesting level: %d\n", recurse_count )); +#endif + + /* some fonts have an incorrect value of `maxComponentDepth' */ + if ( recurse_count > face->max_profile.maxComponentDepth ) + { + FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n", + recurse_count )); + face->max_profile.maxComponentDepth = (FT_UShort)recurse_count; + } + +#ifndef FT_CONFIG_OPTION_INCREMENTAL + /* check glyph index */ + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = FT_THROW( Invalid_Glyph_Index ); + goto Exit; + } +#endif + + loader->glyph_index = glyph_index; + + if ( loader->load_flags & FT_LOAD_NO_SCALE ) + { + x_scale = 0x10000L; + y_scale = 0x10000L; + } + else + { + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; + } + + /* Set `offset' to the start of the glyph relative to the start of */ + /* the `glyf' table, and `byte_len' to the length of the glyph in */ + /* bytes. */ + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* If we are loading glyph data via the incremental interface, set */ + /* the loader stream to a memory stream reading the data returned */ + /* by the interface. */ + if ( face->root.internal->incremental_interface ) + { + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &glyph_data ); + if ( error ) + goto Exit; + + glyph_data_loaded = 1; + offset = 0; + loader->byte_len = glyph_data.length; + + FT_ZERO( &inc_stream ); + FT_Stream_OpenMemory( &inc_stream, + glyph_data.pointer, + glyph_data.length ); + + loader->stream = &inc_stream; + } + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ULong len; + + + offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len ); + + loader->byte_len = (FT_UInt)len; + } + + if ( loader->byte_len > 0 ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* for the incremental interface, `glyf_offset' is always zero */ + if ( !face->glyf_offset && + !face->root.internal->incremental_interface ) +#else + if ( !face->glyf_offset ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + error = face->access_glyph_frame( loader, glyph_index, + face->glyf_offset + offset, + loader->byte_len ); + if ( error ) + goto Exit; + + /* read glyph header first */ + error = face->read_glyph_header( loader ); + + face->forget_glyph_frame( loader ); + + if ( error ) + goto Exit; + } + + /* a space glyph */ + if ( loader->byte_len == 0 || loader->n_contours == 0 ) + { + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + } + + /* the metrics must be computed after loading the glyph header */ + /* since we need the glyph's `yMax' value in case the vertical */ + /* metrics must be emulated */ + error = tt_get_metrics( loader, glyph_index ); + if ( error ) + goto Exit; + + if ( header_only ) + goto Exit; + + if ( loader->byte_len == 0 || loader->n_contours == 0 ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) + { + /* a small outline structure with four elements for */ + /* communication with `TT_Vary_Apply_Glyph_Deltas' */ + FT_Vector points[4]; + FT_Outline outline; + + /* unrounded values */ + FT_Vector unrounded[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + + + points[0] = loader->pp1; + points[1] = loader->pp2; + points[2] = loader->pp3; + points[3] = loader->pp4; + + outline.n_points = 0; + outline.n_contours = 0; + outline.points = points; + outline.tags = NULL; + outline.contours = NULL; + + /* this must be done before scaling */ + error = TT_Vary_Apply_Glyph_Deltas( loader, + &outline, + unrounded ); + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + error = FT_Err_Ok; + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* we now open a frame again, right after the glyph header */ + /* (which consists of 10 bytes) */ + error = face->access_glyph_frame( loader, glyph_index, + face->glyf_offset + offset + 10, + loader->byte_len - 10 ); + if ( error ) + goto Exit; + + opened_frame = 1; + + /* if it is a simple glyph, load it */ + + if ( loader->n_contours > 0 ) + { + error = face->read_simple_glyph( loader ); + if ( error ) + goto Exit; + + /* all data have been read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + + error = TT_Process_Simple_Glyph( loader ); + if ( error ) + goto Exit; + + FT_GlyphLoader_Add( gloader ); + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + /* otherwise, load a composite! */ + else if ( loader->n_contours < 0 ) + { + FT_Memory memory = face->root.memory; + + FT_UInt start_point; + FT_UInt start_contour; + FT_ULong ins_pos; /* position of composite instructions, if any */ + + FT_ListNode node, node2; + + + /* normalize the `n_contours' value */ + loader->n_contours = -1; + + /* + * We store the glyph index directly in the `node->data' pointer, + * following the glib solution (cf. macro `GUINT_TO_POINTER') with a + * double cast to make this portable. Note, however, that this needs + * pointers with a width of at least 32 bits. + */ + + /* clear the nodes filled by sibling chains */ + node = ft_list_get_node_at( &loader->composites, recurse_count ); + for ( node2 = node; node2; node2 = node2->next ) + node2->data = (void*)-1; + + /* check whether we already have a composite glyph with this index */ + if ( FT_List_Find( &loader->composites, + FT_UINT_TO_POINTER( glyph_index ) ) ) + { + FT_TRACE1(( "TT_Load_Composite_Glyph:" + " infinite recursion detected\n" )); + error = FT_THROW( Invalid_Composite ); + goto Exit; + } + + else if ( node ) + node->data = FT_UINT_TO_POINTER( glyph_index ); + + else + { + if ( FT_QNEW( node ) ) + goto Exit; + node->data = FT_UINT_TO_POINTER( glyph_index ); + FT_List_Add( &loader->composites, node ); + } + + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; + + /* for each subglyph, read composite header */ + error = face->read_composite_glyph( loader ); + if ( error ) + goto Exit; + + /* store the offset of instructions */ + ins_pos = loader->ins_pos; + + /* all data we need are read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) + { + FT_UShort i, limit; + FT_SubGlyph subglyph; + + FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 }; + FT_Vector* unrounded = NULL; + + + limit = (FT_UShort)gloader->current.num_subglyphs; + + /* construct an outline structure for */ + /* communication with `TT_Vary_Apply_Glyph_Deltas' */ + if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) || + FT_QNEW_ARRAY( outline.tags, limit ) || + FT_QNEW_ARRAY( outline.contours, limit ) || + FT_QNEW_ARRAY( unrounded, limit + 4 ) ) + goto Exit1; + + outline.n_contours = outline.n_points = limit; + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < limit; i++, subglyph++ ) + { + /* applying deltas for anchor points doesn't make sense, */ + /* but we don't have to specially check this since */ + /* unused delta values are zero anyways */ + outline.points[i].x = subglyph->arg1; + outline.points[i].y = subglyph->arg2; + outline.tags[i] = ON_CURVE_POINT; + outline.contours[i] = i; + } + + outline.points[i++] = loader->pp1; + outline.points[i++] = loader->pp2; + outline.points[i++] = loader->pp3; + outline.points[i ] = loader->pp4; + + /* this call provides additional offsets */ + /* for each component's translation */ + if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas( loader, + &outline, + unrounded ) ) ) + goto Exit1; + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < limit; i++, subglyph++ ) + { + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + subglyph->arg1 = (FT_Int16)outline.points[i].x; + subglyph->arg2 = (FT_Int16)outline.points[i].y; + } + } + + Exit1: + FT_FREE( outline.points ); + FT_FREE( outline.tags ); + FT_FREE( outline.contours ); + FT_FREE( unrounded ); + + if ( error ) + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + + /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ + /* `as is' in the glyph slot (the client application will be */ + /* responsible for interpreting these data)... */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + FT_GlyphLoader_Add( gloader ); + loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + + goto Exit; + } + + /*********************************************************************/ + /*********************************************************************/ + /*********************************************************************/ + + { + FT_UInt n, num_base_points; + FT_SubGlyph subglyph = NULL; + + FT_UInt num_points = start_point; + FT_UInt num_subglyphs = gloader->current.num_subglyphs; + FT_UInt num_base_subgs = gloader->base.num_subglyphs; + + FT_Stream old_stream = loader->stream; + FT_UInt old_byte_len = loader->byte_len; + + + FT_GlyphLoader_Add( gloader ); + + /* read each subglyph independently */ + for ( n = 0; n < num_subglyphs; n++ ) + { + FT_Vector pp[4]; + + FT_Int linear_hadvance; + FT_Int linear_vadvance; + + + /* Each time we call `load_truetype_glyph' in this loop, the */ + /* value of `gloader.base.subglyphs' can change due to table */ + /* reallocations. We thus need to recompute the subglyph */ + /* pointer on each iteration. */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + pp[0] = loader->pp1; + pp[1] = loader->pp2; + pp[2] = loader->pp3; + pp[3] = loader->pp4; + + linear_hadvance = loader->linear; + linear_vadvance = loader->vadvance; + + num_base_points = gloader->base.outline.n_points; + + error = load_truetype_glyph( loader, + (FT_UInt)subglyph->index, + recurse_count + 1, + FALSE ); + if ( error ) + goto Exit; + + /* restore subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + + /* restore phantom points if necessary */ + if ( !( subglyph->flags & USE_MY_METRICS ) ) + { + loader->pp1 = pp[0]; + loader->pp2 = pp[1]; + loader->pp3 = pp[2]; + loader->pp4 = pp[3]; + + loader->linear = linear_hadvance; + loader->vadvance = linear_vadvance; + } + + num_points = gloader->base.outline.n_points; + + if ( num_points == num_base_points ) + continue; + + /* gloader->base.outline consists of three parts: */ + /* */ + /* 0 ----> start_point ----> num_base_points ----> n_points */ + /* (1) (2) (3) */ + /* */ + /* (1) points that exist from the beginning */ + /* (2) component points that have been loaded so far */ + /* (3) points of the newly loaded component */ + error = TT_Process_Composite_Component( loader, + subglyph, + start_point, + num_base_points ); + if ( error ) + goto Exit; + } + + loader->stream = old_stream; + loader->byte_len = old_byte_len; + + /* process the glyph */ + loader->ins_pos = ins_pos; + if ( IS_HINTED( loader->load_flags ) && +#ifdef TT_USE_BYTECODE_INTERPRETER + subglyph && + subglyph->flags & WE_HAVE_INSTR && +#endif + num_points > start_point ) + { + error = TT_Process_Composite_Glyph( loader, + start_point, + start_contour ); + if ( error ) + goto Exit; + } + } + + /* retain the overlap flag */ + if ( gloader->base.num_subglyphs && + gloader->base.subglyphs[0].flags & OVERLAP_COMPOUND ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; + } + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + Exit: + + if ( opened_frame ) + face->forget_glyph_frame( loader ); + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( glyph_data_loaded ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + +#endif + + return error; + } + + + static FT_Error + compute_glyph_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = loader->face; + TT_Size size = loader->size; + TT_GlyphSlot glyph = loader->glyph; + FT_BBox bbox; + FT_Fixed y_scale; + + + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + y_scale = size->metrics->y_scale; + + if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + else + bbox = loader->bbox; + + /* get the device-independent horizontal advance; it is scaled later */ + /* by the base layer. */ + glyph->linearHoriAdvance = loader->linear; + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + if ( loader->widthp ) + glyph->metrics.horiAdvance = loader->widthp[glyph_index] * 64; + else + glyph->metrics.horiAdvance = SUB_LONG( loader->pp2.x, loader->pp1.x ); + + /* set glyph dimensions */ + glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); + glyph->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin ); + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), */ + /* create some metrics manually */ + { + FT_Pos top; /* scaled vertical top side bearing */ + FT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled top bearing and advance height. */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + top = (FT_Short)FT_DivFix( SUB_LONG( loader->pp3.y, bbox.yMax ), + y_scale ); + + if ( loader->pp3.y <= loader->pp4.y ) + advance = 0; + else + advance = (FT_UShort)FT_DivFix( SUB_LONG( loader->pp3.y, + loader->pp4.y ), + y_scale ); + } + else + { + FT_Pos height; + + + /* XXX Compute top side bearing and advance height in */ + /* Get_VMetrics instead of here. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them, if there is an OS/2 */ + /* table in the font. Otherwise, we use the */ + /* values defined in the horizontal header. */ + + height = (FT_Short)FT_DivFix( SUB_LONG( bbox.yMax, + bbox.yMin ), + y_scale ); + if ( face->os2.version != 0xFFFFU ) + advance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + advance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + + top = ( advance - height ) / 2; + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + { + FT_Incremental_InterfaceRec* incr; + FT_Incremental_MetricsRec incr_metrics; + FT_Error error; + + + incr = face->root.internal->incremental_interface; + + /* If this is an incrementally loaded font see if there are */ + /* overriding metrics for this glyph. */ + if ( incr && incr->funcs->get_glyph_metrics ) + { + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = top; + incr_metrics.advance = advance; + + error = incr->funcs->get_glyph_metrics( incr->object, + glyph_index, + TRUE, + &incr_metrics ); + if ( error ) + return error; + + top = incr_metrics.bearing_y; + advance = incr_metrics.advance; + } + } + + /* GWW: Do vertical metrics get loaded incrementally too? */ + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + glyph->linearVertAdvance = advance; + + /* scale the metrics */ + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + top = FT_MulFix( top, y_scale ); + advance = FT_MulFix( advance, y_scale ); + } + + /* XXX: for now, we have no better algorithm for the lsb, but it */ + /* should work fine. */ + /* */ + glyph->metrics.vertBearingX = SUB_LONG( glyph->metrics.horiBearingX, + glyph->metrics.horiAdvance / 2 ); + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + return FT_Err_Ok; + } + + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + static FT_Error + load_sbit_image( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face = (TT_Face)glyph->face; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + FT_Stream stream = face->root.stream; + FT_Error error; + TT_SBit_MetricsRec sbit_metrics; + + + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_UInt)load_flags, + stream, + &glyph->bitmap, + &sbit_metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (FT_Pos)sbit_metrics.width * 64; + glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64; + + glyph->metrics.horiBearingX = (FT_Pos)sbit_metrics.horiBearingX * 64; + glyph->metrics.horiBearingY = (FT_Pos)sbit_metrics.horiBearingY * 64; + glyph->metrics.horiAdvance = (FT_Pos)sbit_metrics.horiAdvance * 64; + + glyph->metrics.vertBearingX = (FT_Pos)sbit_metrics.vertBearingX * 64; + glyph->metrics.vertBearingY = (FT_Pos)sbit_metrics.vertBearingY * 64; + glyph->metrics.vertAdvance = (FT_Pos)sbit_metrics.vertAdvance * 64; + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->bitmap_left = sbit_metrics.vertBearingX; + glyph->bitmap_top = sbit_metrics.vertBearingY; + } + else + { + glyph->bitmap_left = sbit_metrics.horiBearingX; + glyph->bitmap_top = sbit_metrics.horiBearingY; + } + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + + static FT_Error + tt_loader_init( TT_Loader loader, + TT_Size size, + TT_GlyphSlot glyph, + FT_Int32 load_flags, + FT_Bool glyf_table_only ) + { + TT_Face face = (TT_Face)glyph->face; + FT_Stream stream = face->root.stream; + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_Error error; + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face ); +#endif +#endif + + + FT_ZERO( loader ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /* load execution context */ + if ( IS_HINTED( load_flags ) && !glyf_table_only ) + { + TT_ExecContext exec; + FT_Bool grayscale = TRUE; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool subpixel_hinting_lean; + FT_Bool grayscale_cleartype; +#endif + + FT_Bool reexecute = FALSE; + + + if ( size->bytecode_ready < 0 || size->cvt_ready < 0 ) + { + error = tt_size_ready_bytecode( size, pedantic ); + if ( error ) + return error; + } + else if ( size->bytecode_ready ) + return size->bytecode_ready; + else if ( size->cvt_ready ) + return size->cvt_ready; + + /* query new execution context */ + exec = size->context; + if ( !exec ) + return FT_THROW( Could_Not_Find_Context ); + + grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + subpixel_hinting_lean = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + grayscale_cleartype = + FT_BOOL( subpixel_hinting_lean && + !( ( load_flags & + FT_LOAD_TARGET_LCD ) || + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ) ); + exec->vertical_lcd_lean = + FT_BOOL( subpixel_hinting_lean && + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ); + grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean ); + } + else + { + subpixel_hinting_lean = FALSE; + grayscale_cleartype = FALSE; + exec->vertical_lcd_lean = FALSE; + } +#endif + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( subpixel_hinting_lean != exec->subpixel_hinting_lean ) + { + FT_TRACE4(( "tt_loader_init: subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->subpixel_hinting_lean = subpixel_hinting_lean; + reexecute = TRUE; + } + + /* a change from colored to grayscale subpixel rendering (and */ + /* vice versa) requires a re-execution of the CVT program */ + if ( grayscale_cleartype != exec->grayscale_cleartype ) + { + FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale_cleartype = grayscale_cleartype; + reexecute = TRUE; + } + } +#endif + + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_TRACE4(( "tt_loader_init: grayscale hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + } + + if ( reexecute ) + { + error = tt_size_run_prep( size, pedantic ); + if ( error ) + return error; + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + } + + /* check whether the cvt program has disabled hinting */ + if ( exec->GS.instruct_control & 1 ) + load_flags |= FT_LOAD_NO_HINTING; + + /* load default graphics state -- if needed */ + if ( exec->GS.instruct_control & 2 ) + exec->GS = tt_default_graphics_state; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Toggle backward compatibility according to what font wants, except + * when + * + * 1) we have a `tricky' font that heavily relies on the interpreter to + * render glyphs correctly, for example DFKai-SB, or + * 2) FT_RENDER_MODE_MONO (i.e, monochrome rendering) is requested. + * + * In those cases, backward compatibility needs to be turned off to get + * correct rendering. The rendering is then completely up to the + * font's programming. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + subpixel_hinting_lean && + !FT_IS_TRICKY( glyph->face ) ) + exec->backward_compatibility = !( exec->GS.instruct_control & 4 ); + else + exec->backward_compatibility = FALSE; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + + exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + loader->exec = exec; + loader->instructions = exec->glyphIns; + + /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */ + /* is set or backward compatibility mode of the v38 or v40 */ + /* interpreters is active. See `ttinterp.h' for details on */ + /* backward compatibility mode. */ + if ( IS_HINTED( loader->load_flags ) && + !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + exec->backward_compatibility ) && +#endif + !face->postscript.isFixedPitch ) + { + loader->widthp = size->widthp; + } + else + loader->widthp = NULL; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + /* get face's glyph loader */ + if ( !glyf_table_only ) + { + FT_GlyphLoader gloader = glyph->internal->loader; + + + FT_GlyphLoader_Rewind( gloader ); + loader->gloader = gloader; + } + + loader->load_flags = (FT_ULong)load_flags; + + loader->face = face; + loader->size = size; + loader->glyph = (FT_GlyphSlot)glyph; + loader->stream = stream; + + loader->composites.head = NULL; + loader->composites.tail = NULL; + + return FT_Err_Ok; + } + + + static void + tt_loader_done( TT_Loader loader ) + { + FT_List_Finalize( &loader->composites, + NULL, + loader->face->root.memory, + NULL ); + } + + + /************************************************************************** + * + * @Function: + * TT_Load_Glyph + * + * @Description: + * A function used to load a single glyph within a given glyph slot, + * for a given size. + * + * @InOut: + * glyph :: + * A handle to a target slot object where the glyph + * will be loaded. + * + * @Input: + * size :: + * A handle to the source face size at which the glyph + * must be scaled/loaded. + * + * glyph_index :: + * The index of the glyph in the font file. + * + * load_flags :: + * A flag indicating what to load for this glyph. The + * FT_LOAD_XXX constants can be used to control the + * glyph loading process (e.g., whether the outline + * should be scaled, whether to load bitmaps or not, + * whether to hint the outline, etc). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face = (TT_Face)glyph->face; + FT_Error error; + TT_LoaderRec loader; + + + FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + + /* try to load embedded bitmap (if any) */ + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( glyph->face ) ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + + error = load_sbit_image( size, glyph, glyph_index, load_flags ); + if ( FT_ERR_EQ( error, Missing_Bitmap ) ) + { + /* the bitmap strike is incomplete and misses the requested glyph; */ + /* if we have a bitmap-only font, return an empty glyph */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + { + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + /* to return an empty glyph, however, we need metrics data */ + /* from the `hmtx' (or `vmtx') table; the assumption is that */ + /* empty glyphs are missing intentionally, representing */ + /* whitespace - not having at least horizontal metrics is */ + /* thus considered an error */ + if ( !face->horz_metrics_size ) + return error; + + /* we now construct an empty bitmap glyph */ + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = 0; + glyph->metrics.height = 0; + + glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); + glyph->metrics.horiBearingY = 0; + glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); + + glyph->metrics.vertBearingX = 0; + glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->bitmap_left = 0; + glyph->bitmap_top = 0; + + return FT_Err_Ok; + } + } + else if ( error ) + { + /* return error if font is not scalable */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + return error; + } + else + { + if ( FT_IS_SCALABLE( glyph->face ) || + FT_HAS_SBIX( glyph->face ) ) + { + /* for the bbox we need the header only */ + (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); + (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); + tt_loader_done( &loader ); + glyph->linearHoriAdvance = loader.linear; + glyph->linearVertAdvance = loader.vadvance; + + /* Bitmaps from the 'sbix' table need special treatment: */ + /* if there is a glyph contour, the bitmap origin must be */ + /* shifted to be relative to the lower left corner of the */ + /* glyph bounding box, also taking the left-side bearing */ + /* (or top bearing) into account. */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX && + loader.n_contours > 0 ) + { + FT_Int bitmap_left; + FT_Int bitmap_top; + + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* This is a guess, since Apple's CoreText engine doesn't */ + /* really do vertical typesetting. */ + bitmap_left = loader.bbox.xMin; + bitmap_top = loader.top_bearing; + } + else + { + bitmap_left = loader.left_bearing; + bitmap_top = loader.bbox.yMin; + } + + glyph->bitmap_left += FT_MulFix( bitmap_left, x_scale ) >> 6; + glyph->bitmap_top += FT_MulFix( bitmap_top, y_scale ) >> 6; + } + + /* sanity checks: if `xxxAdvance' in the sbit metric */ + /* structure isn't set, use `linearXXXAdvance' */ + if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) + glyph->metrics.horiAdvance = FT_MulFix( glyph->linearHoriAdvance, + x_scale ); + if ( !glyph->metrics.vertAdvance && glyph->linearVertAdvance ) + glyph->metrics.vertAdvance = FT_MulFix( glyph->linearVertAdvance, + y_scale ); + } + + return FT_Err_Ok; + } + } + + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) + { + error = FT_THROW( Invalid_Size_Handle ); + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_SVG + + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short leftBearing; + FT_Short topBearing; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->format = FT_GLYPH_FORMAT_SVG; + + sfnt->get_metrics( face, + FALSE, + glyph_index, + &leftBearing, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &topBearing, + &advanceY ); + + glyph->linearHoriAdvance = advanceX; + glyph->linearVertAdvance = advanceY; + + glyph->metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + + /* return immediately if we only want SVG glyphs */ + if ( load_flags & FT_LOAD_SVG_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); + if ( error ) + goto Exit; + + /* done if we are only interested in the `hdmx` advance */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY && + !( load_flags & FT_LOAD_VERTICAL_LAYOUT ) && + loader.widthp ) + { + glyph->metrics.horiAdvance = loader.widthp[glyph_index] * 64; + goto Done; + } + + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->num_subglyphs = 0; + glyph->outline.flags = 0; + + /* main loading loop */ + error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); + if ( !error ) + { + if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE ) + { + glyph->num_subglyphs = loader.gloader->base.num_subglyphs; + glyph->subglyphs = loader.gloader->base.subglyphs; + } + else + { + glyph->outline = loader.gloader->base.outline; + glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; + + /* Translate array so that (0,0) is the glyph's origin. Note */ + /* that this behaviour is independent on the value of bit 1 of */ + /* the `flags' field in the `head' table -- at least major */ + /* applications like Acroread indicate that. */ + if ( loader.pp1.x ) + FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + + if ( IS_HINTED( load_flags ) ) + { + glyph->control_data = loader.exec->glyphIns; + glyph->control_len = loader.exec->glyphSize; + + if ( loader.exec->GS.scan_control ) + { + /* convert scan conversion mode to FT_OUTLINE_XXX flags */ + switch ( loader.exec->GS.scan_type ) + { + case 0: /* simple drop-outs including stubs */ + glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS; + break; + case 1: /* simple drop-outs excluding stubs */ + /* nothing; it's the default rendering mode */ + break; + case 4: /* smart drop-outs including stubs */ + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS | + FT_OUTLINE_INCLUDE_STUBS; + break; + case 5: /* smart drop-outs excluding stubs */ + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS; + break; + + default: /* no drop-out control */ + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + break; + } + } + else + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + error = compute_glyph_metrics( &loader, glyph_index ); + } + + /* Set the `high precision' bit flag. */ + /* This is _critical_ to get correct output for monochrome */ + /* TrueType glyphs at all sizes using the bytecode interpreter. */ + /* */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && + size->metrics->y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + + FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu," + " flags = 0x%.3x\n", + loader.gloader->base.num_subglyphs, + glyph->outline.n_contours, + glyph->outline.n_points, + glyph->outline.flags )); + + Done: + tt_loader_done( &loader ); + + Exit: +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE1(( " failed (error code 0x%x)\n", + error )); +#endif + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttgload.h b/Dependencies/freetype/freetype/src/truetype/ttgload.h new file mode 100644 index 00000000..22ea967f --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttgload.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * + * ttgload.h + * + * TrueType Glyph Loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTGLOAD_H_ +#define TTGLOAD_H_ + + +#include "ttobjs.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + TT_Init_Glyph_Loading( TT_Face face ); + + FT_LOCAL( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ); + + FT_LOCAL( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Pos yMax, + FT_Short* tsb, + FT_UShort* ah ); + + FT_LOCAL( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* TTGLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttgxvar.c b/Dependencies/freetype/freetype/src/truetype/ttgxvar.c new file mode 100644 index 00000000..4f0083c9 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttgxvar.c @@ -0,0 +1,4594 @@ +/**************************************************************************** + * + * ttgxvar.c + * + * TrueType GX Font Variation loader + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * Apple documents the `fvar', `gvar', `cvar', and `avar' tables at + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html + * + * The documentation for `gvar' is not intelligible; `cvar' refers you + * to `gvar' and is thus also incomprehensible. + * + * The documentation for `avar' appears correct, but Apple has no fonts + * with an `avar' table, so it is hard to test. + * + * Many thanks to John Jenkins (at Apple) in figuring this out. + * + * + * Apple's `kern' table has some references to tuple indices, but as + * there is no indication where these indices are defined, nor how to + * interpolate the kerning values (different tuples have different + * classes) this issue is ignored. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ttpload.h" +#include "ttgxvar.h" + +#include "tterrors.h" + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + +#define FT_Stream_FTell( stream ) \ + (FT_ULong)( (stream)->cursor - (stream)->base ) +#define FT_Stream_SeekSet( stream, off ) \ + (stream)->cursor = \ + ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \ + ? (stream)->base + (off) \ + : (stream)->limit + + + /* some macros we need */ +#define FT_fdot14ToFixed( x ) \ + ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) +#define FT_intToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) +#define FT_fdot6ToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 10 ) ) +#define FT_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) +#define FT_fixedToFdot6( x ) \ + ( (FT_Pos)( ( (x) + 0x200 ) >> 10 ) ) + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttgxvar + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Internal Routines *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /************************************************************************** + * + * The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It + * indicates that there is a delta for every point without needing to + * enumerate all of them. + */ + + /* ensure that value `0' has the same width as a pointer */ +#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 + + +#define GX_PT_POINTS_ARE_WORDS 0x80U +#define GX_PT_POINT_RUN_COUNT_MASK 0x7FU + + + /************************************************************************** + * + * @Function: + * ft_var_readpackedpoints + * + * @Description: + * Read a set of points to which the following deltas will apply. + * Points are packed with a run length encoding. + * + * @Input: + * stream :: + * The data stream. + * + * @Output: + * point_cnt :: + * The number of points read. A zero value means that + * all points in the glyph will be affected, without + * enumerating them individually. + * + * @Return: + * An array of FT_UShort containing the affected points or the + * special value ALL_POINTS. + */ + static FT_UShort* + ft_var_readpackedpoints( FT_Stream stream, + FT_UInt *point_cnt ) + { + FT_UShort *points = NULL; + FT_UInt n; + FT_UInt runcnt, cnt; + FT_UInt i, j; + FT_UShort first; + FT_Byte* p; + FT_Memory memory = stream->memory; + FT_Error error; + + + *point_cnt = 0; + + n = FT_GET_BYTE(); + if ( n == 0 ) + return ALL_POINTS; + + if ( n & GX_PT_POINTS_ARE_WORDS ) + { + n &= GX_PT_POINT_RUN_COUNT_MASK; + n <<= 8; + n |= FT_GET_BYTE(); + } + + if ( FT_QNEW_ARRAY( points, n ) ) + return NULL; + + p = stream->cursor; + first = 0; + i = 0; + while ( i < n ) + { + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); + cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; + + /* first point not included in run count */ + cnt++; + if ( cnt > n - i ) + cnt = n - i; + + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) + { + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; + + for ( j = 0; j < cnt; j++ ) + { + first += FT_NEXT_USHORT( p ); + points[i++] = first; + } + } + else + { + if ( cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; + + for ( j = 0; j < cnt; j++ ) + { + first += FT_NEXT_BYTE( p ); + points[i++] = first; + } + } + } + + stream->cursor = p; + + *point_cnt = n; + + return points; + + Fail: + FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" )); + + FT_FREE( points ); + return NULL; + } + + +#define GX_DT_DELTAS_ARE_ZERO 0x80U +#define GX_DT_DELTAS_ARE_WORDS 0x40U +#define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU + + + /************************************************************************** + * + * @Function: + * ft_var_readpackeddeltas + * + * @Description: + * Read a set of deltas. These are packed slightly differently than + * points. In particular there is no overall count. + * + * @Input: + * stream :: + * The data stream. + * + * delta_cnt :: + * The number of deltas to be read. + * + * @Return: + * An array of FT_Fixed containing the deltas for the affected + * points. (This only gets the deltas for one dimension. It will + * generally be called twice, once for x, once for y. When used in + * cvt table, it will only be called once.) + * + * We use FT_Fixed to avoid accumulation errors while summing up all + * deltas (the rounding to integer values happens as the very last + * step). + */ + static FT_Fixed* + ft_var_readpackeddeltas( FT_Stream stream, + FT_UInt delta_cnt ) + { + FT_Fixed *deltas = NULL; + FT_UInt runcnt, cnt; + FT_UInt i, j; + FT_Byte* p; + FT_Memory memory = stream->memory; + FT_Error error; + + + if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) + return NULL; + + p = stream->cursor; + i = 0; + while ( i < delta_cnt ) + { + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); + cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; + + /* first point not included in run count */ + cnt++; + if ( cnt > delta_cnt - i ) + cnt = delta_cnt - i; + + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) + { + for ( j = 0; j < cnt; j++ ) + deltas[i++] = 0; + } + else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) + { + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; + + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) ); + } + else + { + if ( cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; + + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_CHAR( p ) ); + } + } + + stream->cursor = p; + + return deltas; + + Fail: + FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" )); + + FT_FREE( deltas ); + return NULL; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_avar + * + * @Description: + * Parse the `avar' table if present. It need not be, so we return + * nothing. + * + * @InOut: + * face :: + * The font face. + */ + static void + ft_var_load_avar( TT_Face face ) + { + FT_Error error; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Int i, j; + + GX_Blend blend = face->blend; + GX_AVarSegment segment; + GX_AVarTable table; + + FT_Long version; + FT_Long axisCount; + FT_ULong table_len; + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong axisMap_offset; +#endif + + + FT_TRACE2(( "AVAR " )); + + blend->avar_loaded = TRUE; + error = face->goto_table( face, TTAG_avar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + return; + } + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + table_offset = FT_STREAM_POS(); +#endif + + if ( FT_FRAME_ENTER( table_len ) ) + return; + + version = FT_GET_LONG(); + axisCount = FT_GET_LONG(); + + if ( version != 0x00010000L +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + && version != 0x00020000L +#endif + ) + { + FT_TRACE2(( "bad table version\n" )); + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + + if ( axisCount != (FT_Long)blend->mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_load_avar:" + " number of axes in `avar' and `fvar'\n" )); + FT_TRACE2(( " table are different\n" )); + goto Exit; + } + + if ( FT_NEW( blend->avar_table ) ) + goto Exit; + table = blend->avar_table; + + if ( FT_QNEW_ARRAY( table->avar_segment, axisCount ) ) + goto Exit; + + segment = &table->avar_segment[0]; + for ( i = 0; i < axisCount; i++, segment++ ) + { + FT_TRACE5(( " axis %d:\n", i )); + + segment->pairCount = FT_GET_USHORT(); + if ( (FT_ULong)segment->pairCount * 4 > table_len || + FT_QNEW_ARRAY( segment->correspondence, segment->pairCount ) ) + { + /* Failure. Free everything we have done so far. We must do */ + /* it right now since loading the `avar' table is optional. */ + + for ( j = i - 1; j >= 0; j-- ) + FT_FREE( table->avar_segment[j].correspondence ); + + FT_FREE( table->avar_segment ); + goto Exit; + } + + for ( j = 0; j < segment->pairCount; j++ ) + { + segment->correspondence[j].fromCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); + segment->correspondence[j].toCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); + + FT_TRACE5(( " mapping %.5f to %.5f\n", + (double)segment->correspondence[j].fromCoord / 65536, + (double)segment->correspondence[j].toCoord / 65536 )); + } + + FT_TRACE5(( "\n" )); + } + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + if ( version < 0x00020000L ) + goto Exit; + + axisMap_offset = FT_GET_ULONG(); + store_offset = FT_GET_ULONG(); + + if ( store_offset ) + { + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + } + + if ( axisMap_offset ) + { + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), + table_offset + axisMap_offset, + &table->axisMap, + &table->itemStore, + table_len ); + if ( error ) + goto Exit; + } +#endif + + + Exit: + FT_FRAME_EXIT(); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_var_load_item_variation_store( FT_Face face, /* TT_Face */ + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + FT_UShort format; + FT_ULong region_offset; + + FT_UInt data_count; + FT_UShort axis_count; + FT_UInt region_count; + + FT_UInt i, j; + FT_Bool long_words; + + GX_Blend blend = ttface->blend; + FT_ULong* dataOffsetArray = NULL; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_USHORT( format ) ) + goto Exit; + + if ( format != 1 ) + { + FT_TRACE2(( "tt_var_load_item_variation_store: bad store format %d\n", + format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( region_offset ) || + FT_READ_USHORT( data_count ) ) + goto Exit; + + /* we need at least one entry in `itemStore->varData' */ + if ( !data_count ) + { + FT_TRACE2(( "tt_var_load_item_variation_store: missing varData\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* make temporary copy of item variation data offsets; */ + /* we will parse region list first, then come back */ + if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) ) + goto Exit; + + for ( i = 0; i < data_count; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse array of region records (region list) */ + if ( FT_STREAM_SEEK( offset + region_offset ) ) + goto Exit; + + if ( FT_READ_USHORT( axis_count ) || + FT_READ_USHORT( region_count ) ) + goto Exit; + + if ( axis_count != (FT_Long)blend->mmvar->num_axis ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " number of axes in item variation store\n" )); + FT_TRACE2(( " " + " and `fvar' table are different\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + itemStore->axisCount = axis_count; + + /* new constraint in OpenType 1.8.4 */ + if ( region_count >= 32768U ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " too many variation region tables\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_NEW_ARRAY( itemStore->varRegionList, region_count ) ) + goto Exit; + itemStore->regionCount = region_count; + + for ( i = 0; i < itemStore->regionCount; i++ ) + { + GX_AxisCoords axisCoords; + + + if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) ) + goto Exit; + + axisCoords = itemStore->varRegionList[i].axisList; + + for ( j = 0; j < itemStore->axisCount; j++ ) + { + FT_Int start, peak, end; + + + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) + goto Exit; + + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; + + axisCoords[j].startCoord = FT_fdot14ToFixed( start ); + axisCoords[j].peakCoord = FT_fdot14ToFixed( peak ); + axisCoords[j].endCoord = FT_fdot14ToFixed( end ); + } + } + + /* end of region list parse */ + + /* use dataOffsetArray now to parse varData items */ + if ( FT_NEW_ARRAY( itemStore->varData, data_count ) ) + goto Exit; + itemStore->dataCount = data_count; + + for ( i = 0; i < data_count; i++ ) + { + GX_ItemVarData varData = &itemStore->varData[i]; + + FT_UInt item_count; + FT_UShort word_delta_count; + FT_UInt region_idx_count; + FT_UInt per_region_size; + + + if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) ) + goto Exit; + + if ( FT_READ_USHORT( item_count ) || + FT_READ_USHORT( word_delta_count ) || + FT_READ_USHORT( region_idx_count ) ) + goto Exit; + + long_words = !!( word_delta_count & 0x8000 ); + word_delta_count &= 0x7FFF; + + /* check some data consistency */ + if ( word_delta_count > region_idx_count ) + { + FT_TRACE2(( "bad short count %d or region count %d\n", + word_delta_count, + region_idx_count )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( region_idx_count > itemStore->regionCount ) + { + FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", + region_idx_count, + i )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* parse region indices */ + if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) ) + goto Exit; + varData->regionIdxCount = region_idx_count; + varData->wordDeltaCount = word_delta_count; + varData->longWords = long_words; + + for ( j = 0; j < varData->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( varData->regionIndices[j] ) ) + goto Exit; + + if ( varData->regionIndices[j] >= itemStore->regionCount ) + { + FT_TRACE2(( "bad region index %d\n", + varData->regionIndices[j] )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + per_region_size = word_delta_count + region_idx_count; + if ( long_words ) + per_region_size *= 2; + + if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) ) + goto Exit; + if ( FT_Stream_Read( stream, + varData->deltaSet, + per_region_size * item_count ) ) + { + FT_TRACE2(( "deltaSet read failed." )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + varData->itemCount = item_count; + } + + Exit: + FT_FREE( dataOffsetArray ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, /* TT_Face */ + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + + FT_Byte format; + FT_Byte entryFormat; + FT_UInt entrySize; + FT_UInt innerBitCount; + FT_UInt innerIndexMask; + FT_ULong i; + FT_UInt j; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_BYTE( format ) || + FT_READ_BYTE( entryFormat ) ) + goto Exit; + + if ( format == 0 ) + { + if ( FT_READ_USHORT( map->mapCount ) ) + goto Exit; + } + else if ( format == 1 ) /* new in OpenType 1.9 */ + { + if ( FT_READ_ULONG( map->mapCount ) ) + goto Exit; + } + else + { + FT_TRACE2(( "bad map format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( entryFormat & 0xC0 ) + { + FT_TRACE2(( "bad entry format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* bytes per entry: 1, 2, 3, or 4 */ + entrySize = ( ( entryFormat & 0x30 ) >> 4 ) + 1; + innerBitCount = ( entryFormat & 0x0F ) + 1; + innerIndexMask = ( 1 << innerBitCount ) - 1; + + /* rough sanity check */ + if ( map->mapCount * entrySize > table_len ) + { + FT_TRACE1(( "tt_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) + goto Exit; + + if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) + goto Exit; + + for ( i = 0; i < map->mapCount; i++ ) + { + FT_UInt mapData = 0; + FT_UInt outerIndex, innerIndex; + + + /* read map data one unsigned byte at a time, big endian */ + for ( j = 0; j < entrySize; j++ ) + { + FT_Byte data; + + + if ( FT_READ_BYTE( data ) ) + goto Exit; + + mapData = ( mapData << 8 ) | data; + } + + /* new in OpenType 1.8.4 */ + if ( mapData == 0xFFFFFFFFUL ) + { + /* no variation data for this item */ + map->outerIndex[i] = 0xFFFFU; + map->innerIndex[i] = 0xFFFFU; + + continue; + } + + outerIndex = mapData >> innerBitCount; + + if ( outerIndex >= itemStore->dataCount ) + { + FT_TRACE2(( "outerIndex[%ld] == %d out of range\n", + i, + outerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->outerIndex[i] = outerIndex; + + innerIndex = mapData & innerIndexMask; + + if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) + { + FT_TRACE2(( "innerIndex[%ld] == %d out of range\n", + i, + innerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->innerIndex[i] = innerIndex; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_hvvar + * + * @Description: + * If `vertical' is zero, parse the `HVAR' table and set + * `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked' + * is set to TRUE. + * + * If `vertical' is not zero, parse the `VVAR' table and set + * `blend->vvar_loaded' to TRUE. On success, `blend->vvar_checked' + * is set to TRUE. + * + * Some memory may remain allocated on error; it is always freed in + * `tt_done_blend', however. + * + * @InOut: + * face :: + * The font face. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + ft_var_load_hvvar( TT_Face face, + FT_Bool vertical ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + + GX_HVVarTable table; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong widthMap_offset; + + + if ( vertical ) + { + blend->vvar_loaded = TRUE; + + FT_TRACE2(( "VVAR " )); + + error = face->goto_table( face, TTAG_VVAR, stream, &table_len ); + } + else + { + blend->hvar_loaded = TRUE; + + FT_TRACE2(( "HVAR " )); + + error = face->goto_table( face, TTAG_HVAR, stream, &table_len ); + } + + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + goto Exit; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_READ_ULONG( store_offset ) || + FT_READ_ULONG( widthMap_offset ) ) + goto Exit; + + if ( vertical ) + { + if ( FT_NEW( blend->vvar_table ) ) + goto Exit; + table = blend->vvar_table; + } + else + { + if ( FT_NEW( blend->hvar_table ) ) + goto Exit; + table = blend->hvar_table; + } + + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + + if ( widthMap_offset ) + { + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), + table_offset + widthMap_offset, + &table->widthMap, + &table->itemStore, + table_len ); + if ( error ) + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + error = FT_Err_Ok; + + Exit: + if ( !error ) + { + if ( vertical ) + { + blend->vvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* TSB, BSB, or VORG values; we thus don't have to implement */ + /* support for those three item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE; + } + else + { + blend->hvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* LSB or RSB values; we thus don't have to implement */ + /* support for those two item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE; + } + } + + return error; + } + + + FT_LOCAL_DEF( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, /* TT_Face */ + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + GX_ItemVarData varData; + FT_ItemVarDelta* deltaSet = NULL; + FT_ItemVarDelta deltaSetStack[16]; + + FT_Fixed* scalars = NULL; + FT_Fixed scalarsStack[16]; + + FT_UInt master, j; + FT_ItemVarDelta returnValue = 0; + FT_UInt per_region_size; + FT_Byte* bytes; + + + if ( !ttface->blend || !ttface->blend->normalizedcoords ) + return 0; + + /* OpenType 1.8.4+: No variation data for this item */ + /* as indices have special value 0xFFFF. */ + if ( outerIndex == 0xFFFF && innerIndex == 0xFFFF ) + return 0; + + /* See pseudo code from `Font Variations Overview' */ + /* in the OpenType specification. */ + + if ( outerIndex >= itemStore->dataCount ) + return 0; /* Out of range. */ + + varData = &itemStore->varData[outerIndex]; + + if ( innerIndex >= varData->itemCount ) + return 0; /* Out of range. */ + + if ( varData->regionIdxCount == 0 ) + return 0; /* Avoid "applying zero offset to null pointer". */ + + if ( varData->regionIdxCount < 16 ) + { + deltaSet = deltaSetStack; + scalars = scalarsStack; + } + else + { + if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) ) + goto Exit; + if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) ) + goto Exit; + } + + /* Parse delta set. */ + /* */ + /* Deltas are (word_delta_count + region_idx_count) bytes each */ + /* if `longWords` isn't set, and twice as much otherwise. */ + per_region_size = varData->wordDeltaCount + varData->regionIdxCount; + if ( varData->longWords ) + per_region_size *= 2; + + bytes = varData->deltaSet + per_region_size * innerIndex; + + if ( varData->longWords ) + { + for ( master = 0; master < varData->wordDeltaCount; master++ ) + deltaSet[master] = FT_NEXT_LONG( bytes ); + for ( ; master < varData->regionIdxCount; master++ ) + deltaSet[master] = FT_NEXT_SHORT( bytes ); + } + else + { + for ( master = 0; master < varData->wordDeltaCount; master++ ) + deltaSet[master] = FT_NEXT_SHORT( bytes ); + for ( ; master < varData->regionIdxCount; master++ ) + deltaSet[master] = FT_NEXT_CHAR( bytes ); + } + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < varData->regionIdxCount; master++ ) + { + FT_Fixed scalar = 0x10000L; + FT_UInt regionIndex = varData->regionIndices[master]; + + GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; + + + /* inner loop steps through axes in this region */ + for ( j = 0; j < itemStore->axisCount; j++, axis++ ) + { + FT_Fixed ncv = ttface->blend->normalizedcoords[j]; + + + /* compute the scalar contribution of this axis */ + /* with peak of 0 used for invalid axes */ + if ( axis->peakCoord == ncv || + axis->peakCoord == 0 ) + continue; + + /* ignore this region if coords are out of range */ + else if ( ncv <= axis->startCoord || + ncv >= axis->endCoord ) + { + scalar = 0; + break; + } + + /* cumulative product of all the axis scalars */ + else if ( ncv < axis->peakCoord ) + scalar = FT_MulDiv( scalar, + ncv - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* ncv > axis->peakCoord */ + scalar = FT_MulDiv( scalar, + axis->endCoord - ncv, + axis->endCoord - axis->peakCoord ); + + } /* per-axis loop */ + + scalars[master] = scalar; + + } /* per-region loop */ + + + /* Compute the scaled delta for this region. + * + * From: https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables: + * + * `Fixed` is a 32-bit (16.16) type and, in the general case, requires + * 32-bit deltas. As described above, the `DeltaSet` record can + * accommodate deltas that are, logically, either 16-bit or 32-bit. + * When scaled deltas are applied to `Fixed` values, the `Fixed` value + * is treated like a 32-bit integer. + * + * `FT_MulAddFix` internally uses 64-bit precision; it thus can handle + * deltas ranging from small 8-bit to large 32-bit values that are + * applied to 16.16 `FT_Fixed` / OpenType `Fixed` values. + */ + returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount ); + + Exit: + if ( scalars != scalarsStack ) + FT_FREE( scalars ); + if ( deltaSet != deltaSetStack ) + FT_FREE( deltaSet ); + + return returnValue; + } + + + /************************************************************************** + * + * @Function: + * tt_hvadvance_adjust + * + * @Description: + * Apply `HVAR' advance width or `VVAR' advance height adjustment of + * a given glyph. + * + * @Input: + * gindex :: + * The glyph index. + * + * vertical :: + * If set, handle `VVAR' table. + * + * @InOut: + * face :: + * The font face. + * + * adelta :: + * Points to width or height value that gets modified. + */ + static FT_Error + tt_hvadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *avalue, + FT_Bool vertical ) + { + FT_Error error = FT_Err_Ok; + FT_UInt innerIndex, outerIndex; + FT_Int delta; + + GX_HVVarTable table; + + + if ( !face->doblend || !face->blend ) + goto Exit; + + if ( vertical ) + { + if ( !face->blend->vvar_loaded ) + { + /* initialize vvar table */ + face->blend->vvar_error = ft_var_load_hvvar( face, 1 ); + } + + if ( !face->blend->vvar_checked ) + { + error = face->blend->vvar_error; + goto Exit; + } + + table = face->blend->vvar_table; + } + else + { + if ( !face->blend->hvar_loaded ) + { + /* initialize hvar table */ + face->blend->hvar_error = ft_var_load_hvvar( face, 0 ); + } + + if ( !face->blend->hvar_checked ) + { + error = face->blend->hvar_error; + goto Exit; + } + + table = face->blend->hvar_table; + } + + /* advance width or height adjustments are always present in an */ + /* `HVAR' or `VVAR' table; no need to test for this capability */ + + if ( table->widthMap.innerIndex ) + { + FT_UInt idx = gindex; + + + if ( idx >= table->widthMap.mapCount ) + idx = table->widthMap.mapCount - 1; + + /* trust that HVAR parser has checked indices */ + outerIndex = table->widthMap.outerIndex[idx]; + innerIndex = table->widthMap.innerIndex[idx]; + } + else + { + /* no widthMap data */ + outerIndex = 0; + innerIndex = gindex; + } + + delta = tt_var_get_item_delta( FT_FACE( face ), + &table->itemStore, + outerIndex, + innerIndex ); + + if ( delta ) + { + FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", + vertical ? "vertical height" : "horizontal width", + *avalue, + delta, + delta == 1 ? "" : "s", + vertical ? "VVAR" : "HVAR" )); + + *avalue = ADD_INT( *avalue, delta ); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_hadvance_adjust( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_vadvance_adjust( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 ); + } + + +#define GX_VALUE_SIZE 8 + + /* all values are FT_Short or FT_UShort entities; */ + /* we treat them consistently as FT_Short */ +#define GX_VALUE_CASE( tag, dflt ) \ + case MVAR_TAG_ ## tag : \ + p = (FT_Short*)&face->dflt; \ + break + +#define GX_GASP_CASE( idx ) \ + case MVAR_TAG_GASP_ ## idx : \ + if ( idx < face->gasp.numRanges - 1 ) \ + p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \ + else \ + p = NULL; \ + break + + + static FT_Short* + ft_var_get_value_pointer( TT_Face face, + FT_ULong mvar_tag ) + { + FT_Short* p; + + + switch ( mvar_tag ) + { + GX_GASP_CASE( 0 ); + GX_GASP_CASE( 1 ); + GX_GASP_CASE( 2 ); + GX_GASP_CASE( 3 ); + GX_GASP_CASE( 4 ); + GX_GASP_CASE( 5 ); + GX_GASP_CASE( 6 ); + GX_GASP_CASE( 7 ); + GX_GASP_CASE( 8 ); + GX_GASP_CASE( 9 ); + + GX_VALUE_CASE( CPHT, os2.sCapHeight ); + GX_VALUE_CASE( HASC, os2.sTypoAscender ); + GX_VALUE_CASE( HCLA, os2.usWinAscent ); + GX_VALUE_CASE( HCLD, os2.usWinDescent ); + GX_VALUE_CASE( HCOF, horizontal.caret_Offset ); + GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run ); + GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise ); + GX_VALUE_CASE( HDSC, os2.sTypoDescender ); + GX_VALUE_CASE( HLGP, os2.sTypoLineGap ); + GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset); + GX_VALUE_CASE( SBXS, os2.ySubscriptXSize ); + GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset ); + GX_VALUE_CASE( SBYS, os2.ySubscriptYSize ); + GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset ); + GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize ); + GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset ); + GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize ); + GX_VALUE_CASE( STRO, os2.yStrikeoutPosition ); + GX_VALUE_CASE( STRS, os2.yStrikeoutSize ); + GX_VALUE_CASE( UNDO, postscript.underlinePosition ); + GX_VALUE_CASE( UNDS, postscript.underlineThickness ); + GX_VALUE_CASE( VASC, vertical.Ascender ); + GX_VALUE_CASE( VCOF, vertical.caret_Offset ); + GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run ); + GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise ); + GX_VALUE_CASE( VDSC, vertical.Descender ); + GX_VALUE_CASE( VLGP, vertical.Line_Gap ); + GX_VALUE_CASE( XHGT, os2.sxHeight ); + + default: + /* ignore unknown tag */ + p = NULL; + } + + return p; + } + + + /************************************************************************** + * + * @Function: + * ft_var_load_mvar + * + * @Description: + * Parse the `MVAR' table. + * + * Some memory may remain allocated on error; it is always freed in + * `tt_done_blend', however. + * + * @InOut: + * face :: + * The font face. + */ + static void + ft_var_load_mvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + GX_ItemVarStore itemStore; + GX_Value value, limit; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_UShort store_offset; + FT_ULong records_offset; + + + FT_TRACE2(( "MVAR " )); + + error = face->goto_table( face, TTAG_MVAR, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + return; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + return; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + return; + } + + if ( FT_NEW( blend->mvar_table ) ) + return; + + /* skip reserved entry and value record size */ + if ( FT_STREAM_SKIP( 4 ) || + FT_READ_USHORT( blend->mvar_table->valueCount ) || + FT_READ_USHORT( store_offset ) ) + return; + + records_offset = FT_STREAM_POS(); + + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &blend->mvar_table->itemStore ); + if ( error ) + return; + + if ( FT_NEW_ARRAY( blend->mvar_table->values, + blend->mvar_table->valueCount ) ) + return; + + if ( FT_STREAM_SEEK( records_offset ) || + FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) ) + return; + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + itemStore = &blend->mvar_table->itemStore; + + for ( ; value < limit; value++ ) + { + value->tag = FT_GET_ULONG(); + value->outerIndex = FT_GET_USHORT(); + value->innerIndex = FT_GET_USHORT(); + + /* new in OpenType 1.8.4 */ + if ( value->outerIndex == 0xFFFFU && value->innerIndex == 0xFFFFU ) + { + /* no variation data for this item */ + continue; + } + + if ( value->outerIndex >= itemStore->dataCount || + value->innerIndex >= itemStore->varData[value->outerIndex] + .itemCount ) + { + error = FT_THROW( Invalid_Table ); + break; + } + } + + FT_FRAME_EXIT(); + + if ( error ) + return; + + FT_TRACE2(( "loaded\n" )); + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + + /* save original values of the data MVAR is going to modify */ + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( face, value->tag ); + + + if ( p ) + value->unmodified = *p; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE1(( "ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ) )); +#endif + } + + face->variation_support |= TT_FACE_FLAG_VAR_MVAR; + } + + + static FT_Error + ft_size_reset_iterator( FT_ListNode node, + void* user ) + { + FT_Size size = (FT_Size)node->data; + FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user; + + + var->size_reset( size ); + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_apply_mvar + * + * @Description: + * Apply `MVAR' table adjustments. + * + * @InOut: + * face :: + * The font face. + */ + FT_LOCAL_DEF( void ) + tt_apply_mvar( FT_Face face ) /* TT_Face */ + { + TT_Face ttface = (TT_Face)face; + + GX_Blend blend = ttface->blend; + GX_Value value, limit; + + FT_Short mvar_hasc_delta = 0; + FT_Short mvar_hdsc_delta = 0; + FT_Short mvar_hlgp_delta = 0; + + + if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) + return; + + value = blend->mvar_table->values; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); + + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( ttface, value->tag ); + FT_Int delta; + + + delta = tt_var_get_item_delta( face, + &blend->mvar_table->itemStore, + value->outerIndex, + value->innerIndex ); + + if ( p && delta ) + { + FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ), + value->unmodified, + value->unmodified == 1 ? "" : "s", + delta, + delta == 1 ? "" : "s" )); + + /* since we handle both signed and unsigned values as FT_Short, */ + /* ensure proper overflow arithmetic */ + *p = (FT_Short)( value->unmodified + (FT_Short)delta ); + + /* Treat hasc, hdsc and hlgp specially, see below. */ + if ( value->tag == MVAR_TAG_HASC ) + mvar_hasc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HDSC ) + mvar_hdsc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HLGP ) + mvar_hlgp_delta = (FT_Short)delta; + } + } + + /* adjust all derived values */ + { + FT_Service_MetricsVariations var = + (FT_Service_MetricsVariations)ttface->face_var; + + /* + * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender, + * descender and height attributes, no matter how they were originally + * computed. + * + * (Code that ignores those and accesses the font's metrics values + * directly is already served by the delta application code above.) + * + * The MVAR table supports variations for both typo and win metrics. + * According to Behdad Esfahbod, the thinking of the working group was + * that no one uses win metrics anymore for setting line metrics (the + * specification even calls these metrics "horizontal clipping + * ascent/descent", probably for their role on the Windows platform in + * computing clipping boxes), and new fonts should use typo metrics, so + * typo deltas should be applied to whatever sfnt_load_face decided the + * line metrics should be. + * + * Before, the following led to different line metrics between default + * outline and instances, visible when e.g. the default outlines were + * used as the regular face and instances for everything else: + * + * 1. sfnt_load_face applied the hhea metrics by default. + * 2. This code later applied the typo metrics by default, regardless of + * whether they were actually changed or the font had the OS/2 table's + * fsSelection's bit 7 (USE_TYPO_METRICS) set. + */ + FT_Short current_line_gap = face->height - face->ascender + + face->descender; + + + face->ascender = face->ascender + mvar_hasc_delta; + face->descender = face->descender + mvar_hdsc_delta; + face->height = face->ascender - face->descender + + current_line_gap + mvar_hlgp_delta; + + face->underline_position = ttface->postscript.underlinePosition - + ttface->postscript.underlineThickness / 2; + face->underline_thickness = ttface->postscript.underlineThickness; + + /* iterate over all FT_Size objects and call `var->size_reset' */ + /* to propagate the metrics changes */ + if ( var && var->size_reset ) + FT_List_Iterate( &face->sizes_list, + ft_size_reset_iterator, + (void*)var ); + } + } + + + typedef struct GX_GVar_Head_ + { + FT_Long version; + FT_UShort axisCount; + FT_UShort globalCoordCount; + FT_ULong offsetToCoord; + FT_UShort glyphCount; + FT_UShort flags; + FT_ULong offsetToData; + + } GX_GVar_Head; + + + /************************************************************************** + * + * @Function: + * ft_var_load_gvar + * + * @Description: + * Parse the `gvar' table if present. If `fvar' is there, `gvar' had + * better be there too. + * + * @InOut: + * face :: + * The font face. + * + * @Return: + * FreeType error code. 0 means success. + */ + static FT_Error + ft_var_load_gvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Error error; + FT_UInt i, j; + FT_ULong table_len; + FT_ULong gvar_start; + FT_ULong offsetToData; + FT_ULong offsets_len; + GX_GVar_Head gvar_head; + + static const FT_Frame_Field gvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_GVar_Head + + FT_FRAME_START( 20 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( globalCoordCount ), + FT_FRAME_ULONG ( offsetToCoord ), + FT_FRAME_USHORT( glyphCount ), + FT_FRAME_USHORT( flags ), + FT_FRAME_ULONG ( offsetToData ), + FT_FRAME_END + }; + + + FT_TRACE2(( "GVAR " )); + + if ( FT_SET_ERROR( face->goto_table( face, + TTAG_gvar, + stream, + &table_len ) ) ) + { + FT_TRACE2(( "is missing\n" )); + goto Exit; + } + + gvar_start = FT_STREAM_POS( ); + if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) + goto Exit; + + if ( gvar_head.version != 0x00010000L ) + { + FT_TRACE1(( "bad table version\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) + { + FT_TRACE1(( "ft_var_load_gvar:" + " number of axes in `gvar' and `cvar'\n" )); + FT_TRACE1(( " table are different\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* rough sanity check, ignoring offsets */ + if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount > + table_len / 2 ) + { + FT_TRACE1(( "ft_var_load_gvar:" + " invalid number of global coordinates\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* offsets can be either 2 or 4 bytes */ + /* (one more offset than glyphs, to mark size of last) */ + offsets_len = ( gvar_head.glyphCount + 1 ) * + ( ( gvar_head.flags & 1 ) ? 4L : 2L ); + + /* rough sanity check */ + if (offsets_len > table_len ) + { + FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + + blend->gvar_size = table_len; + offsetToData = gvar_start + gvar_head.offsetToData; + + FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n", + gvar_head.globalCoordCount == 1 ? "is" : "are", + gvar_head.globalCoordCount, + gvar_head.globalCoordCount == 1 ? "" : "s" )); + + if ( FT_FRAME_ENTER( offsets_len ) ) + goto Exit; + + /* offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) + goto Fail2; + + if ( gvar_head.flags & 1 ) + { + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; + + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d not monotonic\n", + i )); + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d out of range\n", + i )); + blend->glyphoffsets[i] = limit; + } + } + } + else + { + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; + + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d not monotonic\n", + i )); + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %d out of range\n", + i )); + blend->glyphoffsets[i] = limit; + } + } + } + + blend->gv_glyphcnt = gvar_head.glyphCount; + + FT_FRAME_EXIT(); + + if ( gvar_head.globalCoordCount != 0 ) + { + if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || + FT_FRAME_ENTER( gvar_head.globalCoordCount * + gvar_head.axisCount * 2L ) ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation shared tuples missing\n" )); + goto Fail; + } + + if ( FT_QNEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * gvar_head.globalCoordCount ) ) + goto Fail2; + + for ( i = 0; i < gvar_head.globalCoordCount; i++ ) + { + FT_TRACE5(( " [ " )); + for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) + { + blend->tuplecoords[i * gvar_head.axisCount + j] = + FT_fdot14ToFixed( FT_GET_SHORT() ); + FT_TRACE5(( "%.5f ", + (double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 )); + } + FT_TRACE5(( "]\n" )); + } + + blend->tuplecount = gvar_head.globalCoordCount; + + FT_TRACE5(( "\n" )); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + + Fail2: + FT_FRAME_EXIT(); + + Fail: + FT_FREE( blend->glyphoffsets ); + blend->gv_glyphcnt = 0; + goto Exit; + } + + + /************************************************************************** + * + * @Function: + * ft_var_apply_tuple + * + * @Description: + * Figure out whether a given tuple (design) applies to the current + * blend, and if so, what is the scaling factor. + * + * @Input: + * blend :: + * The current blend of the font. + * + * tupleIndex :: + * A flag saying whether this is an intermediate + * tuple or not. + * + * tuple_coords :: + * The coordinates of the tuple in normalized axis + * units. + * + * im_start_coords :: + * The initial coordinates where this tuple starts + * to apply (for intermediate coordinates). + * + * im_end_coords :: + * The final coordinates after which this tuple no + * longer applies (for intermediate coordinates). + * + * @Return: + * An FT_Fixed value containing the scaling factor. + */ + static FT_Fixed + ft_var_apply_tuple( GX_Blend blend, + FT_UShort tupleIndex, + FT_Fixed* tuple_coords, + FT_Fixed* im_start_coords, + FT_Fixed* im_end_coords ) + { + FT_UInt i; + FT_Fixed apply = 0x10000L; + + + for ( i = 0; i < blend->num_axis; i++ ) + { + FT_Fixed ncv = blend->normalizedcoords[i]; + + + FT_TRACE6(( " axis %d coordinate %.5f:\n", i, (double)ncv / 65536 )); + + /* It's not clear why (for intermediate tuples) we don't need */ + /* to check against start/end -- the documentation says we don't. */ + /* Similarly, it's unclear why we don't need to scale along the */ + /* axis. */ + + if ( tuple_coords[i] == ncv ) + { + FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n", + (double)tuple_coords[i] / 65536 )); + /* `apply' does not change */ + continue; + } + + if ( tuple_coords[i] == 0 ) + { + FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); + continue; + } + + if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) + { + /* not an intermediate tuple */ + + if ( ( tuple_coords[i] > ncv && ncv > 0 ) || + ( tuple_coords[i] < ncv && ncv < 0 ) ) + { + FT_TRACE6(( " tuple coordinate %.5f fits\n", + (double)tuple_coords[i] / 65536 )); + apply = FT_MulDiv( apply, ncv, tuple_coords[i] ); + } + else + { + FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n", + (double)tuple_coords[i] / 65536 )); + apply = 0; + break; + } + } + else + { + /* intermediate tuple */ + + if ( ncv <= im_start_coords[i] || + ncv >= im_end_coords[i] ) + { + FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ is exceeded," + " stop\n", + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); + apply = 0; + break; + } + + FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n", + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); + if ( ncv < tuple_coords[i] ) + apply = FT_MulDiv( apply, + ncv - im_start_coords[i], + tuple_coords[i] - im_start_coords[i] ); + else /* ncv > tuple_coords[i] */ + apply = FT_MulDiv( apply, + im_end_coords[i] - ncv, + im_end_coords[i] - tuple_coords[i] ); + } + } + + FT_TRACE6(( " apply factor is %.5f\n", (double)apply / 65536 )); + + return apply; + } + + + /* convert from design coordinates to normalized coordinates */ + + static void + ft_var_to_normalized( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* normalized ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = face->root.memory; + FT_UInt i, j; + + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + GX_AVarSegment av; + + FT_Fixed* new_normalized = NULL; + FT_Fixed* old_normalized; + + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_to_normalized:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + /* Axis normalization is a two-stage process. First we normalize */ + /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ + /* Then, if there's an `avar' table, we renormalize this range. */ + + a = mmvar->axis; + for ( i = 0; i < num_coords; i++, a++ ) + { + FT_Fixed coord = coords[i]; + + + FT_TRACE5(( " %d: %.5f\n", i, (double)coord / 65536 )); + if ( coord > a->maximum || coord < a->minimum ) + { + FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n", + (double)coord / 65536 )); + FT_TRACE1(( " is out of range [%.5f;%.5f];" + " clamping\n", + (double)a->minimum / 65536, + (double)a->maximum / 65536 )); + } + + if ( coord > a->def ) + normalized[i] = coord >= a->maximum ? 0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->maximum, a->def ) ); + else if ( coord < a->def ) + normalized[i] = coord <= a->minimum ? -0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->def, a->minimum ) ); + else + normalized[i] = 0; + } + + FT_TRACE5(( "\n" )); + + for ( ; i < mmvar->num_axis; i++ ) + normalized[i] = 0; + + if ( blend->avar_table ) + { + GX_AVarTable table = blend->avar_table; + + + FT_TRACE5(( "normalized design coordinates" + " before applying `avar' data:\n" )); + + if ( table->avar_segment ) + { + av = table->avar_segment; + + for ( i = 0; i < mmvar->num_axis; i++, av++ ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( normalized[i] < av->correspondence[j].fromCoord ) + { + FT_TRACE5(( " %.5f\n", (double)normalized[i] / 65536 )); + + normalized[i] = + FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ) + + av->correspondence[j - 1].toCoord; + break; + } + } + } + } + + if ( table->itemStore.varData ) + { + if ( FT_QNEW_ARRAY( new_normalized, mmvar->num_axis ) ) + return; + + /* Install our half-normalized coordinates for the next */ + /* Item Variation Store to work with. */ + old_normalized = face->blend->normalizedcoords; + face->blend->normalizedcoords = normalized; + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + FT_Fixed v = normalized[i]; + FT_UInt innerIndex = i; + FT_UInt outerIndex = 0; + FT_Int delta; + + + if ( table->axisMap.innerIndex ) + { + FT_UInt idx = i; + + + if ( idx >= table->axisMap.mapCount ) + idx = table->axisMap.mapCount - 1; + + outerIndex = table->axisMap.outerIndex[idx]; + innerIndex = table->axisMap.innerIndex[idx]; + } + + delta = tt_var_get_item_delta( FT_FACE( face ), + &table->itemStore, + outerIndex, + innerIndex ); + + /* Convert delta in F2DOT14 to 16.16 before adding. */ + v += MUL_INT( delta, 4 ); + + /* Clamp value to range [-1, 1]. */ + v = v >= 0x10000L ? 0x10000 : v; + v = v <= -0x10000L ? -0x10000 : v; + + new_normalized[i] = v; + } + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + normalized[i] = new_normalized[i]; + } + + face->blend->normalizedcoords = old_normalized; + + FT_FREE( new_normalized ); + } + } + } + + + /* convert from normalized coordinates to design coordinates */ + + static void + ft_var_to_design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* design ) + { + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + + FT_UInt i, j, nc; + + + blend = face->blend; + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "ft_var_to_design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + design[i] = coords[i]; + + for ( ; i < num_coords; i++ ) + design[i] = 0; + + if ( blend->avar_table && blend->avar_table->avar_segment ) + { + GX_AVarSegment av = blend->avar_table->avar_segment; + + + FT_TRACE5(( "design coordinates" + " after removing `avar' distortion:\n" )); + + for ( i = 0; i < nc; i++, av++ ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( design[i] < av->correspondence[j].toCoord ) + { + design[i] = + FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord ) + + av->correspondence[j - 1].fromCoord; + + FT_TRACE5(( " %.5f\n", (double)design[i] / 65536 )); + break; + } + } + } + } + + mmvar = blend->mmvar; + a = mmvar->axis; + + for ( i = 0; i < nc; i++, a++ ) + { + if ( design[i] < 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->def - a->minimum ); + else if ( design[i] > 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->maximum - a->def ); + else + design[i] = a->def; + } + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + typedef struct GX_FVar_Head_ + { + FT_Long version; + FT_UShort offsetToData; + FT_UShort axisCount; + FT_UShort axisSize; + FT_UShort instanceCount; + FT_UShort instanceSize; + + } GX_FVar_Head; + + + typedef struct fvar_axis_ + { + FT_ULong axisTag; + FT_Fixed minValue; + FT_Fixed defaultValue; + FT_Fixed maxValue; + FT_UShort flags; + FT_UShort nameID; + + } GX_FVar_Axis; + + + /************************************************************************** + * + * @Function: + * TT_Get_MM_Var + * + * @Description: + * Check that the font's `fvar' table is valid, parse it, and return + * those data. It also loads (and parses) the `MVAR' table, if + * possible. + * + * @InOut: + * face :: + * The font face. + * TT_Get_MM_Var initializes the blend structure. + * + * @Output: + * master :: + * The `fvar' data (must be freed by caller). Can be NULL, + * which makes this function simply load MM support. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Var( FT_Face face, /* TT_Face */ + FT_MM_Var* *master ) + { + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_ULong table_len; + FT_Error error = FT_Err_Ok; + FT_ULong fvar_start = 0; + FT_UInt i, j; + FT_MM_Var* mmvar = NULL; + FT_Fixed* next_coords; + FT_Fixed* nsc; + FT_String* next_name; + FT_Var_Axis* a; + FT_Fixed* c; + FT_Var_Named_Style* ns; + GX_FVar_Head fvar_head = { 0, 0, 0, 0, 0, 0 }; + FT_Bool usePsName = 0; + FT_UInt num_instances; + FT_UInt num_axes; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; + FT_Offset namedstyle_size; + FT_Offset next_coords_size; + FT_Offset next_name_size; + + FT_Bool need_init; + + static const FT_Frame_Field fvar_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Head + + FT_FRAME_START( 16 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT ( offsetToData ), + FT_FRAME_SKIP_SHORT, + FT_FRAME_USHORT ( axisCount ), + FT_FRAME_USHORT ( axisSize ), + FT_FRAME_USHORT ( instanceCount ), + FT_FRAME_USHORT ( instanceSize ), + FT_FRAME_END + }; + + static const FT_Frame_Field fvaraxis_fields[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Axis + + FT_FRAME_START( 20 ), + FT_FRAME_ULONG ( axisTag ), + FT_FRAME_LONG ( minValue ), + FT_FRAME_LONG ( defaultValue ), + FT_FRAME_LONG ( maxValue ), + FT_FRAME_USHORT( flags ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_END + }; + + /* `num_instances` holds the number of all named instances including */ + /* the default instance, which might be missing in the table of named */ + /* instances (in 'fvar'). This value is validated in `sfobjs.c` and */ + /* may be reset to 0 if consistency checks fail. */ + num_instances = (FT_UInt)face->style_flags >> 16; + + /* read the font data and set up the internal representation */ + /* if not already done */ + + need_init = !ttface->blend; + + if ( need_init ) + { + FT_TRACE2(( "FVAR " )); + + if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar, + stream, &table_len ) ) ) + { + FT_TRACE1(( "is missing\n" )); + goto Exit; + } + + fvar_start = FT_STREAM_POS( ); + + /* the validity of the `fvar' header data was already checked */ + /* in function `sfnt_init_face' */ + if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) + goto Exit; + + /* If `num_instances` is larger, synthetization of the default */ + /* instance is required. If `num_instances` is smaller, */ + /* however, the value has been reset to 0 in `sfnt_init_face` */ + /* (in `sfobjs.c`); in this case we have underallocated `mmvar` */ + /* structs. */ + if ( num_instances < fvar_head.instanceCount ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + usePsName = FT_BOOL( fvar_head.instanceSize == + 6 + 4 * fvar_head.axisCount ); + + FT_TRACE2(( "loaded\n" )); + + FT_TRACE5(( "%d variation ax%s\n", + fvar_head.axisCount, + fvar_head.axisCount == 1 ? "is" : "es" )); + + if ( FT_NEW( ttface->blend ) ) + goto Exit; + + num_axes = fvar_head.axisCount; + ttface->blend->num_axis = num_axes; + } + else + num_axes = ttface->blend->num_axis; + + /* prepare storage area for MM data; this cannot overflow */ + /* 32-bit arithmetic because of the size limits used in the */ + /* `fvar' table validity check in `sfnt_init_face' */ + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmvar' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( num_axes * + sizeof ( FT_UShort ) ); + axis_size = ALIGN_SIZE( num_axes * + sizeof ( FT_Var_Axis ) ); + namedstyle_size = ALIGN_SIZE( num_instances * + sizeof ( FT_Var_Named_Style ) ); + next_coords_size = ALIGN_SIZE( num_instances * + num_axes * + sizeof ( FT_Fixed ) ); + next_name_size = num_axes * 5; + + if ( need_init ) + { + ttface->blend->mmvar_len = mmvar_size + + axis_flags_size + + axis_size + + namedstyle_size + + next_coords_size + + next_name_size; + + if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) ) + goto Exit; + ttface->blend->mmvar = mmvar; + + /* set up pointers and offsets into the `mmvar' array; */ + /* the data gets filled in later on */ + + mmvar->num_axis = + num_axes; + mmvar->num_designs = + ~0U; /* meaningless in this context; each glyph */ + /* may have a different number of designs */ + /* (or tuples, as called by Apple) */ + mmvar->num_namedstyles = + num_instances; + + /* alas, no public field in `FT_Var_Axis' for axis flags */ + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); + mmvar->axis = + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = + (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size ); + + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); + for ( i = 0; i < num_instances; i++ ) + { + mmvar->namedstyle[i].coords = next_coords; + next_coords += num_axes; + } + + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( i = 0; i < num_axes; i++ ) + { + mmvar->axis[i].name = next_name; + next_name += 5; + } + + /* now fill in the data */ + + if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) + goto Exit; + + a = mmvar->axis; + for ( i = 0; i < num_axes; i++ ) + { + GX_FVar_Axis axis_rec; + +#ifdef FT_DEBUG_LEVEL_TRACE + int invalid = 0; +#endif + + + if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) + goto Exit; + a->tag = axis_rec.axisTag; + a->minimum = axis_rec.minValue; + a->def = axis_rec.defaultValue; + a->maximum = axis_rec.maxValue; + a->strid = axis_rec.nameID; + + a->name[0] = (FT_String)( a->tag >> 24 ); + a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); + a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); + a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); + a->name[4] = '\0'; + + *axis_flags = axis_rec.flags; + + if ( a->minimum > a->def || + a->def > a->maximum ) + { + a->minimum = a->def; + a->maximum = a->def; + +#ifdef FT_DEBUG_LEVEL_TRACE + invalid = 1; +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( i == 0 ) + FT_TRACE5(( " idx tag " + /* " XXX `XXXX'" */ + " minimum default maximum flags\n" )); + /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */ + + FT_TRACE5(( " %3d `%s'" + " %10.5f %10.5f %10.5f 0x%04X%s\n", + i, + a->name, + (double)a->minimum / 65536, + (double)a->def / 65536, + (double)a->maximum / 65536, + *axis_flags, + invalid ? " (invalid, disabled)" : "" )); +#endif + + a++; + axis_flags++; + } + + FT_TRACE5(( "\n" )); + + /* named instance coordinates are stored as design coordinates; */ + /* we have to convert them to normalized coordinates also */ + if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords, + num_axes * num_instances ) ) + goto Exit; + + if ( fvar_head.instanceCount && !ttface->blend->avar_loaded ) + { + FT_ULong offset = FT_STREAM_POS(); + + + ft_var_load_avar( ttface ); + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + } + + FT_TRACE5(( "%d named instance%s\n", + fvar_head.instanceCount, + fvar_head.instanceCount == 1 ? "" : "s" )); + + ns = mmvar->namedstyle; + nsc = ttface->blend->normalized_stylecoords; + for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) + { + /* PostScript names add 2 bytes to the instance record size */ + if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) + + 4L * num_axes ) ) + goto Exit; + + ns->strid = FT_GET_USHORT(); + (void) /* flags = */ FT_GET_USHORT(); + + c = ns->coords; + for ( j = 0; j < num_axes; j++, c++ ) + *c = FT_GET_LONG(); + + /* valid psid values are 6, [256;32767], and 0xFFFF */ + if ( usePsName ) + ns->psid = FT_GET_USHORT(); + else + ns->psid = 0xFFFF; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_String* strname = NULL; + FT_String* psname = NULL; + + FT_ULong pos; + + + pos = FT_STREAM_POS(); + + if ( ns->strid != 0xFFFF ) + { + (void)sfnt->get_name( ttface, + (FT_UShort)ns->strid, + &strname ); + if ( strname && !ft_strcmp( strname, ".notdef" ) ) + strname = NULL; + } + + if ( ns->psid != 0xFFFF ) + { + (void)sfnt->get_name( ttface, + (FT_UShort)ns->psid, + &psname ); + if ( psname && !ft_strcmp( psname, ".notdef" ) ) + psname = NULL; + } + + (void)FT_STREAM_SEEK( pos ); + + FT_TRACE5(( " named instance %d (%s%s%s, %s%s%s)\n", + i, + strname ? "name: `" : "", + strname ? strname : "unnamed", + strname ? "'" : "", + psname ? "PS name: `" : "", + psname ? psname : "no PS name", + psname ? "'" : "" )); + + FT_FREE( strname ); + FT_FREE( psname ); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + ft_var_to_normalized( ttface, num_axes, ns->coords, nsc ); + nsc += num_axes; + + FT_FRAME_EXIT(); + } + + if ( num_instances != fvar_head.instanceCount ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_Int found, dummy1, dummy2; + FT_UInt strid = ~0U; + + + /* The default instance is missing in array the */ + /* of named instances; try to synthesize an entry. */ + /* If this fails, `default_named_instance` remains */ + /* at value zero, which doesn't do any harm. */ + found = sfnt->get_name_id( ttface, + TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY; + else + { + found = sfnt->get_name_id( ttface, + TT_NAME_ID_FONT_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_FONT_SUBFAMILY; + } + + if ( found ) + { + found = sfnt->get_name_id( ttface, + TT_NAME_ID_PS_NAME, + &dummy1, + &dummy2 ); + if ( found ) + { + FT_TRACE5(( "TT_Get_MM_Var:" + " Adding default instance to named instances\n" )); + + /* named instance indices start with value 1 */ + ttface->var_default_named_instance = num_instances; + + ns = &mmvar->namedstyle[fvar_head.instanceCount]; + + ns->strid = strid; + ns->psid = TT_NAME_ID_PS_NAME; + + a = mmvar->axis; + c = ns->coords; + for ( j = 0; j < num_axes; j++, a++, c++ ) + *c = a->def; + } + } + } + + ft_var_load_mvar( ttface ); + } + + /* fill the output array if requested */ + + if ( master ) + { + FT_UInt n; + + + if ( FT_DUP( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ) ) + goto Exit; + + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); + mmvar->axis = + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = + (FT_Var_Named_Style*)( (char*)mmvar->axis+ axis_size ); + + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); + for ( n = 0; n < mmvar->num_namedstyles; n++ ) + { + mmvar->namedstyle[n].coords = next_coords; + next_coords += num_axes; + } + + a = mmvar->axis; + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( n = 0; n < num_axes; n++ ) + { + a->name = next_name; + + /* standard PostScript names for some standard apple tags */ + if ( a->tag == TTAG_wght ) + a->name = (char*)"Weight"; + else if ( a->tag == TTAG_wdth ) + a->name = (char*)"Width"; + else if ( a->tag == TTAG_opsz ) + a->name = (char*)"OpticalSize"; + else if ( a->tag == TTAG_slnt ) + a->name = (char*)"Slant"; + else if ( a->tag == TTAG_ital ) + a->name = (char*)"Italic"; + + next_name += 5; + a++; + } + + *master = mmvar; + } + + Exit: + return error; + } + + + static FT_Error + tt_set_mm_blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Bool set_design_coords ) + { + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + + FT_Bool all_design_coords = FALSE; + + FT_Memory memory = face->root.memory; + + enum + { + mcvt_retain, + mcvt_modify, + mcvt_load + + } manageCvt; + + + face->doblend = FALSE; + + if ( !face->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) ) + goto Exit; + } + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "TT_Set_MM_Blend:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + FT_TRACE5(( "TT_Set_MM_Blend:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); + + for ( i = 0; i < num_coords; i++ ) + { + FT_TRACE5(( " %.5f\n", (double)coords[i] / 65536 )); + if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) + { + FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n", + (double)coords[i] / 65536 )); + FT_TRACE1(( " is out of range [-1;1]\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + FT_TRACE5(( "\n" )); + + if ( !face->is_cff2 && !blend->glyphoffsets ) + { + /* While a missing 'gvar' table is acceptable, for example for */ + /* fonts that only vary metrics information or 'COLR' v1 */ + /* `PaintVar*` tables, an incorrect SFNT table offset or size */ + /* for 'gvar', or an inconsistent 'gvar' table is not. */ + error = ft_var_load_gvar( face ); + if ( error != FT_Err_Table_Missing && error != FT_Err_Ok ) + goto Exit; + error = FT_Err_Ok; + } + + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + + /* the first time we have to compute all design coordinates */ + all_design_coords = TRUE; + } + + if ( !blend->normalizedcoords ) + { + if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) + goto Exit; + + manageCvt = mcvt_modify; + + /* If we have not set the blend coordinates before this, then the */ + /* cvt table will still be what we read from the `cvt ' table and */ + /* we don't need to reload it. We may need to change it though... */ + } + else + { + FT_Bool have_diff = 0; + FT_UInt j; + FT_Fixed* c; + FT_Fixed* n; + + + manageCvt = mcvt_retain; + + for ( i = 0; i < num_coords; i++ ) + { + if ( blend->normalizedcoords[i] != coords[i] ) + { + manageCvt = mcvt_load; + have_diff = 1; + break; + } + } + + if ( !have_diff ) + { + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + { + FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16; + + + c = blend->normalizedcoords + i; + n = blend->normalized_stylecoords + + ( instance_index - 1 ) * mmvar->num_axis + + i; + + for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) + if ( *c != *n ) + have_diff = 1; + } + else + { + c = blend->normalizedcoords + i; + for ( j = i; j < mmvar->num_axis; j++, c++ ) + if ( *c != 0 ) + have_diff = 1; + } + } + + /* return value -1 indicates `no change' */ + if ( !have_diff ) + { + face->doblend = TRUE; + + return -1; + } + + for ( ; i < mmvar->num_axis; i++ ) + { + if ( blend->normalizedcoords[i] != 0 ) + { + manageCvt = mcvt_load; + break; + } + } + + /* If we don't change the blend coords then we don't need to do */ + /* anything to the cvt table. It will be correct. Otherwise we */ + /* no longer have the original cvt (it was modified when we set */ + /* the blend last time), so we must reload and then modify it. */ + } + + blend->num_axis = mmvar->num_axis; + if ( coords ) + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); + + if ( set_design_coords ) + ft_var_to_design( face, + all_design_coords ? blend->num_axis : num_coords, + blend->normalizedcoords, + blend->coords ); + + face->doblend = TRUE; + + if ( face->cvt ) + { + switch ( manageCvt ) + { + case mcvt_load: + /* The cvt table has been loaded already; every time we change the */ + /* blend we may need to reload and remodify the cvt table. */ + FT_FREE( face->cvt ); + + error = tt_face_load_cvt( face, face->root.stream ); + break; + + case mcvt_modify: + /* The original cvt table is in memory. All we need to do is */ + /* apply the `cvar' table (if any). */ + error = tt_face_vary_cvt( face, face->root.stream ); + break; + + case mcvt_retain: + /* The cvt table is correct for this set of coordinates. */ + break; + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_MM_Blend + * + * @Description: + * Set the blend (normalized) coordinates for this instance of the + * font. Check that the `gvar' table is reasonable and does some + * initial preparation. + * + * @InOut: + * face :: + * The font. + * Initialize the blend structure with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, ignore the excess + * values. If it is smaller than the number of axes, + * use the default value (0) for the remaining axes. + * + * coords :: + * An array of `num_coords', each between [-1,1]. + * + * @Return: + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_MM_Blend( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 ); + } + + + /************************************************************************** + * + * @Function: + * TT_Get_MM_Blend + * + * @Description: + * Get the blend (normalized) coordinates for this instance of the + * font. + * + * @InOut: + * face :: + * The font. + * Initialize the blend structure with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, set the excess + * values to 0. + * + * coords :: + * An array of `num_coords', each between [-1,1]. + * + * @Return: + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Blend( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = ttface->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_MM_Blend:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( ttface->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->normalizedcoords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_Var_Design + * + * @Description: + * Set the coordinates for the instance, measured in the user + * coordinate system. Parse the `avar' table (if present) to convert + * from user to normalized coordinates. + * + * @InOut: + * face :: + * The font face. + * Initialize the blend struct with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, ignore the excess + * values. If it is smaller than the number of axes, + * use the default values for the remaining axes. + * + * coords :: + * A coordinate array with `num_coords' elements. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Var_Design( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_Fixed* c; + FT_Fixed* n; + FT_Fixed* normalized = NULL; + + FT_Bool have_diff = 0; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + blend = ttface->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "TT_Set_Var_Design:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + } + + c = blend->coords; + n = coords; + for ( i = 0; i < num_coords; i++, n++, c++ ) + { + if ( *c != *n ) + { + *c = *n; + have_diff = 1; + } + } + + if ( FT_IS_NAMED_INSTANCE( face ) ) + { + FT_UInt instance_index; + FT_Var_Named_Style* named_style; + + + instance_index = (FT_UInt)face->face_index >> 16; + named_style = mmvar->namedstyle + instance_index - 1; + + n = named_style->coords + num_coords; + for ( ; i < mmvar->num_axis; i++, n++, c++ ) + { + if ( *c != *n ) + { + *c = *n; + have_diff = 1; + } + } + } + else + { + FT_Var_Axis* a; + + + a = mmvar->axis + num_coords; + for ( ; i < mmvar->num_axis; i++, a++, c++ ) + { + if ( *c != a->def ) + { + *c = a->def; + have_diff = 1; + } + } + } + + /* return value -1 indicates `no change'; */ + /* we can exit early if `normalizedcoords' is already computed */ + if ( blend->normalizedcoords && !have_diff ) + return -1; + + if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) + goto Exit; + + if ( !ttface->blend->avar_loaded ) + ft_var_load_avar( ttface ); + + FT_TRACE5(( "TT_Set_Var_Design:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); + ft_var_to_normalized( ttface, num_coords, blend->coords, normalized ); + + error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 ); + if ( error ) + goto Exit; + + Exit: + FT_FREE( normalized ); + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Get_Var_Design + * + * @Description: + * Get the design coordinates of the currently selected interpolated + * font. + * + * @Input: + * face :: + * A handle to the source face. + * + * num_coords :: + * The number of design coordinates to retrieve. If it + * is larger than the number of axes, set the excess + * values to~0. + * + * @Output: + * coords :: + * The design coordinates array. + * + * @Return: + * FreeType error code. 0~means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Var_Design( FT_Face face, /* TT_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = ttface->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_Var_Design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( ttface->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->coords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_Named_Instance + * + * @Description: + * Set the given named instance, also resetting any further + * variation. + * + * @Input: + * face :: + * A handle to the source face. + * + * instance_index :: + * The instance index, starting with value 1. + * Value 0 indicates to not use an instance. + * + * @Return: + * FreeType error code. 0~means success, -1 means success and unchanged + * axis values. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Named_Instance( FT_Face face, /* TT_Face */ + FT_UInt instance_index ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error; + GX_Blend blend; + FT_MM_Var* mmvar; + + FT_Memory memory = FT_FACE_MEMORY( face ); + + FT_UInt num_instances; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + blend = ttface->blend; + mmvar = blend->mmvar; + + num_instances = (FT_UInt)face->style_flags >> 16; + + /* `instance_index' starts with value 1, thus `>' */ + if ( instance_index > num_instances ) + { + error = FT_ERR( Invalid_Argument ); + goto Exit; + } + + if ( instance_index > 0 ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + + FT_Var_Named_Style* named_style; + FT_String* style_name; + + + named_style = mmvar->namedstyle + instance_index - 1; + + error = sfnt->get_name( ttface, + (FT_UShort)named_style->strid, + &style_name ); + if ( error ) + goto Exit; + + /* set (or replace) style name */ + FT_FREE( face->style_name ); + face->style_name = style_name; + + /* finally, select the named instance */ + error = TT_Set_Var_Design( face, + mmvar->num_axis, + named_style->coords ); + } + else + { + /* restore non-VF style name */ + FT_FREE( face->style_name ); + if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) ) + goto Exit; + error = TT_Set_Var_Design( face, 0, NULL ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * TT_Get_Default_Named_Instance + * + * @Description: + * Get the default named instance. + * + * @Input: + * face :: + * A handle to the source face. + * + * @Output: + * instance_index :: + * The default named instance index. + * + * @Return: + * FreeType error code. 0~means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + *instance_index = ttface->var_default_named_instance; + + Exit: + return error; + } + + + /* This function triggers (lazy) recomputation of the `postscript_name` */ + /* field in `TT_Face`. */ + + FT_LOCAL_DEF( void ) + tt_construct_ps_name( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( ttface->postscript_name ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GX VAR PARSING ROUTINES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + static FT_Error + tt_cvt_ready_iterator( FT_ListNode node, + void* user ) + { + TT_Size size = (TT_Size)node->data; + + FT_UNUSED( user ); + + + size->cvt_ready = -1; + + return FT_Err_Ok; + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + + + /************************************************************************** + * + * @Function: + * tt_face_vary_cvt + * + * @Description: + * Modify the loaded cvt table according to the `cvar' table and the + * font's blend. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + * + * Most errors are ignored. It is perfectly valid not to have a + * `cvar' table even if there is a `gvar' and `fvar' table. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + FT_Error error; + FT_Memory memory = stream->memory; + + FT_Face root = &face->root; + + FT_ULong table_start; + FT_ULong table_len; + + FT_UInt tupleCount; + FT_ULong offsetToData; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + + FT_Fixed* deltas = NULL; + FT_Fixed* cvt_deltas = NULL; + + + FT_TRACE2(( "CVAR " )); + + if ( !blend ) + { + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); + + return FT_Err_Ok; + } + + if ( !face->cvt ) + { + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); + + return FT_Err_Ok; + } + + error = face->goto_table( face, TTAG_cvar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + + return FT_Err_Ok; + } + + if ( FT_FRAME_ENTER( table_len ) ) + return FT_Err_Ok; + + table_start = FT_Stream_FTell( stream ); + if ( FT_GET_LONG() != 0x00010000L ) + { + FT_TRACE2(( "bad table version\n" )); + + error = FT_Err_Ok; + goto FExit; + } + + FT_TRACE2(( "loaded\n" )); + + tupleCount = FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > + table_len ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid CVT variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + + offsetToData += table_start; + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "cvar: there %s %d tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || + FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) + goto Exit; + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + FT_TRACE6(( " tuple %d:\n", i )); + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; j++ ) + peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + tuple_coords = peak_coords; + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + else + { + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid tuple index\n" )); + + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; j++ ) + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + for ( j = 0; j < blend->num_axis; j++ ) + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + + if ( apply == 0 ) /* tuple isn't active for our blend */ + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + localpoints = ft_var_readpackedpoints( stream, &point_count ); + points = localpoints; + } + else + { + localpoints = NULL; + points = sharedpoints; + point_count = spoint_count; + } + + deltas = ft_var_readpackeddeltas( stream, + point_count == 0 ? face->cvt_size + : point_count ); + + if ( !points || !deltas ) + ; /* failure, ignore it */ + + else if ( localpoints == ALL_POINTS ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " CVT deltas:\n" )); + + /* this means that there are deltas for every entry in cvt */ + for ( j = 0; j < face->cvt_size; j++ ) + { + FT_Fixed old_cvt_delta; + + + old_cvt_delta = cvt_deltas[j]; + cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( old_cvt_delta != cvt_deltas[j] ) + { + FT_TRACE7(( " %d: %f -> %f\n", + j, + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + cvt_deltas[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + else + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " CVT deltas:\n" )); + + for ( j = 0; j < point_count; j++ ) + { + int pindex; + FT_Fixed old_cvt_delta; + + + pindex = points[j]; + if ( (FT_ULong)pindex >= face->cvt_size ) + continue; + + old_cvt_delta = cvt_deltas[pindex]; + cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply ); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( old_cvt_delta != cvt_deltas[pindex] ) + { + FT_TRACE7(( " %d: %f -> %f\n", + pindex, + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + cvt_deltas[pindex] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "\n" )); + + for ( i = 0; i < face->cvt_size; i++ ) + face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] ); + + /* Iterate over all `FT_Size` objects and set `cvt_ready` to -1 */ + /* to trigger rescaling of all CVT values. */ + FT_List_Iterate( &root->sizes_list, + tt_cvt_ready_iterator, + NULL ); + + Exit: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); + FT_FREE( cvt_deltas ); + FT_FREE( peak_coords ); + + FExit: + FT_FRAME_EXIT(); + + return error; + +#else /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + } + + + /* Shift the original coordinates of all points between indices `p1' */ + /* and `p2', using the same difference as given by index `ref'. */ + + /* modeled after `af_iup_shift' */ + + static void + tt_delta_shift( int p1, + int p2, + int ref, + FT_Vector* in_points, + FT_Vector* out_points ) + { + int p; + FT_Vector delta; + + + delta.x = out_points[ref].x - in_points[ref].x; + delta.y = out_points[ref].y - in_points[ref].y; + + if ( delta.x == 0 && delta.y == 0 ) + return; + + for ( p = p1; p < ref; p++ ) + { + out_points[p].x += delta.x; + out_points[p].y += delta.y; + } + + for ( p = ref + 1; p <= p2; p++ ) + { + out_points[p].x += delta.x; + out_points[p].y += delta.y; + } + } + + + /* Interpolate the original coordinates of all points with indices */ + /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ + /* point indices. */ + + /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ + /* `Ins_IUP' with spec differences in handling ill-defined cases. */ + static void + tt_delta_interpolate( int p1, + int p2, + int ref1, + int ref2, + FT_Vector* in_points, + FT_Vector* out_points ) + { + int p, i; + + FT_Pos out, in1, in2, out1, out2, d1, d2; + + + if ( p1 > p2 ) + return; + + /* handle both horizontal and vertical coordinates */ + for ( i = 0; i <= 1; i++ ) + { + /* shift array pointers so that we can access `foo.y' as `foo.x' */ + in_points = (FT_Vector*)( (FT_Pos*)in_points + i ); + out_points = (FT_Vector*)( (FT_Pos*)out_points + i ); + + if ( in_points[ref1].x > in_points[ref2].x ) + { + p = ref1; + ref1 = ref2; + ref2 = p; + } + + in1 = in_points[ref1].x; + in2 = in_points[ref2].x; + out1 = out_points[ref1].x; + out2 = out_points[ref2].x; + d1 = out1 - in1; + d2 = out2 - in2; + + /* If the reference points have the same coordinate but different */ + /* delta, inferred delta is zero. Otherwise interpolate. */ + if ( in1 != in2 || out1 == out2 ) + { + FT_Fixed scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 ) + : 0; + + + for ( p = p1; p <= p2; p++ ) + { + out = in_points[p].x; + + if ( out <= in1 ) + out += d1; + else if ( out >= in2 ) + out += d2; + else + out = out1 + FT_MulFix( out - in1, scale ); + + out_points[p].x = out; + } + } + } + } + + + /* Interpolate points without delta values, similar to */ + /* the `IUP' hinting instruction. */ + + /* modeled after `Ins_IUP */ + + static void + tt_interpolate_deltas( FT_Outline* outline, + FT_Vector* out_points, + FT_Vector* in_points, + FT_Bool* has_delta ) + { + FT_Int first_point; + FT_Int end_point; + + FT_Int first_delta; + FT_Int cur_delta; + + FT_Int point; + FT_Short contour; + + + /* ignore empty outlines */ + if ( !outline->n_contours ) + return; + + contour = 0; + point = 0; + + do + { + end_point = outline->contours[contour]; + first_point = point; + + /* search first point that has a delta */ + while ( point <= end_point && !has_delta[point] ) + point++; + + if ( point <= end_point ) + { + first_delta = point; + cur_delta = point; + + point++; + + while ( point <= end_point ) + { + /* search next point that has a delta */ + /* and interpolate intermediate points */ + if ( has_delta[point] ) + { + tt_delta_interpolate( cur_delta + 1, + point - 1, + cur_delta, + point, + in_points, + out_points ); + cur_delta = point; + } + + point++; + } + + /* shift contour if we only have a single delta */ + if ( cur_delta == first_delta ) + tt_delta_shift( first_point, + end_point, + cur_delta, + in_points, + out_points ); + else + { + /* otherwise handle remaining points */ + /* at the end and beginning of the contour */ + tt_delta_interpolate( cur_delta + 1, + end_point, + cur_delta, + first_delta, + in_points, + out_points ); + + if ( first_delta > 0 ) + tt_delta_interpolate( first_point, + first_delta - 1, + cur_delta, + first_delta, + in_points, + out_points ); + } + } + contour++; + + } while ( contour < outline->n_contours ); + } + + + /************************************************************************** + * + * @Function: + * TT_Vary_Apply_Glyph_Deltas + * + * @Description: + * Apply the appropriate deltas to the current glyph. + * + * @InOut: + * loader :: + * A handle to the loader object. + * + * outline :: + * The outline to change, with appended phantom points. + * + * @Output: + * unrounded :: + * An array with `n_points' elements that is filled with unrounded + * point coordinates (in 26.6 format). + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, + FT_Outline* outline, + FT_Vector* unrounded ) + { + FT_Error error; + TT_Face face = loader->face; + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + FT_UInt glyph_index = loader->glyph_index; + FT_UInt n_points = (FT_UInt)outline->n_points + 4; + + FT_Vector* points_org = NULL; /* coordinates in 16.16 format */ + FT_Vector* points_out = NULL; /* coordinates in 16.16 format */ + FT_Bool* has_delta = NULL; + + FT_ULong glyph_start; + + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong dataSize; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + + FT_Fixed* deltas_x = NULL; + FT_Fixed* deltas_y = NULL; + FT_Fixed* point_deltas_x = NULL; + FT_Fixed* point_deltas_y = NULL; + + + if ( !face->doblend || !blend ) + return FT_THROW( Invalid_Argument ); + + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x ); + unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y ); + } + + if ( glyph_index >= blend->gv_glyphcnt || + blend->glyphoffsets[glyph_index] == + blend->glyphoffsets[glyph_index + 1] ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " no variation data for glyph %d\n", glyph_index )); + return FT_Err_Ok; + } + + dataSize = blend->glyphoffsets[glyph_index + 1] - + blend->glyphoffsets[glyph_index]; + + if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || + FT_FRAME_ENTER( dataSize ) ) + return error; + + glyph_start = FT_Stream_FTell( stream ); + + /* each set of glyph variation data is formatted similarly to `cvar' */ + + tupleCount = FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData > dataSize || + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + + offsetToData += glyph_start; + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "gvar: there %s %d tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || + FT_NEW_ARRAY( point_deltas_x, 2 * n_points ) || + FT_QNEW_ARRAY( points_org, n_points ) || + FT_QNEW_ARRAY( points_out, n_points ) || + FT_QNEW_ARRAY( has_delta, n_points ) ) + goto Exit; + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; + point_deltas_y = point_deltas_x + n_points; + + for ( j = 0; j < n_points; j++ ) + { + points_org[j].x = FT_intToFixed( outline->points[j].x ); + points_org[j].y = FT_intToFixed( outline->points[j].y ); + } + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + + + FT_TRACE6(( " tuple %d:\n", i )); + + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; j++ ) + peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + tuple_coords = peak_coords; + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + else + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid tuple index\n" )); + + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; j++ ) + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + for ( j = 0; j < blend->num_axis; j++ ) + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + } + + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); + + if ( apply == 0 ) /* tuple isn't active for our blend */ + { + offsetToData += tupleDataSize; + continue; + } + + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + localpoints = ft_var_readpackedpoints( stream, &point_count ); + points = localpoints; + } + else + { + points = sharedpoints; + point_count = spoint_count; + } + + deltas_x = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + deltas_y = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + + if ( !points || !deltas_y || !deltas_x ) + ; /* failure, ignore it */ + + else if ( points == ALL_POINTS ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + FT_TRACE7(( " point deltas:\n" )); + + /* this means that there are deltas for every point in the glyph */ + for ( j = 0; j < n_points; j++ ) + { + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Fixed point_delta_x = FT_MulFix( deltas_x[j], apply ); + FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply ); + + + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( point_delta_x || point_delta_y ) + { + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + j, + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + else + { +#ifdef FT_DEBUG_LEVEL_TRACE + int count = 0; +#endif + + + /* we have to interpolate the missing deltas similar to the */ + /* IUP bytecode instruction */ + for ( j = 0; j < n_points; j++ ) + { + has_delta[j] = FALSE; + points_out[j] = points_org[j]; + } + + for ( j = 0; j < point_count; j++ ) + { + FT_UShort idx = points[j]; + + + if ( idx >= n_points ) + continue; + + has_delta[idx] = TRUE; + + points_out[idx].x += FT_MulFix( deltas_x[j], apply ); + points_out[idx].y += FT_MulFix( deltas_y[j], apply ); + } + + /* no need to handle phantom points here, */ + /* since solitary points can't be interpolated */ + tt_interpolate_deltas( outline, + points_out, + points_org, + has_delta ); + + FT_TRACE7(( " point deltas:\n" )); + + for ( j = 0; j < n_points; j++ ) + { + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Pos point_delta_x = points_out[j].x - points_org[j].x; + FT_Pos point_delta_y = points_out[j].y - points_org[j].y; + + + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( point_delta_x || point_delta_y ) + { + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + j, + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); + count++; + } +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !count ) + FT_TRACE7(( " none\n" )); +#endif + } + + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas_x ); + FT_FREE( deltas_y ); + + offsetToData += tupleDataSize; + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "\n" )); + + /* To avoid double adjustment of advance width or height, */ + /* do not move phantom points if there is HVAR or VVAR */ + /* support, respectively. */ + if ( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) + { + point_deltas_x[n_points - 4] = 0; + point_deltas_y[n_points - 4] = 0; + point_deltas_x[n_points - 3] = 0; + point_deltas_y[n_points - 3] = 0; + } + if ( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) + { + point_deltas_x[n_points - 2] = 0; + point_deltas_y[n_points - 2] = 0; + point_deltas_x[n_points - 1] = 0; + point_deltas_y[n_points - 1] = 0; + } + + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] ); + unrounded[i].y += FT_fixedToFdot6( point_deltas_y[i] ); + + outline->points[i].x += FT_fixedToInt( point_deltas_x[i] ); + outline->points[i].y += FT_fixedToInt( point_deltas_y[i] ); + } + + /* To avoid double adjustment of advance width or height, */ + /* adjust phantom points only if there is no HVAR or VVAR */ + /* support, respectively. */ + if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + { + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x - + unrounded[n_points - 4].x ) / 64; + } + if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + { + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].y - + unrounded[n_points - 2].y ) / 64; + } + + Exit: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); + FT_FREE( points_org ); + FT_FREE( points_out ); + FT_FREE( has_delta ); + FT_FREE( peak_coords ); + FT_FREE( point_deltas_x ); + + FExit: + FT_FRAME_EXIT(); + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_get_var_blend + * + * @Description: + * An extended internal version of `TT_Get_MM_Blend' that returns + * pointers instead of copying data, without any initialization of + * the MM machinery in case it isn't loaded yet. + */ + FT_LOCAL_DEF( FT_Error ) + tt_get_var_blend( FT_Face face, /* TT_Face */ + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->blend ) + { + if ( num_coords ) + *num_coords = ttface->blend->num_axis; + if ( coords ) + *coords = ttface->blend->coords; + if ( normalizedcoords ) + *normalizedcoords = ttface->blend->normalizedcoords; + if ( mm_var ) + *mm_var = ttface->blend->mmvar; + } + else + { + if ( num_coords ) + *num_coords = 0; + if ( coords ) + *coords = NULL; + if ( mm_var ) + *mm_var = NULL; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + tt_var_done_item_variation_store( FT_Face face, + GX_ItemVarStore itemStore ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UInt i; + + + if ( itemStore->varData ) + { + for ( i = 0; i < itemStore->dataCount; i++ ) + { + FT_FREE( itemStore->varData[i].regionIndices ); + FT_FREE( itemStore->varData[i].deltaSet ); + } + + FT_FREE( itemStore->varData ); + } + + if ( itemStore->varRegionList ) + { + for ( i = 0; i < itemStore->regionCount; i++ ) + FT_FREE( itemStore->varRegionList[i].axisList ); + + FT_FREE( itemStore->varRegionList ); + } + } + + + FT_LOCAL_DEF( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( deltaSetIdxMap->innerIndex ); + FT_FREE( deltaSetIdxMap->outerIndex ); + } + + + /************************************************************************** + * + * @Function: + * tt_done_blend + * + * @Description: + * Free the blend internal data structure. + */ + FT_LOCAL_DEF( void ) + tt_done_blend( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + GX_Blend blend = ttface->blend; + + + if ( blend ) + { + FT_UInt i, num_axes; + + + /* blend->num_axis might not be set up yet */ + num_axes = blend->mmvar->num_axis; + + FT_FREE( blend->coords ); + FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->normalized_stylecoords ); + FT_FREE( blend->mmvar ); + + if ( blend->avar_table ) + { + if ( blend->avar_table->avar_segment ) + { + for ( i = 0; i < num_axes; i++ ) + FT_FREE( blend->avar_table->avar_segment[i].correspondence ); + FT_FREE( blend->avar_table->avar_segment ); + } + + tt_var_done_item_variation_store( face, + &blend->avar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->avar_table->axisMap ); + + FT_FREE( blend->avar_table ); + } + + if ( blend->hvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->hvar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->hvar_table->widthMap ); + FT_FREE( blend->hvar_table ); + } + + if ( blend->vvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->vvar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->vvar_table->widthMap ); + FT_FREE( blend->vvar_table ); + } + + if ( blend->mvar_table ) + { + tt_var_done_item_variation_store( face, + &blend->mvar_table->itemStore ); + + FT_FREE( blend->mvar_table->values ); + FT_FREE( blend->mvar_table ); + } + + FT_FREE( blend->tuplecoords ); + FT_FREE( blend->glyphoffsets ); + FT_FREE( blend ); + } + } + +#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_gxvar_dummy_; + +#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttgxvar.h b/Dependencies/freetype/freetype/src/truetype/ttgxvar.h new file mode 100644 index 00000000..9326011e --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttgxvar.h @@ -0,0 +1,453 @@ +/**************************************************************************** + * + * ttgxvar.h + * + * TrueType GX Font Variation loader (specification) + * + * Copyright (C) 2004-2024 by + * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTGXVAR_H_ +#define TTGXVAR_H_ + + +#include +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /************************************************************************** + * + * @Struct: + * GX_AVarCorrespondenceRec + * + * @Description: + * A data structure representing `shortFracCorrespondence' in `avar' + * table according to the specifications from Apple. + */ + typedef struct GX_AVarCorrespondenceRec_ + { + FT_Fixed fromCoord; + FT_Fixed toCoord; + + } GX_AVarCorrespondenceRec_, *GX_AVarCorrespondence; + + + /************************************************************************** + * + * @Struct: + * GX_AVarRec + * + * @Description: + * Data from the segment field of `avar' table. + * There is one of these for each axis. + */ + typedef struct GX_AVarSegmentRec_ + { + FT_UShort pairCount; + GX_AVarCorrespondence correspondence; /* array with pairCount entries */ + + } GX_AVarSegmentRec, *GX_AVarSegment; + + + /************************************************************************** + * + * @Struct: + * GX_AVarTableRec + * + * @Description: + * Data from the `avar' table. + */ + typedef struct GX_AVarTableRec_ + { + GX_AVarSegment avar_segment; /* avar_segment[num_axis] */ + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec axisMap; /* Axis Mapping */ + + } GX_AVarTableRec, *GX_AVarTable; + + + /************************************************************************** + * + * @Struct: + * GX_HVVarTableRec + * + * @Description: + * Data from either the `HVAR' or `VVAR' table. + */ + typedef struct GX_HVVarTableRec_ + { + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec widthMap; /* Advance Width Mapping */ + +#if 0 + GX_DeltaSetIdxMapRec lsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec rsbMap; /* not implemented */ + + GX_DeltaSetIdxMapRec tsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec bsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec vorgMap; /* not implemented */ +#endif + + } GX_HVVarTableRec, *GX_HVVarTable; + + +#define MVAR_TAG_GASP_0 FT_MAKE_TAG( 'g', 's', 'p', '0' ) +#define MVAR_TAG_GASP_1 FT_MAKE_TAG( 'g', 's', 'p', '1' ) +#define MVAR_TAG_GASP_2 FT_MAKE_TAG( 'g', 's', 'p', '2' ) +#define MVAR_TAG_GASP_3 FT_MAKE_TAG( 'g', 's', 'p', '3' ) +#define MVAR_TAG_GASP_4 FT_MAKE_TAG( 'g', 's', 'p', '4' ) +#define MVAR_TAG_GASP_5 FT_MAKE_TAG( 'g', 's', 'p', '5' ) +#define MVAR_TAG_GASP_6 FT_MAKE_TAG( 'g', 's', 'p', '6' ) +#define MVAR_TAG_GASP_7 FT_MAKE_TAG( 'g', 's', 'p', '7' ) +#define MVAR_TAG_GASP_8 FT_MAKE_TAG( 'g', 's', 'p', '8' ) +#define MVAR_TAG_GASP_9 FT_MAKE_TAG( 'g', 's', 'p', '9' ) + +#define MVAR_TAG_CPHT FT_MAKE_TAG( 'c', 'p', 'h', 't' ) +#define MVAR_TAG_HASC FT_MAKE_TAG( 'h', 'a', 's', 'c' ) +#define MVAR_TAG_HCLA FT_MAKE_TAG( 'h', 'c', 'l', 'a' ) +#define MVAR_TAG_HCLD FT_MAKE_TAG( 'h', 'c', 'l', 'd' ) +#define MVAR_TAG_HCOF FT_MAKE_TAG( 'h', 'c', 'o', 'f' ) +#define MVAR_TAG_HCRN FT_MAKE_TAG( 'h', 'c', 'r', 'n' ) +#define MVAR_TAG_HCRS FT_MAKE_TAG( 'h', 'c', 'r', 's' ) +#define MVAR_TAG_HDSC FT_MAKE_TAG( 'h', 'd', 's', 'c' ) +#define MVAR_TAG_HLGP FT_MAKE_TAG( 'h', 'l', 'g', 'p' ) +#define MVAR_TAG_SBXO FT_MAKE_TAG( 's', 'b', 'x', 'o' ) +#define MVAR_TAG_SBXS FT_MAKE_TAG( 's', 'b', 'x', 's' ) +#define MVAR_TAG_SBYO FT_MAKE_TAG( 's', 'b', 'y', 'o' ) +#define MVAR_TAG_SBYS FT_MAKE_TAG( 's', 'b', 'y', 's' ) +#define MVAR_TAG_SPXO FT_MAKE_TAG( 's', 'p', 'x', 'o' ) +#define MVAR_TAG_SPXS FT_MAKE_TAG( 's', 'p', 'x', 's' ) +#define MVAR_TAG_SPYO FT_MAKE_TAG( 's', 'p', 'y', 'o' ) +#define MVAR_TAG_SPYS FT_MAKE_TAG( 's', 'p', 'y', 's' ) +#define MVAR_TAG_STRO FT_MAKE_TAG( 's', 't', 'r', 'o' ) +#define MVAR_TAG_STRS FT_MAKE_TAG( 's', 't', 'r', 's' ) +#define MVAR_TAG_UNDO FT_MAKE_TAG( 'u', 'n', 'd', 'o' ) +#define MVAR_TAG_UNDS FT_MAKE_TAG( 'u', 'n', 'd', 's' ) +#define MVAR_TAG_VASC FT_MAKE_TAG( 'v', 'a', 's', 'c' ) +#define MVAR_TAG_VCOF FT_MAKE_TAG( 'v', 'c', 'o', 'f' ) +#define MVAR_TAG_VCRN FT_MAKE_TAG( 'v', 'c', 'r', 'n' ) +#define MVAR_TAG_VCRS FT_MAKE_TAG( 'v', 'c', 'r', 's' ) +#define MVAR_TAG_VDSC FT_MAKE_TAG( 'v', 'd', 's', 'c' ) +#define MVAR_TAG_VLGP FT_MAKE_TAG( 'v', 'l', 'g', 'p' ) +#define MVAR_TAG_XHGT FT_MAKE_TAG( 'x', 'h', 'g', 't' ) + + + typedef struct GX_ValueRec_ + { + FT_ULong tag; + FT_UShort outerIndex; + FT_UShort innerIndex; + + FT_Short unmodified; /* values are either FT_Short or FT_UShort */ + + } GX_ValueRec, *GX_Value; + + + /************************************************************************** + * + * @Struct: + * GX_MVarTableRec + * + * @Description: + * Data from the `MVAR' table. + */ + typedef struct GX_MVarTableRec_ + { + FT_UShort valueCount; + + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_Value values; /* Value Records */ + + } GX_MVarTableRec, *GX_MVarTable; + + + /************************************************************************** + * + * @Struct: + * GX_BlendRec + * + * @Description: + * Data for interpolating a font from a distortable font specified + * by the GX *var tables ([fgcahvm]var). + * + * @Fields: + * num_axis :: + * The number of axes along which interpolation may happen. + * + * coords :: + * An array of design coordinates (in user space) indicating the + * contribution along each axis to the final interpolated font. + * `normalizedcoords' holds the same values. + * + * normalizedcoords :: + * An array of normalized values (between [-1,1]) indicating the + * contribution along each axis to the final interpolated font. + * `coords' holds the same values. + * + * mmvar :: + * Data from the `fvar' table. + * + * mmvar_len :: + * The length of the `mmvar' structure. + * + * normalized_stylecoords :: + * A two-dimensional array that holds the named instance data from + * `mmvar' as normalized values. + * + * avar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `avar' + * table. + * + * avar_table :: + * Data from the `avar' table. + * + * hvar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `hvar' + * table. + * + * hvar_checked :: + * A Boolean; if set, FreeType successfully loaded and parsed the + * `hvar' table. + * + * hvar_error :: + * If loading and parsing of the `hvar' table failed, this field + * holds the corresponding error code. + * + * hvar_table :: + * Data from the `hvar' table. + * + * vvar_loaded :: + * A Boolean; if set, FreeType tried to load (and parse) the `vvar' + * table. + * + * vvar_checked :: + * A Boolean; if set, FreeType successfully loaded and parsed the + * `vvar' table. + * + * vvar_error :: + * If loading and parsing of the `vvar' table failed, this field + * holds the corresponding error code. + * + * vvar_table :: + * Data from the `vvar' table. + * + * mvar_table :: + * Data from the `mvar' table. + * + * tuplecount :: + * The number of shared tuples in the `gvar' table. + * + * tuplecoords :: + * A two-dimensional array that holds the shared tuple coordinates + * in the `gvar' table. + * + * gv_glyphcnt :: + * The number of glyphs handled in the `gvar' table. + * + * glyphoffsets :: + * Offsets into the glyph variation data array. + * + * gvar_size :: + * The size of the `gvar' table. + */ + typedef struct GX_BlendRec_ + { + FT_UInt num_axis; + FT_Fixed* coords; + FT_Fixed* normalizedcoords; + + FT_MM_Var* mmvar; + FT_Offset mmvar_len; + + FT_Fixed* normalized_stylecoords; + /* normalized_stylecoords[num_namedstyles][num_axis] */ + + FT_Bool avar_loaded; + GX_AVarTable avar_table; + + FT_Bool hvar_loaded; + FT_Bool hvar_checked; + FT_Error hvar_error; + GX_HVVarTable hvar_table; + + FT_Bool vvar_loaded; + FT_Bool vvar_checked; + FT_Error vvar_error; + GX_HVVarTable vvar_table; + + GX_MVarTable mvar_table; + + FT_UInt tuplecount; + FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + + FT_UInt gv_glyphcnt; + FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ + + FT_ULong gvar_size; + + } GX_BlendRec; + + + /************************************************************************** + * + * @enum: + * GX_TupleCountFlags + * + * @Description: + * Flags used within the `TupleCount' field of the `gvar' table. + */ + typedef enum GX_TupleCountFlags_ + { + GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000, + GX_TC_RESERVED_TUPLE_FLAGS = 0x7000, + GX_TC_TUPLE_COUNT_MASK = 0x0FFF + + } GX_TupleCountFlags; + + + /************************************************************************** + * + * @enum: + * GX_TupleIndexFlags + * + * @Description: + * Flags used within the `TupleIndex' field of the `gvar' and `cvar' + * tables. + */ + typedef enum GX_TupleIndexFlags_ + { + GX_TI_EMBEDDED_TUPLE_COORD = 0x8000, + GX_TI_INTERMEDIATE_TUPLE = 0x4000, + GX_TI_PRIVATE_POINT_NUMBERS = 0x2000, + GX_TI_RESERVED_TUPLE_FLAG = 0x1000, + GX_TI_TUPLE_INDEX_MASK = 0x0FFF + + } GX_TupleIndexFlags; + + +#define TTAG_wght FT_MAKE_TAG( 'w', 'g', 'h', 't' ) +#define TTAG_wdth FT_MAKE_TAG( 'w', 'd', 't', 'h' ) +#define TTAG_opsz FT_MAKE_TAG( 'o', 'p', 's', 'z' ) +#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' ) +#define TTAG_ital FT_MAKE_TAG( 'i', 't', 'a', 'l' ) + + + FT_LOCAL( FT_Error ) + TT_Set_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Get_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Get_MM_Var( FT_Face face, + FT_MM_Var* *master ); + + FT_LOCAL( FT_Error ) + TT_Get_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Named_Instance( FT_Face face, + FT_UInt instance_index ); + + FT_LOCAL( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + + FT_LOCAL( void ) + tt_construct_ps_name( FT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, + FT_Outline* outline, + FT_Vector* unrounded ); + + FT_LOCAL( FT_Error ) + tt_hadvance_adjust( FT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( FT_Error ) + tt_vadvance_adjust( FT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( void ) + tt_apply_mvar( FT_Face face ); + + FT_LOCAL( FT_Error ) + tt_var_load_item_variation_store( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + FT_LOCAL( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + FT_LOCAL( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + FT_LOCAL( void ) + tt_var_done_item_variation_store( FT_Face face, + GX_ItemVarStore itemStore ); + + FT_LOCAL( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + + + FT_LOCAL( FT_Error ) + tt_get_var_blend( FT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); + + FT_LOCAL( void ) + tt_done_blend( FT_Face face ); + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + +FT_END_HEADER + + +#endif /* TTGXVAR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttinterp.c b/Dependencies/freetype/freetype/src/truetype/ttinterp.c new file mode 100644 index 00000000..951891db --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttinterp.c @@ -0,0 +1,7751 @@ +/**************************************************************************** + * + * ttinterp.c + * + * TrueType bytecode interpreter (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +/* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */ +/* issues; many thanks! */ + + +#include +#include +#include +#include +#include +#include + +#include "ttinterp.h" +#include "tterrors.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttinterp + + +#define NO_SUBPIXEL_HINTING \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_35 ) + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#define SUBPIXEL_HINTING_MINIMAL \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_40 ) +#endif + +#define PROJECT( v1, v2 ) \ + exc->func_project( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) + +#define DUALPROJ( v1, v2 ) \ + exc->func_dualproj( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) + +#define FAST_PROJECT( v ) \ + exc->func_project( exc, (v)->x, (v)->y ) + +#define FAST_DUALPROJ( v ) \ + exc->func_dualproj( exc, (v)->x, (v)->y ) + + + /************************************************************************** + * + * Two simple bounds-checking macros. + */ +#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) +#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) ) + + +#undef SUCCESS +#define SUCCESS 0 + +#undef FAILURE +#define FAILURE 1 + + + /************************************************************************** + * + * CODERANGE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * TT_Goto_CodeRange + * + * @Description: + * Switches to a new code range (updates the code related elements in + * `exec', and `IP'). + * + * @Input: + * range :: + * The new execution code range. + * + * IP :: + * The new IP in the new code range. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ) + { + TT_CodeRange* coderange; + + + FT_ASSERT( range >= 1 && range <= 3 ); + + coderange = &exec->codeRangeTable[range - 1]; + + FT_ASSERT( coderange->base ); + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for IP <= Size instead of IP < Size. */ + /* */ + FT_ASSERT( IP <= coderange->size ); + + exec->code = coderange->base; + exec->codeSize = coderange->size; + exec->IP = IP; + exec->curRange = range; + } + + + /************************************************************************** + * + * @Function: + * TT_Set_CodeRange + * + * @Description: + * Sets a code range. + * + * @Input: + * range :: + * The code range index. + * + * base :: + * The new code base. + * + * length :: + * The range size in bytes. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].size = length; + } + + + /************************************************************************** + * + * @Function: + * TT_Clear_CodeRange + * + * @Description: + * Clears a code range. + * + * @Input: + * range :: + * The code range index. + * + * @InOut: + * exec :: + * The target execution context. + */ + FT_LOCAL_DEF( void ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + + exec->codeRangeTable[range - 1].base = NULL; + exec->codeRangeTable[range - 1].size = 0; + } + + + /************************************************************************** + * + * EXECUTION CONTEXT ROUTINES + * + */ + + + /************************************************************************** + * + * @Function: + * TT_Done_Context + * + * @Description: + * Destroys a given context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * memory :: + * A handle to the parent memory object. + * + * @Note: + * Only the glyph loader and debugger should call this function. + */ + FT_LOCAL_DEF( void ) + TT_Done_Context( TT_ExecContext exec ) + { + FT_Memory memory = exec->memory; + + + /* points zone */ + exec->maxPoints = 0; + exec->maxContours = 0; + + /* free stack */ + FT_FREE( exec->stack ); + exec->stackSize = 0; + + /* free glyf cvt working area */ + FT_FREE( exec->glyfCvt ); + exec->glyfCvtSize = 0; + + /* free glyf storage working area */ + FT_FREE( exec->glyfStorage ); + exec->glyfStoreSize = 0; + + /* free call stack */ + FT_FREE( exec->callStack ); + exec->callSize = 0; + exec->callTop = 0; + + /* free glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->size = NULL; + exec->face = NULL; + + FT_FREE( exec ); + } + + + /************************************************************************** + * + * @Function: + * TT_Load_Context + * + * @Description: + * Prepare an execution context for glyph hinting. + * + * @Input: + * face :: + * A handle to the source face object. + * + * size :: + * A handle to the source size object. + * + * @InOut: + * exec :: + * A handle to the target execution context. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only the glyph loader and debugger should call this function. + * + * Note that not all members of `TT_ExecContext` get initialized. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ) + { + FT_Int i; + TT_MaxProfile* maxp; + FT_Error error; + FT_Memory memory = exec->memory; + + + exec->face = face; + maxp = &face->max_profile; + exec->size = size; + + if ( size ) + { + exec->numFDefs = size->num_function_defs; + exec->maxFDefs = size->max_function_defs; + exec->numIDefs = size->num_instruction_defs; + exec->maxIDefs = size->max_instruction_defs; + exec->FDefs = size->function_defs; + exec->IDefs = size->instruction_defs; + exec->pointSize = size->point_size; + exec->tt_metrics = size->ttmetrics; + exec->metrics = *size->metrics; + + exec->maxFunc = size->max_func; + exec->maxIns = size->max_ins; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + exec->codeRangeTable[i] = size->codeRangeTable[i]; + + /* set graphics state */ + exec->GS = size->GS; + + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + + exec->storeSize = size->storage_size; + exec->storage = size->storage; + + exec->twilight = size->twilight; + + /* In case of multi-threading it can happen that the old size object */ + /* no longer exists, thus we must clear all glyph zone references. */ + FT_ZERO( &exec->zp0 ); + exec->zp1 = exec->zp0; + exec->zp2 = exec->zp0; + } + + /* XXX: We reserve a little more elements on the stack to deal safely */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + if ( FT_QRENEW_ARRAY( exec->stack, + exec->stackSize, + maxp->maxStackElements + 32 ) ) + return error; + exec->stackSize = maxp->maxStackElements + 32; + + /* free previous glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; + + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + exec->zp0 = exec->pts; + + exec->instruction_trap = FALSE; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * TT_Save_Context + * + * @Description: + * Saves the code ranges in a `size' object. + * + * @Input: + * exec :: + * A handle to the source execution context. + * + * @InOut: + * size :: + * A handle to the target size object. + * + * @Note: + * Only the glyph loader and debugger should call this function. + */ + FT_LOCAL_DEF( void ) + TT_Save_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_Int i; + + + /* XXX: Will probably disappear soon with all the code range */ + /* management, which is now rather obsolete. */ + /* */ + size->num_function_defs = exec->numFDefs; + size->num_instruction_defs = exec->numIDefs; + + size->max_func = exec->maxFunc; + size->max_ins = exec->maxIns; + + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + size->codeRangeTable[i] = exec->codeRangeTable[i]; + } + + + /************************************************************************** + * + * @Function: + * TT_Run_Context + * + * @Description: + * Executes one or more instructions in the execution context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * TrueType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec ) + { + TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ); + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0000; + + exec->GS.freeVector = exec->GS.projVector; + exec->GS.dualVector = exec->GS.projVector; + + exec->GS.round_state = 1; + exec->GS.loop = 1; + + /* some glyphs leave something on the stack. so we clean it */ + /* before a new execution. */ + exec->top = 0; + exec->callTop = 0; + + return exec->face->interpreter( exec ); + } + + + /* The default value for `scan_control' is documented as FALSE in the */ + /* TrueType specification. This is confusing since it implies a */ + /* Boolean value. However, this is not the case, thus both the */ + /* default values of our `scan_type' and `scan_control' fields (which */ + /* the documentation's `scan_control' variable is split into) are */ + /* zero. */ + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, + { 0x4000, 0 }, + { 0x4000, 0 }, + { 0x4000, 0 }, + + 1, 64, 1, + TRUE, 68, 0, 0, 9, 3, + 0, FALSE, 0, 1, 1, 1 + }; + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( TT_ExecContext ) + TT_New_Context( TT_Driver driver ) + { + FT_Memory memory; + FT_Error error; + + TT_ExecContext exec = NULL; + + + if ( !driver ) + goto Fail; + + memory = driver->root.root.memory; + + /* allocate object and zero everything inside */ + if ( FT_NEW( exec ) ) + goto Fail; + + /* create callStack here, other allocations delayed */ + exec->memory = memory; + exec->callSize = 32; + + if ( FT_QNEW_ARRAY( exec->callStack, exec->callSize ) ) + FT_FREE( exec ); + + Fail: + return exec; + } + + + /************************************************************************** + * + * Before an opcode is executed, the interpreter verifies that there are + * enough arguments on the stack, with the help of the `Pop_Push_Count' + * table. + * + * For each opcode, the first column gives the number of arguments that + * are popped from the stack; the second one gives the number of those + * that are pushed in result. + * + * Opcodes which have a varying number of parameters in the data stream + * (NPUSHB, NPUSHW) are handled specially; they have a negative value in + * the `opcode_length' table, and the value in `Pop_Push_Count' is set + * to zero. + * + */ + + +#undef PACK +#define PACK( x, y ) ( ( x << 4 ) | y ) + + + static + const FT_Byte Pop_Push_Count[256] = + { + /* opcodes are gathered in groups of 16 */ + /* please keep the spaces as they are */ + + /* 0x00 */ + /* SVTCA[0] */ PACK( 0, 0 ), + /* SVTCA[1] */ PACK( 0, 0 ), + /* SPVTCA[0] */ PACK( 0, 0 ), + /* SPVTCA[1] */ PACK( 0, 0 ), + /* SFVTCA[0] */ PACK( 0, 0 ), + /* SFVTCA[1] */ PACK( 0, 0 ), + /* SPVTL[0] */ PACK( 2, 0 ), + /* SPVTL[1] */ PACK( 2, 0 ), + /* SFVTL[0] */ PACK( 2, 0 ), + /* SFVTL[1] */ PACK( 2, 0 ), + /* SPVFS */ PACK( 2, 0 ), + /* SFVFS */ PACK( 2, 0 ), + /* GPV */ PACK( 0, 2 ), + /* GFV */ PACK( 0, 2 ), + /* SFVTPV */ PACK( 0, 0 ), + /* ISECT */ PACK( 5, 0 ), + + /* 0x10 */ + /* SRP0 */ PACK( 1, 0 ), + /* SRP1 */ PACK( 1, 0 ), + /* SRP2 */ PACK( 1, 0 ), + /* SZP0 */ PACK( 1, 0 ), + /* SZP1 */ PACK( 1, 0 ), + /* SZP2 */ PACK( 1, 0 ), + /* SZPS */ PACK( 1, 0 ), + /* SLOOP */ PACK( 1, 0 ), + /* RTG */ PACK( 0, 0 ), + /* RTHG */ PACK( 0, 0 ), + /* SMD */ PACK( 1, 0 ), + /* ELSE */ PACK( 0, 0 ), + /* JMPR */ PACK( 1, 0 ), + /* SCVTCI */ PACK( 1, 0 ), + /* SSWCI */ PACK( 1, 0 ), + /* SSW */ PACK( 1, 0 ), + + /* 0x20 */ + /* DUP */ PACK( 1, 2 ), + /* POP */ PACK( 1, 0 ), + /* CLEAR */ PACK( 0, 0 ), + /* SWAP */ PACK( 2, 2 ), + /* DEPTH */ PACK( 0, 1 ), + /* CINDEX */ PACK( 1, 1 ), + /* MINDEX */ PACK( 1, 0 ), + /* ALIGNPTS */ PACK( 2, 0 ), + /* INS_$28 */ PACK( 0, 0 ), + /* UTP */ PACK( 1, 0 ), + /* LOOPCALL */ PACK( 2, 0 ), + /* CALL */ PACK( 1, 0 ), + /* FDEF */ PACK( 1, 0 ), + /* ENDF */ PACK( 0, 0 ), + /* MDAP[0] */ PACK( 1, 0 ), + /* MDAP[1] */ PACK( 1, 0 ), + + /* 0x30 */ + /* IUP[0] */ PACK( 0, 0 ), + /* IUP[1] */ PACK( 0, 0 ), + /* SHP[0] */ PACK( 0, 0 ), /* loops */ + /* SHP[1] */ PACK( 0, 0 ), /* loops */ + /* SHC[0] */ PACK( 1, 0 ), + /* SHC[1] */ PACK( 1, 0 ), + /* SHZ[0] */ PACK( 1, 0 ), + /* SHZ[1] */ PACK( 1, 0 ), + /* SHPIX */ PACK( 1, 0 ), /* loops */ + /* IP */ PACK( 0, 0 ), /* loops */ + /* MSIRP[0] */ PACK( 2, 0 ), + /* MSIRP[1] */ PACK( 2, 0 ), + /* ALIGNRP */ PACK( 0, 0 ), /* loops */ + /* RTDG */ PACK( 0, 0 ), + /* MIAP[0] */ PACK( 2, 0 ), + /* MIAP[1] */ PACK( 2, 0 ), + + /* 0x40 */ + /* NPUSHB */ PACK( 0, 0 ), + /* NPUSHW */ PACK( 0, 0 ), + /* WS */ PACK( 2, 0 ), + /* RS */ PACK( 1, 1 ), + /* WCVTP */ PACK( 2, 0 ), + /* RCVT */ PACK( 1, 1 ), + /* GC[0] */ PACK( 1, 1 ), + /* GC[1] */ PACK( 1, 1 ), + /* SCFS */ PACK( 2, 0 ), + /* MD[0] */ PACK( 2, 1 ), + /* MD[1] */ PACK( 2, 1 ), + /* MPPEM */ PACK( 0, 1 ), + /* MPS */ PACK( 0, 1 ), + /* FLIPON */ PACK( 0, 0 ), + /* FLIPOFF */ PACK( 0, 0 ), + /* DEBUG */ PACK( 1, 0 ), + + /* 0x50 */ + /* LT */ PACK( 2, 1 ), + /* LTEQ */ PACK( 2, 1 ), + /* GT */ PACK( 2, 1 ), + /* GTEQ */ PACK( 2, 1 ), + /* EQ */ PACK( 2, 1 ), + /* NEQ */ PACK( 2, 1 ), + /* ODD */ PACK( 1, 1 ), + /* EVEN */ PACK( 1, 1 ), + /* IF */ PACK( 1, 0 ), + /* EIF */ PACK( 0, 0 ), + /* AND */ PACK( 2, 1 ), + /* OR */ PACK( 2, 1 ), + /* NOT */ PACK( 1, 1 ), + /* DELTAP1 */ PACK( 1, 0 ), + /* SDB */ PACK( 1, 0 ), + /* SDS */ PACK( 1, 0 ), + + /* 0x60 */ + /* ADD */ PACK( 2, 1 ), + /* SUB */ PACK( 2, 1 ), + /* DIV */ PACK( 2, 1 ), + /* MUL */ PACK( 2, 1 ), + /* ABS */ PACK( 1, 1 ), + /* NEG */ PACK( 1, 1 ), + /* FLOOR */ PACK( 1, 1 ), + /* CEILING */ PACK( 1, 1 ), + /* ROUND[0] */ PACK( 1, 1 ), + /* ROUND[1] */ PACK( 1, 1 ), + /* ROUND[2] */ PACK( 1, 1 ), + /* ROUND[3] */ PACK( 1, 1 ), + /* NROUND[0] */ PACK( 1, 1 ), + /* NROUND[1] */ PACK( 1, 1 ), + /* NROUND[2] */ PACK( 1, 1 ), + /* NROUND[3] */ PACK( 1, 1 ), + + /* 0x70 */ + /* WCVTF */ PACK( 2, 0 ), + /* DELTAP2 */ PACK( 1, 0 ), + /* DELTAP3 */ PACK( 1, 0 ), + /* DELTAC1 */ PACK( 1, 0 ), + /* DELTAC2 */ PACK( 1, 0 ), + /* DELTAC3 */ PACK( 1, 0 ), + /* SROUND */ PACK( 1, 0 ), + /* S45ROUND */ PACK( 1, 0 ), + /* JROT */ PACK( 2, 0 ), + /* JROF */ PACK( 2, 0 ), + /* ROFF */ PACK( 0, 0 ), + /* INS_$7B */ PACK( 0, 0 ), + /* RUTG */ PACK( 0, 0 ), + /* RDTG */ PACK( 0, 0 ), + /* SANGW */ PACK( 1, 0 ), + /* AA */ PACK( 1, 0 ), + + /* 0x80 */ + /* FLIPPT */ PACK( 0, 0 ), /* loops */ + /* FLIPRGON */ PACK( 2, 0 ), + /* FLIPRGOFF */ PACK( 2, 0 ), + /* INS_$83 */ PACK( 0, 0 ), + /* INS_$84 */ PACK( 0, 0 ), + /* SCANCTRL */ PACK( 1, 0 ), + /* SDPVTL[0] */ PACK( 2, 0 ), + /* SDPVTL[1] */ PACK( 2, 0 ), + /* GETINFO */ PACK( 1, 1 ), + /* IDEF */ PACK( 1, 0 ), + /* ROLL */ PACK( 3, 3 ), + /* MAX */ PACK( 2, 1 ), + /* MIN */ PACK( 2, 1 ), + /* SCANTYPE */ PACK( 1, 0 ), + /* INSTCTRL */ PACK( 2, 0 ), + /* INS_$8F */ PACK( 0, 0 ), + + /* 0x90 */ + /* INS_$90 */ PACK( 0, 0 ), + /* GETVAR */ PACK( 0, 0 ), /* will be handled specially */ + /* GETDATA */ PACK( 0, 1 ), + /* INS_$93 */ PACK( 0, 0 ), + /* INS_$94 */ PACK( 0, 0 ), + /* INS_$95 */ PACK( 0, 0 ), + /* INS_$96 */ PACK( 0, 0 ), + /* INS_$97 */ PACK( 0, 0 ), + /* INS_$98 */ PACK( 0, 0 ), + /* INS_$99 */ PACK( 0, 0 ), + /* INS_$9A */ PACK( 0, 0 ), + /* INS_$9B */ PACK( 0, 0 ), + /* INS_$9C */ PACK( 0, 0 ), + /* INS_$9D */ PACK( 0, 0 ), + /* INS_$9E */ PACK( 0, 0 ), + /* INS_$9F */ PACK( 0, 0 ), + + /* 0xA0 */ + /* INS_$A0 */ PACK( 0, 0 ), + /* INS_$A1 */ PACK( 0, 0 ), + /* INS_$A2 */ PACK( 0, 0 ), + /* INS_$A3 */ PACK( 0, 0 ), + /* INS_$A4 */ PACK( 0, 0 ), + /* INS_$A5 */ PACK( 0, 0 ), + /* INS_$A6 */ PACK( 0, 0 ), + /* INS_$A7 */ PACK( 0, 0 ), + /* INS_$A8 */ PACK( 0, 0 ), + /* INS_$A9 */ PACK( 0, 0 ), + /* INS_$AA */ PACK( 0, 0 ), + /* INS_$AB */ PACK( 0, 0 ), + /* INS_$AC */ PACK( 0, 0 ), + /* INS_$AD */ PACK( 0, 0 ), + /* INS_$AE */ PACK( 0, 0 ), + /* INS_$AF */ PACK( 0, 0 ), + + /* 0xB0 */ + /* PUSHB[0] */ PACK( 0, 1 ), + /* PUSHB[1] */ PACK( 0, 2 ), + /* PUSHB[2] */ PACK( 0, 3 ), + /* PUSHB[3] */ PACK( 0, 4 ), + /* PUSHB[4] */ PACK( 0, 5 ), + /* PUSHB[5] */ PACK( 0, 6 ), + /* PUSHB[6] */ PACK( 0, 7 ), + /* PUSHB[7] */ PACK( 0, 8 ), + /* PUSHW[0] */ PACK( 0, 1 ), + /* PUSHW[1] */ PACK( 0, 2 ), + /* PUSHW[2] */ PACK( 0, 3 ), + /* PUSHW[3] */ PACK( 0, 4 ), + /* PUSHW[4] */ PACK( 0, 5 ), + /* PUSHW[5] */ PACK( 0, 6 ), + /* PUSHW[6] */ PACK( 0, 7 ), + /* PUSHW[7] */ PACK( 0, 8 ), + + /* 0xC0 */ + /* MDRP[00] */ PACK( 1, 0 ), + /* MDRP[01] */ PACK( 1, 0 ), + /* MDRP[02] */ PACK( 1, 0 ), + /* MDRP[03] */ PACK( 1, 0 ), + /* MDRP[04] */ PACK( 1, 0 ), + /* MDRP[05] */ PACK( 1, 0 ), + /* MDRP[06] */ PACK( 1, 0 ), + /* MDRP[07] */ PACK( 1, 0 ), + /* MDRP[08] */ PACK( 1, 0 ), + /* MDRP[09] */ PACK( 1, 0 ), + /* MDRP[10] */ PACK( 1, 0 ), + /* MDRP[11] */ PACK( 1, 0 ), + /* MDRP[12] */ PACK( 1, 0 ), + /* MDRP[13] */ PACK( 1, 0 ), + /* MDRP[14] */ PACK( 1, 0 ), + /* MDRP[15] */ PACK( 1, 0 ), + + /* 0xD0 */ + /* MDRP[16] */ PACK( 1, 0 ), + /* MDRP[17] */ PACK( 1, 0 ), + /* MDRP[18] */ PACK( 1, 0 ), + /* MDRP[19] */ PACK( 1, 0 ), + /* MDRP[20] */ PACK( 1, 0 ), + /* MDRP[21] */ PACK( 1, 0 ), + /* MDRP[22] */ PACK( 1, 0 ), + /* MDRP[23] */ PACK( 1, 0 ), + /* MDRP[24] */ PACK( 1, 0 ), + /* MDRP[25] */ PACK( 1, 0 ), + /* MDRP[26] */ PACK( 1, 0 ), + /* MDRP[27] */ PACK( 1, 0 ), + /* MDRP[28] */ PACK( 1, 0 ), + /* MDRP[29] */ PACK( 1, 0 ), + /* MDRP[30] */ PACK( 1, 0 ), + /* MDRP[31] */ PACK( 1, 0 ), + + /* 0xE0 */ + /* MIRP[00] */ PACK( 2, 0 ), + /* MIRP[01] */ PACK( 2, 0 ), + /* MIRP[02] */ PACK( 2, 0 ), + /* MIRP[03] */ PACK( 2, 0 ), + /* MIRP[04] */ PACK( 2, 0 ), + /* MIRP[05] */ PACK( 2, 0 ), + /* MIRP[06] */ PACK( 2, 0 ), + /* MIRP[07] */ PACK( 2, 0 ), + /* MIRP[08] */ PACK( 2, 0 ), + /* MIRP[09] */ PACK( 2, 0 ), + /* MIRP[10] */ PACK( 2, 0 ), + /* MIRP[11] */ PACK( 2, 0 ), + /* MIRP[12] */ PACK( 2, 0 ), + /* MIRP[13] */ PACK( 2, 0 ), + /* MIRP[14] */ PACK( 2, 0 ), + /* MIRP[15] */ PACK( 2, 0 ), + + /* 0xF0 */ + /* MIRP[16] */ PACK( 2, 0 ), + /* MIRP[17] */ PACK( 2, 0 ), + /* MIRP[18] */ PACK( 2, 0 ), + /* MIRP[19] */ PACK( 2, 0 ), + /* MIRP[20] */ PACK( 2, 0 ), + /* MIRP[21] */ PACK( 2, 0 ), + /* MIRP[22] */ PACK( 2, 0 ), + /* MIRP[23] */ PACK( 2, 0 ), + /* MIRP[24] */ PACK( 2, 0 ), + /* MIRP[25] */ PACK( 2, 0 ), + /* MIRP[26] */ PACK( 2, 0 ), + /* MIRP[27] */ PACK( 2, 0 ), + /* MIRP[28] */ PACK( 2, 0 ), + /* MIRP[29] */ PACK( 2, 0 ), + /* MIRP[30] */ PACK( 2, 0 ), + /* MIRP[31] */ PACK( 2, 0 ) + }; + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* the first hex digit gives the length of the opcode name; the space */ + /* after the digit is here just to increase readability of the source */ + /* code */ + + static + const char* const opcode_name[256] = + { + /* 0x00 */ + "8 SVTCA[y]", + "8 SVTCA[x]", + "9 SPVTCA[y]", + "9 SPVTCA[x]", + "9 SFVTCA[y]", + "9 SFVTCA[x]", + "9 SPVTL[||]", + "8 SPVTL[+]", + "9 SFVTL[||]", + "8 SFVTL[+]", + "5 SPVFS", + "5 SFVFS", + "3 GPV", + "3 GFV", + "6 SFVTPV", + "5 ISECT", + + /* 0x10 */ + "4 SRP0", + "4 SRP1", + "4 SRP2", + "4 SZP0", + "4 SZP1", + "4 SZP2", + "4 SZPS", + "5 SLOOP", + "3 RTG", + "4 RTHG", + "3 SMD", + "4 ELSE", + "4 JMPR", + "6 SCVTCI", + "5 SSWCI", + "3 SSW", + + /* 0x20 */ + "3 DUP", + "3 POP", + "5 CLEAR", + "4 SWAP", + "5 DEPTH", + "6 CINDEX", + "6 MINDEX", + "8 ALIGNPTS", + "7 INS_$28", + "3 UTP", + "8 LOOPCALL", + "4 CALL", + "4 FDEF", + "4 ENDF", + "6 MDAP[]", + "9 MDAP[rnd]", + + /* 0x30 */ + "6 IUP[y]", + "6 IUP[x]", + "8 SHP[rp2]", + "8 SHP[rp1]", + "8 SHC[rp2]", + "8 SHC[rp1]", + "8 SHZ[rp2]", + "8 SHZ[rp1]", + "5 SHPIX", + "2 IP", + "7 MSIRP[]", + "A MSIRP[rp0]", + "7 ALIGNRP", + "4 RTDG", + "6 MIAP[]", + "9 MIAP[rnd]", + + /* 0x40 */ + "6 NPUSHB", + "6 NPUSHW", + "2 WS", + "2 RS", + "5 WCVTP", + "4 RCVT", + "8 GC[curr]", + "8 GC[orig]", + "4 SCFS", + "8 MD[curr]", + "8 MD[orig]", + "5 MPPEM", + "3 MPS", + "6 FLIPON", + "7 FLIPOFF", + "5 DEBUG", + + /* 0x50 */ + "2 LT", + "4 LTEQ", + "2 GT", + "4 GTEQ", + "2 EQ", + "3 NEQ", + "3 ODD", + "4 EVEN", + "2 IF", + "3 EIF", + "3 AND", + "2 OR", + "3 NOT", + "7 DELTAP1", + "3 SDB", + "3 SDS", + + /* 0x60 */ + "3 ADD", + "3 SUB", + "3 DIV", + "3 MUL", + "3 ABS", + "3 NEG", + "5 FLOOR", + "7 CEILING", + "8 ROUND[G]", + "8 ROUND[B]", + "8 ROUND[W]", + "7 ROUND[]", + "9 NROUND[G]", + "9 NROUND[B]", + "9 NROUND[W]", + "8 NROUND[]", + + /* 0x70 */ + "5 WCVTF", + "7 DELTAP2", + "7 DELTAP3", + "7 DELTAC1", + "7 DELTAC2", + "7 DELTAC3", + "6 SROUND", + "8 S45ROUND", + "4 JROT", + "4 JROF", + "4 ROFF", + "7 INS_$7B", + "4 RUTG", + "4 RDTG", + "5 SANGW", + "2 AA", + + /* 0x80 */ + "6 FLIPPT", + "8 FLIPRGON", + "9 FLIPRGOFF", + "7 INS_$83", + "7 INS_$84", + "8 SCANCTRL", + "A SDPVTL[||]", + "9 SDPVTL[+]", + "7 GETINFO", + "4 IDEF", + "4 ROLL", + "3 MAX", + "3 MIN", + "8 SCANTYPE", + "8 INSTCTRL", + "7 INS_$8F", + + /* 0x90 */ + "7 INS_$90", +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + "C GETVARIATION", + "7 GETDATA", +#else + "7 INS_$91", + "7 INS_$92", +#endif + "7 INS_$93", + "7 INS_$94", + "7 INS_$95", + "7 INS_$96", + "7 INS_$97", + "7 INS_$98", + "7 INS_$99", + "7 INS_$9A", + "7 INS_$9B", + "7 INS_$9C", + "7 INS_$9D", + "7 INS_$9E", + "7 INS_$9F", + + /* 0xA0 */ + "7 INS_$A0", + "7 INS_$A1", + "7 INS_$A2", + "7 INS_$A3", + "7 INS_$A4", + "7 INS_$A5", + "7 INS_$A6", + "7 INS_$A7", + "7 INS_$A8", + "7 INS_$A9", + "7 INS_$AA", + "7 INS_$AB", + "7 INS_$AC", + "7 INS_$AD", + "7 INS_$AE", + "7 INS_$AF", + + /* 0xB0 */ + "8 PUSHB[0]", + "8 PUSHB[1]", + "8 PUSHB[2]", + "8 PUSHB[3]", + "8 PUSHB[4]", + "8 PUSHB[5]", + "8 PUSHB[6]", + "8 PUSHB[7]", + "8 PUSHW[0]", + "8 PUSHW[1]", + "8 PUSHW[2]", + "8 PUSHW[3]", + "8 PUSHW[4]", + "8 PUSHW[5]", + "8 PUSHW[6]", + "8 PUSHW[7]", + + /* 0xC0 */ + "7 MDRP[G]", + "7 MDRP[B]", + "7 MDRP[W]", + "6 MDRP[]", + "8 MDRP[rG]", + "8 MDRP[rB]", + "8 MDRP[rW]", + "7 MDRP[r]", + "8 MDRP[mG]", + "8 MDRP[mB]", + "8 MDRP[mW]", + "7 MDRP[m]", + "9 MDRP[mrG]", + "9 MDRP[mrB]", + "9 MDRP[mrW]", + "8 MDRP[mr]", + + /* 0xD0 */ + "8 MDRP[pG]", + "8 MDRP[pB]", + "8 MDRP[pW]", + "7 MDRP[p]", + "9 MDRP[prG]", + "9 MDRP[prB]", + "9 MDRP[prW]", + "8 MDRP[pr]", + "9 MDRP[pmG]", + "9 MDRP[pmB]", + "9 MDRP[pmW]", + "8 MDRP[pm]", + "A MDRP[pmrG]", + "A MDRP[pmrB]", + "A MDRP[pmrW]", + "9 MDRP[pmr]", + + /* 0xE0 */ + "7 MIRP[G]", + "7 MIRP[B]", + "7 MIRP[W]", + "6 MIRP[]", + "8 MIRP[rG]", + "8 MIRP[rB]", + "8 MIRP[rW]", + "7 MIRP[r]", + "8 MIRP[mG]", + "8 MIRP[mB]", + "8 MIRP[mW]", + "7 MIRP[m]", + "9 MIRP[mrG]", + "9 MIRP[mrB]", + "9 MIRP[mrW]", + "8 MIRP[mr]", + + /* 0xF0 */ + "8 MIRP[pG]", + "8 MIRP[pB]", + "8 MIRP[pW]", + "7 MIRP[p]", + "9 MIRP[prG]", + "9 MIRP[prB]", + "9 MIRP[prW]", + "8 MIRP[pr]", + "9 MIRP[pmG]", + "9 MIRP[pmB]", + "9 MIRP[pmW]", + "8 MIRP[pm]", + "A MIRP[pmrG]", + "A MIRP[pmrB]", + "A MIRP[pmrW]", + "9 MIRP[pmr]" + }; + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + static + const FT_Char opcode_length[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + +#undef PACK + + +#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER + +#if defined( __arm__ ) && \ + ( defined( __thumb2__ ) || !defined( __thumb__ ) ) + +#define TT_MulFix14 TT_MulFix14_arm + + static FT_Int32 + TT_MulFix14_arm( FT_Int32 a, + FT_Int b ) + { + FT_Int32 t, t2; + + +#if defined( __CC_ARM ) || defined( __ARMCC__ ) + + __asm + { + smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ + mov a, t, asr #31 /* a = (hi >> 31) */ + add a, a, #0x2000 /* a += 0x2000 */ + adds t2, t2, a /* t2 += a */ + adc t, t, #0 /* t += carry */ + mov a, t2, lsr #14 /* a = t2 >> 14 */ + orr a, a, t, lsl #18 /* a |= t << 18 */ + } + +#elif defined( __GNUC__ ) + + __asm__ __volatile__ ( + "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ + "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ +#if defined( __clang__ ) && defined( __thumb2__ ) + "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ +#else + "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ +#endif + "adds %1, %1, %0\n\t" /* %1 += %0 */ + "adc %2, %2, #0\n\t" /* %2 += carry */ + "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */ + "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */ + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + +#endif + + return a; + } + +#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */ + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + + +#if defined( __GNUC__ ) && \ + ( defined( __i386__ ) || defined( __x86_64__ ) ) + +#define TT_MulFix14 TT_MulFix14_long_long + + /* Temporarily disable the warning that C90 doesn't support `long long'. */ +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wlong-long" + + /* This is declared `noinline' because inlining the function results */ + /* in slower code. The `pure' attribute indicates that the result */ + /* only depends on the parameters. */ + static __attribute__(( noinline )) + __attribute__(( pure )) FT_Int32 + TT_MulFix14_long_long( FT_Int32 a, + FT_Int b ) + { + + long long ret = (long long)a * b; + + /* The following line assumes that right shifting of signed values */ + /* will actually preserve the sign bit. The exact behaviour is */ + /* undefined, but this is true on x86 and x86_64. */ + long long tmp = ret >> 63; + + + ret += 0x2000 + tmp; + + return (FT_Int32)( ret >> 14 ); + } + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic pop +#endif + +#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */ + + +#ifndef TT_MulFix14 + + /* Compute (a*b)/2^14 with maximum accuracy and rounding. */ + /* This is optimized to be faster than calling FT_MulFix() */ + /* for platforms where sizeof(int) == 2. */ + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 sign; + FT_UInt32 ah, al, mid, lo, hi; + + + sign = a ^ b; + + if ( a < 0 ) + a = -a; + if ( b < 0 ) + b = -b; + + ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); + al = (FT_UInt32)( a & 0xFFFFU ); + + lo = al * b; + mid = ah * b; + hi = mid >> 16; + mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */ + lo += mid; + if ( lo < mid ) + hi += 1; + + mid = ( lo >> 14 ) | ( hi << 18 ); + + return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; + } + +#endif /* !TT_MulFix14 */ + + +#if defined( __GNUC__ ) && \ + ( defined( __i386__ ) || \ + defined( __x86_64__ ) || \ + defined( __arm__ ) ) + +#define TT_DotFix14 TT_DotFix14_long_long + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wlong-long" + + static __attribute__(( pure )) FT_Int32 + TT_DotFix14_long_long( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + /* Temporarily disable the warning that C90 doesn't support */ + /* `long long'. */ + + long long temp1 = (long long)ax * bx; + long long temp2 = (long long)ay * by; + + + temp1 += temp2; + temp2 = temp1 >> 63; + temp1 += 0x2000 + temp2; + + return (FT_Int32)( temp1 >> 14 ); + + } + +#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 +#pragma GCC diagnostic pop +#endif + +#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */ + + +#ifndef TT_DotFix14 + + /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ + static FT_Int32 + TT_DotFix14( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + FT_Int32 m, s, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); + m = ( ax >> 16 ) * bx; + + lo1 = l + ( (FT_UInt32)m << 16 ); + hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l ); + + /* compute ay*by as 64-bit value */ + l = (FT_UInt32)( ( ay & 0xFFFFU ) * by ); + m = ( ay >> 16 ) * by; + + lo2 = l + ( (FT_UInt32)m << 16 ); + hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l ); + + /* add them */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); + + /* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + + l = lo + 0x2000U; + hi += ( l < lo ); + + return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); + } + +#endif /* TT_DotFix14 */ + + + /************************************************************************** + * + * @Function: + * Current_Ratio + * + * @Description: + * Returns the current aspect ratio scaling factor depending on the + * projection vector's state and device resolutions. + * + * @Return: + * The aspect ratio in 16.16 format, always <= 1.0 . + */ + static FT_Long + Current_Ratio( TT_ExecContext exc ) + { + if ( !exc->tt_metrics.ratio ) + { + if ( exc->GS.projVector.y == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.x_ratio; + + else if ( exc->GS.projVector.x == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.y_ratio; + + else + { + FT_F26Dot6 x, y; + + + x = TT_MulFix14( exc->tt_metrics.x_ratio, + exc->GS.projVector.x ); + y = TT_MulFix14( exc->tt_metrics.y_ratio, + exc->GS.projVector.y ); + exc->tt_metrics.ratio = FT_Hypot( x, y ); + } + } + return exc->tt_metrics.ratio; + } + + + FT_CALLBACK_DEF( FT_Long ) + Current_Ppem( TT_ExecContext exc ) + { + return exc->tt_metrics.ppem; + } + + + FT_CALLBACK_DEF( FT_Long ) + Current_Ppem_Stretched( TT_ExecContext exc ) + { + return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) ); + } + + + /************************************************************************** + * + * Functions related to the control value table (CVT). + * + */ + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT( TT_ExecContext exc, + FT_ULong idx ) + { + return exc->cvt[idx]; + } + + + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx ) + { + return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) ); + } + + + static void + Modify_CVT_Check( TT_ExecContext exc ) + { + if ( exc->iniRange == tt_coderange_glyph && + exc->cvt != exc->glyfCvt ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfCvtSize = exc->cvtSize; + FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize ); + exc->cvt = exc->glyfCvt; + } + } + + + FT_CALLBACK_DEF( void ) + Write_CVT( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = value; + } + + + FT_CALLBACK_DEF( void ) + Write_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) ); + } + + + FT_CALLBACK_DEF( void ) + Move_CVT( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value ); + } + + + FT_CALLBACK_DEF( void ) + Move_CVT_Stretched( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ) + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], + FT_DivFix( value, Current_Ratio( exc ) ) ); + } + + + /************************************************************************** + * + * @Function: + * GetShortIns + * + * @Description: + * Returns a short integer taken from the instruction stream at + * address IP. + * + * @Return: + * Short read at code[IP]. + * + * @Note: + * This one could become a macro. + */ + static FT_Short + GetShortIns( TT_ExecContext exc ) + { + /* Reading a byte stream so there is no endianness (DaveP) */ + exc->IP += 2; + return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) + + exc->code[exc->IP - 1] ); + } + + + /************************************************************************** + * + * @Function: + * Ins_Goto_CodeRange + * + * @Description: + * Goes to a certain code range in the instruction stream. + * + * @Input: + * aRange :: + * The index of the code range. + * + * aIP :: + * The new IP address in the code range. + * + * @Return: + * SUCCESS or FAILURE. + */ + static FT_Bool + Ins_Goto_CodeRange( TT_ExecContext exc, + FT_Int aRange, + FT_Long aIP ) + { + TT_CodeRange* range; + + + if ( aRange < 1 || aRange > 3 ) + { + exc->error = FT_THROW( Bad_Argument ); + return FAILURE; + } + + range = &exc->codeRangeTable[aRange - 1]; + + if ( !range->base ) /* invalid coderange */ + { + exc->error = FT_THROW( Invalid_CodeRange ); + return FAILURE; + } + + /* NOTE: Because the last instruction of a program may be a CALL */ + /* which will return to the first byte *after* the code */ + /* range, we test for aIP <= Size, instead of aIP < Size. */ + + if ( aIP > range->size ) + { + exc->error = FT_THROW( Code_Overflow ); + return FAILURE; + } + + exc->code = range->base; + exc->codeSize = range->size; + exc->IP = aIP; + exc->curRange = aRange; + + return SUCCESS; + } + + + /* + * + * Apple's TrueType specification at + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#order + * + * gives the following order of operations in instructions that move + * points. + * + * - check single width cut-in (MIRP, MDRP) + * + * - check control value cut-in (MIRP, MIAP) + * + * - apply engine compensation (MIRP, MDRP) + * + * - round distance (MIRP, MDRP) or value (MIAP, MDAP) + * + * - check minimum distance (MIRP,MDRP) + * + * - move point (MIRP, MDRP, MIAP, MSIRP, MDAP) + * + * For rounding instructions, engine compensation happens before rounding. + * + */ + + + /************************************************************************** + * + * @Function: + * Direct_Move + * + * @Description: + * Moves a point by a given distance along the freedom vector. The + * point will be `touched'. + * + * @Input: + * point :: + * The index of the point to move. + * + * distance :: + * The distance to apply. + * + * @InOut: + * zone :: + * The affected glyph zone. + * + * @Note: + * See `ttinterp.h' for details on backward compatibility mode. + * `Touches' the point. + */ + static void + Direct_Move( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + + v = exc->GS.freeVector.x; + + if ( v != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Exception to the post-IUP curfew: Allow the x component of */ + /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ + /* diagonal stems like on `Z' and `z' post-IUP. */ + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + v = exc->GS.freeVector.y; + + if ( v != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /************************************************************************** + * + * @Function: + * Direct_Move_Orig + * + * @Description: + * Moves the *original* position of a point by a given distance along + * the freedom vector. Obviously, the point will not be `touched'. + * + * @Input: + * point :: + * The index of the point to move. + * + * distance :: + * The distance to apply. + * + * @InOut: + * zone :: + * The affected glyph zone. + */ + static void + Direct_Move_Orig( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + + + v = exc->GS.freeVector.x; + + if ( v != 0 ) + zone->org[point].x = ADD_LONG( zone->org[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + + v = exc->GS.freeVector.y; + + if ( v != 0 ) + zone->org[point].y = ADD_LONG( zone->org[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + } + + + /************************************************************************** + * + * Special versions of Direct_Move() + * + * The following versions are used whenever both vectors are both + * along one of the coordinate unit vectors, i.e. in 90% of the cases. + * See `ttinterp.h' for details on backward compatibility mode. + * + */ + + + static void + Direct_Move_X( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + + static void + Direct_Move_Y( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + + + /************************************************************************** + * + * Special versions of Direct_Move_Orig() + * + * The following versions are used whenever both vectors are both + * along one of the coordinate unit vectors, i.e. in 90% of the cases. + * + */ + + + static void + Direct_Move_Orig_X( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + + zone->org[point].x = ADD_LONG( zone->org[point].x, distance ); + } + + + static void + Direct_Move_Orig_Y( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED( exc ); + + zone->org[point].y = ADD_LONG( zone->org[point].y, distance ); + } + + /************************************************************************** + * + * @Function: + * Round_None + * + * @Description: + * Does not round, but adds engine compensation. + * + * @Input: + * distance :: + * The distance (not) to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * The compensated distance. + */ + static FT_F26Dot6 + Round_None( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( distance, compensation ); + if ( val < 0 ) + val = 0; + } + else + { + val = SUB_LONG( distance, compensation ); + if ( val > 0 ) + val = 0; + } + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Grid + * + * @Description: + * Rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation, + distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Half_Grid + * + * @Description: + * Rounds value to half grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Half_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ), + 32 ); + if ( val < 0 ) + val = 32; + } + else + { + val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, + distance ) ), + 32 ) ); + if ( val > 0 ) + val = -32; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Down_To_Grid + * + * @Description: + * Rounds value down to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_Down_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Up_To_Grid + * + * @Description: + * Rounds value up to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_Up_To_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation, + distance ) ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_To_Double_Grid + * + * @Description: + * Rounds value to double grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + */ + static FT_F26Dot6 + Round_To_Double_Grid( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 ); + if ( val < 0 ) + val = 0; + } + else + { + val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ), + 32 ) ); + if ( val > 0 ) + val = 0; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Super + * + * @Description: + * Super-rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + * + * @Note: + * The TrueType specification says very little about the relationship + * between rounding and engine compensation. However, it seems from + * the description of super round that we should add the compensation + * before rounding. + */ + static FT_F26Dot6 + Round_Super( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) & + -exc->period; + val = ADD_LONG( val, exc->phase ); + if ( val < 0 ) + val = exc->phase; + } + else + { + val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) & + -exc->period ); + val = SUB_LONG( val, exc->phase ); + if ( val > 0 ) + val = -exc->phase; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Round_Super_45 + * + * @Description: + * Super-rounds value to grid after adding engine compensation. + * + * @Input: + * distance :: + * The distance to round. + * + * color :: + * The engine compensation color. + * + * @Return: + * Rounded distance. + * + * @Note: + * There is a separate function for Round_Super_45() as we may need + * greater precision. + */ + static FT_F26Dot6 + Round_Super_45( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ) + { + FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; + FT_F26Dot6 val; + + + if ( distance >= 0 ) + { + val = ( ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) / + exc->period ) * exc->period; + val = ADD_LONG( val, exc->phase ); + if ( val < 0 ) + val = exc->phase; + } + else + { + val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) / + exc->period ) * exc->period ); + val = SUB_LONG( val, exc->phase ); + if ( val > 0 ) + val = -exc->phase; + } + + return val; + } + + + /************************************************************************** + * + * @Function: + * Compute_Round + * + * @Description: + * Sets the rounding mode. + * + * @Input: + * round_mode :: + * The rounding mode to be used. + */ + static void + Compute_Round( TT_ExecContext exc, + FT_Byte round_mode ) + { + switch ( round_mode ) + { + case TT_Round_Off: + exc->func_round = (TT_Round_Func)Round_None; + break; + + case TT_Round_To_Grid: + exc->func_round = (TT_Round_Func)Round_To_Grid; + break; + + case TT_Round_Up_To_Grid: + exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + break; + + case TT_Round_Down_To_Grid: + exc->func_round = (TT_Round_Func)Round_Down_To_Grid; + break; + + case TT_Round_To_Half_Grid: + exc->func_round = (TT_Round_Func)Round_To_Half_Grid; + break; + + case TT_Round_To_Double_Grid: + exc->func_round = (TT_Round_Func)Round_To_Double_Grid; + break; + + case TT_Round_Super: + exc->func_round = (TT_Round_Func)Round_Super; + break; + + case TT_Round_Super_45: + exc->func_round = (TT_Round_Func)Round_Super_45; + break; + } + } + + + /************************************************************************** + * + * @Function: + * SetSuperRound + * + * @Description: + * Sets Super Round parameters. + * + * @Input: + * GridPeriod :: + * The grid period. + * + * selector :: + * The SROUND opcode. + */ + static void + SetSuperRound( TT_ExecContext exc, + FT_F2Dot14 GridPeriod, + FT_Long selector ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { + case 0: + exc->period = GridPeriod / 2; + break; + + case 0x40: + exc->period = GridPeriod; + break; + + case 0x80: + exc->period = GridPeriod * 2; + break; + + /* This opcode is reserved, but... */ + case 0xC0: + exc->period = GridPeriod; + break; + } + + switch ( (FT_Int)( selector & 0x30 ) ) + { + case 0: + exc->phase = 0; + break; + + case 0x10: + exc->phase = exc->period / 4; + break; + + case 0x20: + exc->phase = exc->period / 2; + break; + + case 0x30: + exc->phase = exc->period * 3 / 4; + break; + } + + if ( ( selector & 0x0F ) == 0 ) + exc->threshold = exc->period - 1; + else + exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8; + + /* convert to F26Dot6 format */ + exc->period >>= 8; + exc->phase >>= 8; + exc->threshold >>= 8; + } + + + /************************************************************************** + * + * @Function: + * Project + * + * @Description: + * Computes the projection of vector given by (v2-v1) along the + * current projection vector. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( dx, dy, + exc->GS.projVector.x, + exc->GS.projVector.y ); + } + + + /************************************************************************** + * + * @Function: + * Dual_Project + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * current dual vector. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Dual_Project( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( dx, dy, + exc->GS.dualVector.x, + exc->GS.dualVector.y ); + } + + + /************************************************************************** + * + * @Function: + * Project_x + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * horizontal axis. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project_x( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED( exc ); + FT_UNUSED( dy ); + + return dx; + } + + + /************************************************************************** + * + * @Function: + * Project_y + * + * @Description: + * Computes the projection of the vector given by (v2-v1) along the + * vertical axis. + * + * @Input: + * v1 :: + * First input vector. + * v2 :: + * Second input vector. + * + * @Return: + * The distance in F26dot6 format. + */ + static FT_F26Dot6 + Project_y( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED( exc ); + FT_UNUSED( dx ); + + return dy; + } + + + /************************************************************************** + * + * @Function: + * Compute_Funcs + * + * @Description: + * Computes the projection and movement function pointers according + * to the current graphics state. + */ + static void + Compute_Funcs( TT_ExecContext exc ) + { + if ( exc->GS.freeVector.x == 0x4000 ) + exc->F_dot_P = exc->GS.projVector.x; + else if ( exc->GS.freeVector.y == 0x4000 ) + exc->F_dot_P = exc->GS.projVector.y; + else + exc->F_dot_P = + ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + + (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14; + + if ( exc->GS.projVector.x == 0x4000 ) + exc->func_project = (TT_Project_Func)Project_x; + else if ( exc->GS.projVector.y == 0x4000 ) + exc->func_project = (TT_Project_Func)Project_y; + else + exc->func_project = (TT_Project_Func)Project; + + if ( exc->GS.dualVector.x == 0x4000 ) + exc->func_dualproj = (TT_Project_Func)Project_x; + else if ( exc->GS.dualVector.y == 0x4000 ) + exc->func_dualproj = (TT_Project_Func)Project_y; + else + exc->func_dualproj = (TT_Project_Func)Dual_Project; + + exc->func_move = (TT_Move_Func)Direct_Move; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; + + if ( exc->F_dot_P == 0x4000L ) + { + if ( exc->GS.freeVector.x == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_X; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else if ( exc->GS.freeVector.y == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_Y; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + } + + /* at small sizes, F_dot_P can become too small, resulting */ + /* in overflows and `spikes' in a number of glyphs like `w'. */ + + if ( FT_ABS( exc->F_dot_P ) < 0x400L ) + exc->F_dot_P = 0x4000L; + + /* Disable cached aspect ratio */ + exc->tt_metrics.ratio = 0; + } + + + /************************************************************************** + * + * @Function: + * Normalize + * + * @Description: + * Norms a vector. + * + * @Input: + * Vx :: + * The horizontal input vector coordinate. + * Vy :: + * The vertical input vector coordinate. + * + * @Output: + * R :: + * The normed unit vector. + * + * @Return: + * Returns FAILURE if a vector parameter is zero. + * + * @Note: + * In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and + * R is undefined. + */ + static FT_Bool + Normalize( FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_Vector V; + + + if ( Vx == 0 && Vy == 0 ) + { + /* XXX: UNDOCUMENTED! It seems that it is possible to try */ + /* to normalize the vector (0,0). Return immediately. */ + return SUCCESS; + } + + V.x = Vx; + V.y = Vy; + + FT_Vector_NormLen( &V ); + + R->x = (FT_F2Dot14)( V.x / 4 ); + R->y = (FT_F2Dot14)( V.y / 4 ); + + return SUCCESS; + } + + + /************************************************************************** + * + * Here we start with the implementation of the various opcodes. + * + */ + + +#define ARRAY_BOUND_ERROR \ + do \ + { \ + exc->error = FT_THROW( Invalid_Reference ); \ + return; \ + } while (0) + + + /************************************************************************** + * + * MPPEM[]: Measure Pixel Per EM + * Opcode range: 0x4B + * Stack: --> Euint16 + */ + static void + Ins_MPPEM( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->func_cur_ppem( exc ); + } + + + /************************************************************************** + * + * MPS[]: Measure Point Size + * Opcode range: 0x4C + * Stack: --> Euint16 + */ + static void + Ins_MPS( TT_ExecContext exc, + FT_Long* args ) + { + if ( NO_SUBPIXEL_HINTING ) + { + /* Microsoft's GDI bytecode interpreter always returns value 12; */ + /* we return the current PPEM value instead. */ + args[0] = exc->func_cur_ppem( exc ); + } + else + { + /* A possible practical application of the MPS instruction is to */ + /* implement optical scaling and similar features, which should be */ + /* based on perceptual attributes, thus independent of the */ + /* resolution. */ + args[0] = exc->pointSize; + } + } + + + /************************************************************************** + * + * DUP[]: DUPlicate the stack's top element + * Opcode range: 0x20 + * Stack: StkElt --> StkElt StkElt + */ + static void + Ins_DUP( FT_Long* args ) + { + args[1] = args[0]; + } + + + /************************************************************************** + * + * POP[]: POP the stack's top element + * Opcode range: 0x21 + * Stack: StkElt --> + */ + static void + Ins_POP( void ) + { + /* nothing to do */ + } + + + /************************************************************************** + * + * CLEAR[]: CLEAR the entire stack + * Opcode range: 0x22 + * Stack: StkElt... --> + */ + static void + Ins_CLEAR( TT_ExecContext exc ) + { + exc->new_top = 0; + } + + + /************************************************************************** + * + * SWAP[]: SWAP the stack's top two elements + * Opcode range: 0x23 + * Stack: 2 * StkElt --> 2 * StkElt + */ + static void + Ins_SWAP( FT_Long* args ) + { + FT_Long L; + + + L = args[0]; + args[0] = args[1]; + args[1] = L; + } + + + /************************************************************************** + * + * DEPTH[]: return the stack DEPTH + * Opcode range: 0x24 + * Stack: --> uint32 + */ + static void + Ins_DEPTH( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->top; + } + + + /************************************************************************** + * + * LT[]: Less Than + * Opcode range: 0x50 + * Stack: int32? int32? --> bool + */ + static void + Ins_LT( FT_Long* args ) + { + args[0] = ( args[0] < args[1] ); + } + + + /************************************************************************** + * + * LTEQ[]: Less Than or EQual + * Opcode range: 0x51 + * Stack: int32? int32? --> bool + */ + static void + Ins_LTEQ( FT_Long* args ) + { + args[0] = ( args[0] <= args[1] ); + } + + + /************************************************************************** + * + * GT[]: Greater Than + * Opcode range: 0x52 + * Stack: int32? int32? --> bool + */ + static void + Ins_GT( FT_Long* args ) + { + args[0] = ( args[0] > args[1] ); + } + + + /************************************************************************** + * + * GTEQ[]: Greater Than or EQual + * Opcode range: 0x53 + * Stack: int32? int32? --> bool + */ + static void + Ins_GTEQ( FT_Long* args ) + { + args[0] = ( args[0] >= args[1] ); + } + + + /************************************************************************** + * + * EQ[]: EQual + * Opcode range: 0x54 + * Stack: StkElt StkElt --> bool + */ + static void + Ins_EQ( FT_Long* args ) + { + args[0] = ( args[0] == args[1] ); + } + + + /************************************************************************** + * + * NEQ[]: Not EQual + * Opcode range: 0x55 + * Stack: StkElt StkElt --> bool + */ + static void + Ins_NEQ( FT_Long* args ) + { + args[0] = ( args[0] != args[1] ); + } + + + /************************************************************************** + * + * ODD[]: Is ODD + * Opcode range: 0x56 + * Stack: f26.6 --> bool + */ + static void + Ins_ODD( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 64 ); + } + + + /************************************************************************** + * + * EVEN[]: Is EVEN + * Opcode range: 0x57 + * Stack: f26.6 --> bool + */ + static void + Ins_EVEN( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 0 ); + } + + + /************************************************************************** + * + * AND[]: logical AND + * Opcode range: 0x5A + * Stack: uint32 uint32 --> uint32 + */ + static void + Ins_AND( FT_Long* args ) + { + args[0] = ( args[0] && args[1] ); + } + + + /************************************************************************** + * + * OR[]: logical OR + * Opcode range: 0x5B + * Stack: uint32 uint32 --> uint32 + */ + static void + Ins_OR( FT_Long* args ) + { + args[0] = ( args[0] || args[1] ); + } + + + /************************************************************************** + * + * NOT[]: logical NOT + * Opcode range: 0x5C + * Stack: StkElt --> uint32 + */ + static void + Ins_NOT( FT_Long* args ) + { + args[0] = !args[0]; + } + + + /************************************************************************** + * + * ADD[]: ADD + * Opcode range: 0x60 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_ADD( FT_Long* args ) + { + args[0] = ADD_LONG( args[0], args[1] ); + } + + + /************************************************************************** + * + * SUB[]: SUBtract + * Opcode range: 0x61 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_SUB( FT_Long* args ) + { + args[0] = SUB_LONG( args[0], args[1] ); + } + + + /************************************************************************** + * + * DIV[]: DIVide + * Opcode range: 0x62 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_DIV( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] == 0 ) + exc->error = FT_THROW( Divide_By_Zero ); + else + args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] ); + } + + + /************************************************************************** + * + * MUL[]: MULtiply + * Opcode range: 0x63 + * Stack: f26.6 f26.6 --> f26.6 + */ + static void + Ins_MUL( FT_Long* args ) + { + args[0] = FT_MulDiv( args[0], args[1], 64L ); + } + + + /************************************************************************** + * + * ABS[]: ABSolute value + * Opcode range: 0x64 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_ABS( FT_Long* args ) + { + if ( args[0] < 0 ) + args[0] = NEG_LONG( args[0] ); + } + + + /************************************************************************** + * + * NEG[]: NEGate + * Opcode range: 0x65 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_NEG( FT_Long* args ) + { + args[0] = NEG_LONG( args[0] ); + } + + + /************************************************************************** + * + * FLOOR[]: FLOOR + * Opcode range: 0x66 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_FLOOR( FT_Long* args ) + { + args[0] = FT_PIX_FLOOR( args[0] ); + } + + + /************************************************************************** + * + * CEILING[]: CEILING + * Opcode range: 0x67 + * Stack: f26.6 --> f26.6 + */ + static void + Ins_CEILING( FT_Long* args ) + { + args[0] = FT_PIX_CEIL_LONG( args[0] ); + } + + + /************************************************************************** + * + * RS[]: Read Store + * Opcode range: 0x43 + * Stack: uint32 --> uint32 + */ + static void + Ins_RS( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + args[0] = exc->storage[I]; + } + + + /************************************************************************** + * + * WS[]: Write Store + * Opcode range: 0x42 + * Stack: uint32 uint32 --> + */ + static void + Ins_WS( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + { + if ( exc->iniRange == tt_coderange_glyph && + exc->storage != exc->glyfStorage ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfStorage, + exc->glyfStoreSize, + exc->storeSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfStoreSize = exc->storeSize; + FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize ); + exc->storage = exc->glyfStorage; + } + + exc->storage[I] = args[1]; + } + } + + + /************************************************************************** + * + * WCVTP[]: Write CVT in Pixel units + * Opcode range: 0x44 + * Stack: f26.6 uint32 --> + */ + static void + Ins_WCVTP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->func_write_cvt( exc, I, args[1] ); + } + + + /************************************************************************** + * + * WCVTF[]: Write CVT in Funits + * Opcode range: 0x70 + * Stack: uint32 uint32 --> + */ + static void + Ins_WCVTF( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale ); + } + + + /************************************************************************** + * + * RCVT[]: Read CVT + * Opcode range: 0x45 + * Stack: uint32 --> f26.6 + */ + static void + Ins_RCVT( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + args[0] = exc->func_read_cvt( exc, I ); + } + + + /************************************************************************** + * + * AA[]: Adjust Angle + * Opcode range: 0x7F + * Stack: uint32 --> + */ + static void + Ins_AA( void ) + { + /* intentionally no longer supported */ + } + + + /************************************************************************** + * + * DEBUG[]: DEBUG. Unsupported. + * Opcode range: 0x4F + * Stack: uint32 --> + * + * Note: The original instruction pops a value from the stack. + */ + static void + Ins_DEBUG( TT_ExecContext exc ) + { + exc->error = FT_THROW( Debug_OpCode ); + } + + + /************************************************************************** + * + * ROUND[ab]: ROUND value + * Opcode range: 0x68-0x6B + * Stack: f26.6 --> f26.6 + */ + static void + Ins_ROUND( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->func_round( exc, args[0], exc->opcode & 3 ); + } + + + /************************************************************************** + * + * NROUND[ab]: No ROUNDing of value + * Opcode range: 0x6C-0x6F + * Stack: f26.6 --> f26.6 + */ + static void + Ins_NROUND( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = Round_None( exc, args[0], exc->opcode & 3 ); + } + + + /************************************************************************** + * + * MAX[]: MAXimum + * Opcode range: 0x8B + * Stack: int32? int32? --> int32 + */ + static void + Ins_MAX( FT_Long* args ) + { + if ( args[1] > args[0] ) + args[0] = args[1]; + } + + + /************************************************************************** + * + * MIN[]: MINimum + * Opcode range: 0x8C + * Stack: int32? int32? --> int32 + */ + static void + Ins_MIN( FT_Long* args ) + { + if ( args[1] < args[0] ) + args[0] = args[1]; + } + + + /************************************************************************** + * + * MINDEX[]: Move INDEXed element + * Opcode range: 0x26 + * Stack: int32? --> StkElt + */ + static void + Ins_MINDEX( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long L, K; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + else + { + K = exc->stack[exc->args - L]; + + FT_ARRAY_MOVE( &exc->stack[exc->args - L ], + &exc->stack[exc->args - L + 1], + ( L - 1 ) ); + + exc->stack[exc->args - 1] = K; + } + } + + + /************************************************************************** + * + * CINDEX[]: Copy INDEXed element + * Opcode range: 0x25 + * Stack: int32 --> StkElt + */ + static void + Ins_CINDEX( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long L; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + args[0] = 0; + } + else + args[0] = exc->stack[exc->args - L]; + } + + + /************************************************************************** + * + * ROLL[]: ROLL top three elements + * Opcode range: 0x8A + * Stack: 3 * StkElt --> 3 * StkElt + */ + static void + Ins_ROLL( FT_Long* args ) + { + FT_Long A, B, C; + + + A = args[2]; + B = args[1]; + C = args[0]; + + args[2] = C; + args[1] = A; + args[0] = B; + } + + + /************************************************************************** + * + * MANAGING THE FLOW OF CONTROL + * + */ + + + /************************************************************************** + * + * SLOOP[]: Set LOOP variable + * Opcode range: 0x17 + * Stack: int32? --> + */ + static void + Ins_SLOOP( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] < 0 ) + exc->error = FT_THROW( Bad_Argument ); + else + { + /* we heuristically limit the number of loops to 16 bits */ + exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0]; + } + } + + + static FT_Bool + SkipCode( TT_ExecContext exc ) + { + exc->IP += exc->length; + + if ( exc->IP < exc->codeSize ) + { + exc->opcode = exc->code[exc->IP]; + + exc->length = opcode_length[exc->opcode]; + if ( exc->length < 0 ) + { + if ( exc->IP + 1 >= exc->codeSize ) + goto Fail_Overflow; + exc->length = 2 - exc->length * exc->code[exc->IP + 1]; + } + + if ( exc->IP + exc->length <= exc->codeSize ) + return SUCCESS; + } + + Fail_Overflow: + exc->error = FT_THROW( Code_Overflow ); + return FAILURE; + } + + + /************************************************************************** + * + * IF[]: IF test + * Opcode range: 0x58 + * Stack: StkElt --> + */ + static void + Ins_IF( TT_ExecContext exc, + FT_Long* args ) + { + FT_Int nIfs; + FT_Bool Out; + + + if ( args[0] != 0 ) + return; + + nIfs = 1; + Out = 0; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x1B: /* ELSE */ + Out = FT_BOOL( nIfs == 1 ); + break; + + case 0x59: /* EIF */ + nIfs--; + Out = FT_BOOL( nIfs == 0 ); + break; + } + } while ( Out == 0 ); + } + + + /************************************************************************** + * + * ELSE[]: ELSE + * Opcode range: 0x1B + * Stack: --> + */ + static void + Ins_ELSE( TT_ExecContext exc ) + { + FT_Int nIfs; + + + nIfs = 1; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x59: /* EIF */ + nIfs--; + break; + } + } while ( nIfs != 0 ); + } + + + /************************************************************************** + * + * EIF[]: End IF + * Opcode range: 0x59 + * Stack: --> + */ + static void + Ins_EIF( void ) + { + /* nothing to do */ + } + + + /************************************************************************** + * + * JMPR[]: JuMP Relative + * Opcode range: 0x1C + * Stack: int32 --> + */ + static void + Ins_JMPR( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] == 0 && exc->args == 0 ) + { + exc->error = FT_THROW( Bad_Argument ); + return; + } + + exc->IP = ADD_LONG( exc->IP, args[0] ); + if ( exc->IP < 0 || + ( exc->callTop > 0 && + exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) + { + exc->error = FT_THROW( Bad_Argument ); + return; + } + + exc->step_ins = FALSE; + + if ( args[0] < 0 ) + { + if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); + } + } + + + /************************************************************************** + * + * JROT[]: Jump Relative On True + * Opcode range: 0x78 + * Stack: StkElt int32 --> + */ + static void + Ins_JROT( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] != 0 ) + Ins_JMPR( exc, args ); + } + + + /************************************************************************** + * + * JROF[]: Jump Relative On False + * Opcode range: 0x79 + * Stack: StkElt int32 --> + */ + static void + Ins_JROF( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[1] == 0 ) + Ins_JMPR( exc, args ); + } + + + /************************************************************************** + * + * DEFINING AND USING FUNCTIONS AND INSTRUCTIONS + * + */ + + + /************************************************************************** + * + * FDEF[]: Function DEFinition + * Opcode range: 0x2C + * Stack: uint32 --> + */ + static void + Ins_FDEF( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; + + + /* FDEF is only allowed in `prep' or `fpgm' */ + if ( exc->iniRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } + + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ + + rec = exc->FDefs; + limit = FT_OFFSET( rec, exc->numFDefs ); + n = (FT_ULong)args[0]; + + for ( ; rec < limit; rec++ ) + { + if ( rec->opc == n ) + break; + } + + if ( rec == limit ) + { + /* check that there is enough room for new functions */ + if ( exc->numFDefs >= exc->maxFDefs ) + { + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; + } + exc->numFDefs++; + } + + /* Although FDEF takes unsigned 32-bit integer, */ + /* func # must be within unsigned 16-bit integer */ + if ( n > 0xFFFFU ) + { + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; + } + + rec->range = exc->curRange; + rec->opc = (FT_UInt16)n; + rec->start = exc->IP + 1; + rec->active = TRUE; + + if ( n > exc->maxFunc ) + exc->maxFunc = (FT_UInt16)n; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFS & FDEFs. */ + + while ( SkipCode( exc ) == SUCCESS ) + { + switch ( exc->opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + + case 0x2D: /* ENDF */ + rec->end = exc->IP; + return; + } + } + } + + + /************************************************************************** + * + * ENDF[]: END Function definition + * Opcode range: 0x2D + * Stack: --> + */ + static void + Ins_ENDF( TT_ExecContext exc ) + { + TT_CallRec* pRec; + + + if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ + { + exc->error = FT_THROW( ENDF_In_Exec_Stream ); + return; + } + + exc->callTop--; + + pRec = &exc->callStack[exc->callTop]; + + pRec->Cur_Count--; + + exc->step_ins = FALSE; + + if ( pRec->Cur_Count > 0 ) + { + exc->callTop++; + exc->IP = pRec->Def->start; + } + else + /* Loop through the current function */ + Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP ); + + /* Exit the current call frame. */ + + /* NOTE: If the last instruction of a program is a */ + /* CALL or LOOPCALL, the return address is */ + /* always out of the code range. This is a */ + /* valid address, and it is why we do not test */ + /* the result of Ins_Goto_CodeRange() here! */ + } + + + /************************************************************************** + * + * CALL[]: CALL function + * Opcode range: 0x2B + * Stack: uint32? --> + */ + static void + Ins_CALL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + + F = (FT_ULong)args[0]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + + if ( !exc->FDefs ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = exc->FDefs + F; + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = exc->FDefs; + limit = def + exc->numFDefs; + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check the call stack */ + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + pCrec = exc->callStack + exc->callTop; + + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = 1; + pCrec->Def = def; + + exc->callTop++; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + + return; + + Fail: + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * LOOPCALL[]: LOOP and CALL function + * Opcode range: 0x2A + * Stack: uint32? Eint16? --> + */ + static void + Ins_LOOPCALL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; + + + /* first of all, check the index */ + F = (FT_ULong)args[1]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ + + def = FT_OFFSET( exc->FDefs, F ); + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; + + + def = exc->FDefs; + limit = FT_OFFSET( def, exc->numFDefs ); + + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; + } + + /* check that the function is active */ + if ( !def->active ) + goto Fail; + + /* check stack */ + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + if ( args[0] > 0 ) + { + pCrec = exc->callStack + exc->callTop; + + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Def = def; + + exc->callTop++; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + + exc->loopcall_counter += (FT_ULong)args[0]; + if ( exc->loopcall_counter > exc->loopcall_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); + } + + return; + + Fail: + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * IDEF[]: Instruction DEFinition + * Opcode range: 0x89 + * Stack: Eint8 --> + */ + static void + Ins_IDEF( TT_ExecContext exc, + FT_Long* args ) + { + TT_DefRecord* def; + TT_DefRecord* limit; + + + /* we enable IDEF only in `prep' or `fpgm' */ + if ( exc->iniRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } + + /* First of all, look for the same function in our table */ + + def = exc->IDefs; + limit = FT_OFFSET( def, exc->numIDefs ); + + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + + if ( def == limit ) + { + /* check that there is enough room for a new instruction */ + if ( exc->numIDefs >= exc->maxIDefs ) + { + exc->error = FT_THROW( Too_Many_Instruction_Defs ); + return; + } + exc->numIDefs++; + } + + /* opcode must be unsigned 8-bit integer */ + if ( 0 > args[0] || args[0] > 0x00FF ) + { + exc->error = FT_THROW( Too_Many_Instruction_Defs ); + return; + } + + def->opc = (FT_Byte)args[0]; + def->start = exc->IP + 1; + def->range = exc->curRange; + def->active = TRUE; + + if ( (FT_ULong)args[0] > exc->maxIns ) + exc->maxIns = (FT_Byte)args[0]; + + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFs & FDEFs. */ + + while ( SkipCode( exc ) == SUCCESS ) + { + switch ( exc->opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + case 0x2D: /* ENDF */ + def->end = exc->IP; + return; + } + } + } + + + /************************************************************************** + * + * PUSHING DATA ONTO THE INTERPRETER STACK + * + */ + + + /************************************************************************** + * + * NPUSHB[]: PUSH N Bytes + * Opcode range: 0x40 + * Stack: --> uint32... + */ + static void + Ins_NPUSHB( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)exc->code[exc->IP + 1]; + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K + 1]; + + exc->new_top += L; + } + + + /************************************************************************** + * + * NPUSHW[]: PUSH N Words + * Opcode range: 0x41 + * Stack: --> int32... + */ + static void + Ins_NPUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)exc->code[exc->IP + 1]; + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + exc->IP += 2; + + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; + exc->new_top += L; + } + + + /************************************************************************** + * + * PUSHB[abc]: PUSH Bytes + * Opcode range: 0xB0-0xB7 + * Stack: --> uint32... + */ + static void + Ins_PUSHB( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K]; + } + + + /************************************************************************** + * + * PUSHW[abc]: PUSH Words + * Opcode range: 0xB8-0xBF + * Stack: --> int32... + */ + static void + Ins_PUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; + + + L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + exc->IP++; + + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; + } + + + /************************************************************************** + * + * MANAGING THE GRAPHICS STATE + * + */ + + + static FT_Bool + Ins_SxVTL( TT_ExecContext exc, + FT_UShort aIdx1, + FT_UShort aIdx2, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; + + FT_Byte opcode = exc->opcode; + + + if ( BOUNDS( aIdx1, exc->zp2.n_points ) || + BOUNDS( aIdx2, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return FAILURE; + } + + p1 = exc->zp1.cur + aIdx2; + p2 = exc->zp2.cur + aIdx1; + + A = SUB_LONG( p1->x, p2->x ); + B = SUB_LONG( p1->y, p2->y ); + + /* If p1 == p2, SPvTL and SFvTL behave the same as */ + /* SPvTCA[X] and SFvTCA[X], respectively. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, Vec ); + + return SUCCESS; + } + + + /************************************************************************** + * + * SVTCA[a]: Set (F and P) Vectors to Coordinate Axis + * Opcode range: 0x00-0x01 + * Stack: --> + * + * SPvTCA[a]: Set PVector to Coordinate Axis + * Opcode range: 0x02-0x03 + * Stack: --> + * + * SFvTCA[a]: Set FVector to Coordinate Axis + * Opcode range: 0x04-0x05 + * Stack: --> + */ + static void + Ins_SxyTCA( TT_ExecContext exc ) + { + FT_Short AA, BB; + + FT_Byte opcode = exc->opcode; + + + AA = (FT_Short)( ( opcode & 1 ) << 14 ); + BB = (FT_Short)( AA ^ 0x4000 ); + + if ( opcode < 4 ) + { + exc->GS.projVector.x = AA; + exc->GS.projVector.y = BB; + + exc->GS.dualVector.x = AA; + exc->GS.dualVector.y = BB; + } + + if ( ( opcode & 2 ) == 0 ) + { + exc->GS.freeVector.x = AA; + exc->GS.freeVector.y = BB; + } + + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SPvTL[a]: Set PVector To Line + * Opcode range: 0x06-0x07 + * Stack: uint32 uint32 --> + */ + static void + Ins_SPVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.projVector ) == SUCCESS ) + { + exc->GS.dualVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + } + + + /************************************************************************** + * + * SFvTL[a]: Set FVector To Line + * Opcode range: 0x08-0x09 + * Stack: uint32 uint32 --> + */ + static void + Ins_SFVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.freeVector ) == SUCCESS ) + { + Compute_Funcs( exc ); + } + } + + + /************************************************************************** + * + * SFvTPv[]: Set FVector To PVector + * Opcode range: 0x0E + * Stack: --> + */ + static void + Ins_SFVTPV( TT_ExecContext exc ) + { + exc->GS.freeVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SPvFS[]: Set PVector From Stack + * Opcode range: 0x0A + * Stack: f2.14 f2.14 --> + */ + static void + Ins_SPVFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Short S; + FT_Long X, Y; + + + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = (FT_Long)S; + + Normalize( X, Y, &exc->GS.projVector ); + + exc->GS.dualVector = exc->GS.projVector; + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SFvFS[]: Set FVector From Stack + * Opcode range: 0x0B + * Stack: f2.14 f2.14 --> + */ + static void + Ins_SFVFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Short S; + FT_Long X, Y; + + + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = S; + + Normalize( X, Y, &exc->GS.freeVector ); + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * GPv[]: Get Projection Vector + * Opcode range: 0x0C + * Stack: ef2.14 --> ef2.14 + */ + static void + Ins_GPV( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->GS.projVector.x; + args[1] = exc->GS.projVector.y; + } + + + /************************************************************************** + * + * GFv[]: Get Freedom Vector + * Opcode range: 0x0D + * Stack: ef2.14 --> ef2.14 + */ + static void + Ins_GFV( TT_ExecContext exc, + FT_Long* args ) + { + args[0] = exc->GS.freeVector.x; + args[1] = exc->GS.freeVector.y; + } + + + /************************************************************************** + * + * SRP0[]: Set Reference Point 0 + * Opcode range: 0x10 + * Stack: uint32 --> + */ + static void + Ins_SRP0( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp0 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SRP1[]: Set Reference Point 1 + * Opcode range: 0x11 + * Stack: uint32 --> + */ + static void + Ins_SRP1( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp1 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SRP2[]: Set Reference Point 2 + * Opcode range: 0x12 + * Stack: uint32 --> + */ + static void + Ins_SRP2( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SMD[]: Set Minimum Distance + * Opcode range: 0x1A + * Stack: f26.6 --> + */ + static void + Ins_SMD( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.minimum_distance = args[0]; + } + + + /************************************************************************** + * + * SCVTCI[]: Set Control Value Table Cut In + * Opcode range: 0x1D + * Stack: f26.6 --> + */ + static void + Ins_SCVTCI( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.control_value_cutin = (FT_F26Dot6)args[0]; + } + + + /************************************************************************** + * + * SSWCI[]: Set Single Width Cut In + * Opcode range: 0x1E + * Stack: f26.6 --> + */ + static void + Ins_SSWCI( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.single_width_cutin = (FT_F26Dot6)args[0]; + } + + + /************************************************************************** + * + * SSW[]: Set Single Width + * Opcode range: 0x1F + * Stack: int32? --> + */ + static void + Ins_SSW( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.single_width_value = FT_MulFix( args[0], + exc->tt_metrics.scale ); + } + + + /************************************************************************** + * + * FLIPON[]: Set auto-FLIP to ON + * Opcode range: 0x4D + * Stack: --> + */ + static void + Ins_FLIPON( TT_ExecContext exc ) + { + exc->GS.auto_flip = TRUE; + } + + + /************************************************************************** + * + * FLIPOFF[]: Set auto-FLIP to OFF + * Opcode range: 0x4E + * Stack: --> + */ + static void + Ins_FLIPOFF( TT_ExecContext exc ) + { + exc->GS.auto_flip = FALSE; + } + + + /************************************************************************** + * + * SANGW[]: Set ANGle Weight + * Opcode range: 0x7E + * Stack: uint32 --> + */ + static void + Ins_SANGW( void ) + { + /* instruction not supported anymore */ + } + + + /************************************************************************** + * + * SDB[]: Set Delta Base + * Opcode range: 0x5E + * Stack: uint32 --> + */ + static void + Ins_SDB( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.delta_base = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SDS[]: Set Delta Shift + * Opcode range: 0x5F + * Stack: uint32 --> + */ + static void + Ins_SDS( TT_ExecContext exc, + FT_Long* args ) + { + if ( (FT_ULong)args[0] > 6UL ) + exc->error = FT_THROW( Bad_Argument ); + else + exc->GS.delta_shift = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * RTHG[]: Round To Half Grid + * Opcode range: 0x19 + * Stack: --> + */ + static void + Ins_RTHG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Half_Grid; + exc->func_round = (TT_Round_Func)Round_To_Half_Grid; + } + + + /************************************************************************** + * + * RTG[]: Round To Grid + * Opcode range: 0x18 + * Stack: --> + */ + static void + Ins_RTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Grid; + exc->func_round = (TT_Round_Func)Round_To_Grid; + } + + + /************************************************************************** + * RTDG[]: Round To Double Grid + * Opcode range: 0x3D + * Stack: --> + */ + static void + Ins_RTDG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Double_Grid; + exc->func_round = (TT_Round_Func)Round_To_Double_Grid; + } + + + /************************************************************************** + * RUTG[]: Round Up To Grid + * Opcode range: 0x7C + * Stack: --> + */ + static void + Ins_RUTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Up_To_Grid; + exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + } + + + /************************************************************************** + * + * RDTG[]: Round Down To Grid + * Opcode range: 0x7D + * Stack: --> + */ + static void + Ins_RDTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Down_To_Grid; + exc->func_round = (TT_Round_Func)Round_Down_To_Grid; + } + + + /************************************************************************** + * + * ROFF[]: Round OFF + * Opcode range: 0x7A + * Stack: --> + */ + static void + Ins_ROFF( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Off; + exc->func_round = (TT_Round_Func)Round_None; + } + + + /************************************************************************** + * + * SROUND[]: Super ROUND + * Opcode range: 0x76 + * Stack: Eint8 --> + */ + static void + Ins_SROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x4000, args[0] ); + + exc->GS.round_state = TT_Round_Super; + exc->func_round = (TT_Round_Func)Round_Super; + } + + + /************************************************************************** + * + * S45ROUND[]: Super ROUND 45 degrees + * Opcode range: 0x77 + * Stack: uint32 --> + */ + static void + Ins_S45ROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x2D41, args[0] ); + + exc->GS.round_state = TT_Round_Super_45; + exc->func_round = (TT_Round_Func)Round_Super_45; + } + + + /************************************************************************** + * + * GC[a]: Get Coordinate projected onto + * Opcode range: 0x46-0x47 + * Stack: uint32 --> f26.6 + * + * XXX: UNDOCUMENTED: Measures from the original glyph must be taken + * along the dual projection vector! + */ + static void + Ins_GC( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong L; + FT_F26Dot6 R; + + + L = (FT_ULong)args[0]; + + if ( BOUNDSL( L, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + R = 0; + } + else + { + if ( exc->opcode & 1 ) + R = FAST_DUALPROJ( &exc->zp2.org[L] ); + else + R = FAST_PROJECT( &exc->zp2.cur[L] ); + } + + args[0] = R; + } + + + /************************************************************************** + * + * SCFS[]: Set Coordinate From Stack + * Opcode range: 0x48 + * Stack: f26.6 uint32 --> + * + * Formula: + * + * OA := OA + ( value - OA.p )/( f.p ) * f + */ + static void + Ins_SCFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long K; + FT_UShort L; + + + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + K = FAST_PROJECT( &exc->zp2.cur[L] ); + + exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) ); + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep2 == 0 ) + exc->zp2.org[L] = exc->zp2.cur[L]; + } + + + /************************************************************************** + * + * MD[a]: Measure Distance + * Opcode range: 0x49-0x4A + * Stack: uint32 uint32 --> f26.6 + * + * XXX: UNDOCUMENTED: Measure taken in the original glyph must be along + * the dual projection vector. + * + * XXX: UNDOCUMENTED: Flag attributes are inverted! + * 0 => measure distance in original outline + * 1 => measure distance in grid-fitted outline + * + * XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! + */ + static void + Ins_MD( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort K, L; + FT_F26Dot6 D; + + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( L, exc->zp0.n_points ) || + BOUNDS( K, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + D = 0; + } + else + { + if ( exc->opcode & 1 ) + D = PROJECT( exc->zp0.cur + L, exc->zp1.cur + K ); + else + { + /* XXX: UNDOCUMENTED: twilight zone special case */ + + if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 ) + { + FT_Vector* vec1 = exc->zp0.org + L; + FT_Vector* vec2 = exc->zp1.org + K; + + + D = DUALPROJ( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = exc->zp0.orus + L; + FT_Vector* vec2 = exc->zp1.orus + K; + + + if ( exc->metrics.x_scale == exc->metrics.y_scale ) + { + /* this should be faster */ + D = DUALPROJ( vec1, vec2 ); + D = FT_MulFix( D, exc->metrics.x_scale ); + } + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale ); + vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale ); + + D = FAST_DUALPROJ( &vec ); + } + } + } + } + + args[0] = D; + } + + + /************************************************************************** + * + * SDPvTL[a]: Set Dual PVector to Line + * Opcode range: 0x86-0x87 + * Stack: uint32 uint32 --> + */ + static void + Ins_SDPVTL( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long A, B, C; + FT_UShort p1, p2; /* was FT_Int in pas type ERROR */ + + FT_Byte opcode = exc->opcode; + + + p1 = (FT_UShort)args[1]; + p2 = (FT_UShort)args[0]; + + if ( BOUNDS( p2, exc->zp1.n_points ) || + BOUNDS( p1, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + { + FT_Vector* v1 = exc->zp1.org + p2; + FT_Vector* v2 = exc->zp2.org + p1; + + + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); + + /* If v1 == v2, SDPvTL behaves the same as */ + /* SVTCA[X], respectively. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, &exc->GS.dualVector ); + + { + FT_Vector* v1 = exc->zp1.cur + p2; + FT_Vector* v2 = exc->zp2.cur + p1; + + + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); + + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; + } + } + + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter-clockwise rotation */ + B = A; + A = NEG_LONG( C ); + } + + Normalize( A, B, &exc->GS.projVector ); + Compute_Funcs( exc ); + } + + + /************************************************************************** + * + * SZP0[]: Set Zone Pointer 0 + * Opcode range: 0x13 + * Stack: uint32 --> + */ + static void + Ins_SZP0( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp0 = exc->twilight; + break; + + case 1: + exc->zp0 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep0 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZP1[]: Set Zone Pointer 1 + * Opcode range: 0x14 + * Stack: uint32 --> + */ + static void + Ins_SZP1( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp1 = exc->twilight; + break; + + case 1: + exc->zp1 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep1 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZP2[]: Set Zone Pointer 2 + * Opcode range: 0x15 + * Stack: uint32 --> + */ + static void + Ins_SZP2( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp2 = exc->twilight; + break; + + case 1: + exc->zp2 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->GS.gep2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * SZPS[]: Set Zone PointerS + * Opcode range: 0x16 + * Stack: uint32 --> + */ + static void + Ins_SZPS( TT_ExecContext exc, + FT_Long* args ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + exc->zp0 = exc->twilight; + break; + + case 1: + exc->zp0 = exc->pts; + break; + + default: + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + exc->zp1 = exc->zp0; + exc->zp2 = exc->zp0; + + exc->GS.gep0 = (FT_UShort)args[0]; + exc->GS.gep1 = (FT_UShort)args[0]; + exc->GS.gep2 = (FT_UShort)args[0]; + } + + + /************************************************************************** + * + * INSTCTRL[]: INSTruction ConTRoL + * Opcode range: 0x8E + * Stack: int32 int32 --> + */ + static void + Ins_INSTCTRL( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong K, L, Kf; + + + K = (FT_ULong)args[1]; + L = (FT_ULong)args[0]; + + /* selector values cannot be `OR'ed; */ + /* they are indices starting with index 1, not flags */ + if ( K < 1 || K > 3 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* convert index to flag value */ + Kf = 1 << ( K - 1 ); + + if ( L != 0 ) + { + /* arguments to selectors look like flag values */ + if ( L != Kf ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + + /* INSTCTRL should only be used in the CVT program */ + if ( exc->iniRange == tt_coderange_cvt ) + { + exc->GS.instruct_control &= ~(FT_Byte)Kf; + exc->GS.instruct_control |= (FT_Byte)L; + } + + /* except to change the subpixel flags temporarily */ + else if ( exc->iniRange == tt_coderange_glyph && K == 3 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType fonts sign a waiver that turns off all backward */ + /* compatibility hacks and lets them program points to the grid like */ + /* it's 1996. They might sign a waiver for just one glyph, though. */ + if ( SUBPIXEL_HINTING_MINIMAL ) + exc->backward_compatibility = !FT_BOOL( L == 4 ); +#endif + } + else if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + + + /************************************************************************** + * + * SCANCTRL[]: SCAN ConTRoL + * Opcode range: 0x85 + * Stack: uint32? --> + */ + static void + Ins_SCANCTRL( TT_ExecContext exc, + FT_Long* args ) + { + FT_Int A; + + + /* Get Threshold */ + A = (FT_Int)( args[0] & 0xFF ); + + if ( A == 0xFF ) + { + exc->GS.scan_control = TRUE; + return; + } + else if ( A == 0 ) + { + exc->GS.scan_control = FALSE; + return; + } + + if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched ) + exc->GS.scan_control = TRUE; + + if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A ) + exc->GS.scan_control = FALSE; + + if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated ) + exc->GS.scan_control = FALSE; + + if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched ) + exc->GS.scan_control = FALSE; + } + + + /************************************************************************** + * + * SCANTYPE[]: SCAN TYPE + * Opcode range: 0x8D + * Stack: uint16 --> + */ + static void + Ins_SCANTYPE( TT_ExecContext exc, + FT_Long* args ) + { + if ( args[0] >= 0 ) + exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF; + } + + + /************************************************************************** + * + * MANAGING OUTLINES + * + */ + + + /************************************************************************** + * + * FLIPPT[]: FLIP PoinT + * Opcode range: 0x80 + * Stack: uint32... --> + */ + static void + Ins_FLIPPT( TT_ExecContext exc ) + { + FT_UShort point; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + goto Fail; +#endif + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + goto Fail; + } + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + exc->pts.tags[point] ^= FT_CURVE_TAG_ON; + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * FLIPRGON[]: FLIP RanGe ON + * Opcode range: 0x81 + * Stack: uint32 uint32 --> + */ + static void + Ins_FLIPRGON( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort I, K, L; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, exc->pts.n_points ) || + BOUNDS( L, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + for ( I = L; I <= K; I++ ) + exc->pts.tags[I] |= FT_CURVE_TAG_ON; + } + + + /************************************************************************** + * + * FLIPRGOFF: FLIP RanGe OFF + * Opcode range: 0x82 + * Stack: uint32 uint32 --> + */ + static void + Ins_FLIPRGOFF( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort I, K, L; + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + + if ( BOUNDS( K, exc->pts.n_points ) || + BOUNDS( L, exc->pts.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + for ( I = L; I <= K; I++ ) + exc->pts.tags[I] &= ~FT_CURVE_TAG_ON; + } + + + static FT_Bool + Compute_Point_Displacement( TT_ExecContext exc, + FT_F26Dot6* x, + FT_F26Dot6* y, + TT_GlyphZone zone, + FT_UShort* refp ) + { + TT_GlyphZoneRec zp; + FT_UShort p; + FT_F26Dot6 d; + + + if ( exc->opcode & 1 ) + { + zp = exc->zp0; + p = exc->GS.rp1; + } + else + { + zp = exc->zp1; + p = exc->GS.rp2; + } + + if ( BOUNDS( p, zp.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + *refp = 0; + return FAILURE; + } + + *zone = zp; + *refp = p; + + d = PROJECT( zp.cur + p, zp.org + p ); + + *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); + *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); + + return SUCCESS; + } + + + /* See `ttinterp.h' for details on backward compatibility mode. */ + static void + Move_Zp2_Point( TT_ExecContext exc, + FT_UShort point, + FT_F26Dot6 dx, + FT_F26Dot6 dy, + FT_Bool touch ) + { + if ( exc->GS.freeVector.x != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) ) +#endif + exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); + + if ( touch ) + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + + if ( exc->GS.freeVector.y != 0 ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); + + if ( touch ) + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } + + + /************************************************************************** + * + * SHP[a]: SHift Point by the last point + * Opcode range: 0x32-0x33 + * Stack: uint32... --> + */ + static void + Ins_SHP( TT_ExecContext exc ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + + FT_F26Dot6 dx, dy; + FT_UShort point; + + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + while ( exc->GS.loop > 0 ) + { + exc->args--; + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + Move_Zp2_Point( exc, point, dx, dy, TRUE ); + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * SHC[a]: SHift Contour + * Opcode range: 0x34-35 + * Stack: uint32 --> + * + * UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) + * contour in the twilight zone, namely contour number + * zero which includes all points of it. + */ + static void + Ins_SHC( TT_ExecContext exc, + FT_Long* args ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, dy; + + FT_UShort contour, bounds; + FT_UShort start, limit, i; + + + contour = (FT_UShort)args[0]; + bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours; + + if ( BOUNDS( contour, bounds ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + if ( contour == 0 ) + start = 0; + else + start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point; + + /* we use the number of points if in the twilight zone */ + if ( exc->GS.gep2 == 0 ) + limit = exc->zp2.n_points; + else + limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point; + + for ( i = start; i < limit; i++ ) + { + if ( zp.cur != exc->zp2.cur || refp != i ) + Move_Zp2_Point( exc, i, dx, dy, TRUE ); + } + } + + + /************************************************************************** + * + * SHZ[a]: SHift Zone + * Opcode range: 0x36-37 + * Stack: uint32 --> + */ + static void + Ins_SHZ( TT_ExecContext exc, + FT_Long* args ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + + FT_UShort limit, i; + + + if ( BOUNDS( args[0], 2 ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + return; + + /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ + /* Twilight zone has no real contours, so use `n_points'. */ + /* Normal zone's `n_points' includes phantoms, so must */ + /* use end of last contour. */ + if ( exc->GS.gep2 == 0 ) + limit = exc->zp2.n_points; + else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) + limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; + else + limit = 0; + + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ + for ( i = 0; i < limit; i++ ) + { + if ( zp.cur != exc->zp2.cur || refp != i ) + Move_Zp2_Point( exc, i, dx, dy, FALSE ); + } + } + + + /************************************************************************** + * + * SHPIX[]: SHift points by a PIXel amount + * Opcode range: 0x38 + * Stack: f26.6 uint32... --> + */ + static void + Ins_SHPIX( TT_ExecContext exc, + FT_Long* args ) + { + FT_F26Dot6 dx, dy; + FT_UShort point; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); +#endif + + + + if ( exc->top < exc->GS.loop + 1 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); + dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + /* Special case: allow SHPIX to move points in the twilight zone. */ + /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */ + /* fonts such as older versions of Rokkitt and DTL Argo T Light */ + /* that would glitch severely after calling ALIGNRP after a */ + /* blocked SHPIX. */ + if ( in_twilight || + ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) + Move_Zp2_Point( exc, point, 0, dy, TRUE ); + } + else +#endif + Move_Zp2_Point( exc, point, dx, dy, TRUE ); + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * MSIRP[a]: Move Stack Indirect Relative Position + * Opcode range: 0x3A-0x3B + * Stack: f26.6 uint32 --> + */ + static void + Ins_MSIRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point = 0; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep1 == 0 ) + { + exc->zp1.org[point] = exc->zp0.org[exc->GS.rp0]; + exc->func_move_orig( exc, &exc->zp1, point, args[1] ); + exc->zp1.cur[point] = exc->zp1.org[point]; + } + + distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( args[1], distance ) ); + + exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; + + if ( ( exc->opcode & 1 ) != 0 ) + exc->GS.rp0 = point; + } + + + /************************************************************************** + * + * MDAP[a]: Move Direct Absolute Point + * Opcode range: 0x2E-0x2F + * Stack: uint32 --> + */ + static void + Ins_MDAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_F26Dot6 cur_dist; + FT_F26Dot6 distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + if ( ( exc->opcode & 1 ) != 0 ) + { + cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); + distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist ); + } + else + distance = 0; + + exc->func_move( exc, &exc->zp0, point, distance ); + + exc->GS.rp0 = point; + exc->GS.rp1 = point; + } + + + /************************************************************************** + * + * MIAP[a]: Move Indirect Absolute Point + * Opcode range: 0x3E-0x3F + * Stack: uint32 uint32 --> + */ + static void + Ins_MIAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong cvtEntry; + FT_UShort point; + FT_F26Dot6 distance; + FT_F26Dot6 org_dist; + + + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) || + BOUNDSL( cvtEntry, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* UNDOCUMENTED! */ + /* */ + /* The behaviour of an MIAP instruction is quite different when used */ + /* in the twilight zone. */ + /* */ + /* First, no control value cut-in test is performed as it would fail */ + /* anyway. Second, the original point, i.e. (org_x,org_y) of */ + /* zp0.point, is set to the absolute, unrounded distance found in the */ + /* CVT. */ + /* */ + /* This is used in the CVT programs of the Microsoft fonts Arial, */ + /* Times, etc., in order to re-adjust some key font heights. It */ + /* allows the use of the IP instruction in the twilight zone, which */ + /* otherwise would be invalid according to the specification. */ + /* */ + /* We implement it with a special sequence for the twilight zone. */ + /* This is a bad hack, but it seems to work. */ + /* */ + /* Confirmed by Greg Hitchcock. */ + + distance = exc->func_read_cvt( exc, cvtEntry ); + + if ( exc->GS.gep0 == 0 ) /* If in twilight zone */ + { + exc->zp0.org[point].x = TT_MulFix14( distance, + exc->GS.freeVector.x ); + exc->zp0.org[point].y = TT_MulFix14( distance, + exc->GS.freeVector.y ); + exc->zp0.cur[point] = exc->zp0.org[point]; + } + + org_dist = FAST_PROJECT( &exc->zp0.cur[point] ); + + if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ + { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + FT_F26Dot6 delta; + + + delta = SUB_LONG( distance, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) + distance = org_dist; + + distance = exc->func_round( exc, distance, 3 ); + } + + exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); + + Fail: + exc->GS.rp0 = point; + exc->GS.rp1 = point; + } + + + /************************************************************************** + * + * MDRP[abcde]: Move Direct Relative Point + * Opcode range: 0xC0-0xDF + * Stack: uint32 --> + */ + static void + Ins_MDRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point = 0; + FT_F26Dot6 org_dist, distance; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* XXX: Is there some undocumented feature while in the */ + /* twilight zone? */ + + /* XXX: UNDOCUMENTED: twilight zone special case */ + + if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 ) + { + FT_Vector* vec1 = &exc->zp1.org[point]; + FT_Vector* vec2 = &exc->zp0.org[exc->GS.rp0]; + + + org_dist = DUALPROJ( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = &exc->zp1.orus[point]; + FT_Vector* vec2 = &exc->zp0.orus[exc->GS.rp0]; + + + if ( exc->metrics.x_scale == exc->metrics.y_scale ) + { + /* this should be faster */ + org_dist = DUALPROJ( vec1, vec2 ); + org_dist = FT_MulFix( org_dist, exc->metrics.x_scale ); + } + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ), + exc->metrics.y_scale ); + + org_dist = FAST_DUALPROJ( &vec ); + } + } + + /* single width cut-in test */ + + /* |org_dist - single_width_value| < single_width_cutin */ + if ( exc->GS.single_width_cutin > 0 && + org_dist < exc->GS.single_width_value + + exc->GS.single_width_cutin && + org_dist > exc->GS.single_width_value - + exc->GS.single_width_cutin ) + { + if ( org_dist >= 0 ) + org_dist = exc->GS.single_width_value; + else + org_dist = -exc->GS.single_width_value; + } + + /* round flag */ + + if ( ( exc->opcode & 4 ) != 0 ) + { + distance = exc->func_round( exc, org_dist, exc->opcode & 3 ); + } + else + distance = Round_None( exc, org_dist, exc->opcode & 3 ); + + /* minimum distance flag */ + + if ( ( exc->opcode & 8 ) != 0 ) + { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); + } + } + + /* now move the point */ + + org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) ); + + Fail: + exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; + + if ( ( exc->opcode & 16 ) != 0 ) + exc->GS.rp0 = point; + } + + + /************************************************************************** + * + * MIRP[abcde]: Move Indirect Relative Point + * Opcode range: 0xE0-0xFF + * Stack: int32? uint32 --> + */ + static void + Ins_MIRP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_ULong cvtEntry; + + FT_F26Dot6 cvt_dist, + distance, + cur_dist, + org_dist; + + FT_F26Dot6 delta; + + + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) ); + + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + + if ( BOUNDS( point, exc->zp1.n_points ) || + BOUNDSL( cvtEntry, exc->cvtSize + 1 ) || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( !cvtEntry ) + cvt_dist = 0; + else + cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 ); + + /* single width test */ + + delta = SUB_LONG( cvt_dist, exc->GS.single_width_value ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta < exc->GS.single_width_cutin ) + { + if ( cvt_dist >= 0 ) + cvt_dist = exc->GS.single_width_value; + else + cvt_dist = -exc->GS.single_width_value; + } + + /* UNDOCUMENTED! The MS rasterizer does that with */ + /* twilight points (confirmed by Greg Hitchcock) */ + if ( exc->GS.gep1 == 0 ) + { + exc->zp1.org[point].x = ADD_LONG( + exc->zp0.org[exc->GS.rp0].x, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.x ) ); + exc->zp1.org[point].y = ADD_LONG( + exc->zp0.org[exc->GS.rp0].y, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.y ) ); + exc->zp1.cur[point] = exc->zp1.org[point]; + } + + org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] ); + cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] ); + + /* auto-flip test */ + + if ( exc->GS.auto_flip ) + { + if ( ( org_dist ^ cvt_dist ) < 0 ) + cvt_dist = NEG_LONG( cvt_dist ); + } + + /* control value cut-in and round */ + + if ( ( exc->opcode & 4 ) != 0 ) + { + /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ + /* refer to the same zone. */ + + if ( exc->GS.gep0 == exc->GS.gep1 ) + { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + + + /* XXX: According to Greg Hitchcock, the following wording is */ + /* the right one: */ + /* */ + /* When the absolute difference between the value in */ + /* the table [CVT] and the measurement directly from */ + /* the outline is _greater_ than the cut_in value, the */ + /* outline measurement is used. */ + /* */ + /* This is from `instgly.doc'. The description in */ + /* `ttinst2.doc', version 1.66, is thus incorrect since */ + /* it implies `>=' instead of `>'. */ + + delta = SUB_LONG( cvt_dist, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) + cvt_dist = org_dist; + } + + distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 ); + } + else + distance = Round_None( exc, cvt_dist, exc->opcode & 3 ); + + /* minimum distance test */ + + if ( ( exc->opcode & 8 ) != 0 ) + { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); + } + } + + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( distance, cur_dist ) ); + + Fail: + exc->GS.rp1 = exc->GS.rp0; + + if ( ( exc->opcode & 16 ) != 0 ) + exc->GS.rp0 = point; + + exc->GS.rp2 = point; + } + + + /************************************************************************** + * + * ALIGNRP[]: ALIGN Relative Point + * Opcode range: 0x3C + * Stack: uint32 uint32... --> + */ + static void + Ins_ALIGNRP( TT_ExecContext exc ) + { + FT_UShort point; + FT_F26Dot6 distance; + + + if ( exc->top < exc->GS.loop || + BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + while ( exc->GS.loop > 0 ) + { + exc->args--; + + point = (FT_UShort)exc->stack[exc->args]; + + if ( BOUNDS( point, exc->zp1.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + { + distance = PROJECT( exc->zp1.cur + point, + exc->zp0.cur + exc->GS.rp0 ); + + exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) ); + } + + exc->GS.loop--; + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * ISECT[]: moves point to InterSECTion + * Opcode range: 0x0F + * Stack: 5 * uint32 --> + */ + static void + Ins_ISECT( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point, + a0, a1, + b0, b1; + + FT_F26Dot6 discriminant, dotproduct; + + FT_F26Dot6 dx, dy, + dax, day, + dbx, dby; + + FT_F26Dot6 val; + + FT_Vector R; + + + point = (FT_UShort)args[0]; + + a0 = (FT_UShort)args[1]; + a1 = (FT_UShort)args[2]; + b0 = (FT_UShort)args[3]; + b1 = (FT_UShort)args[4]; + + if ( BOUNDS( b0, exc->zp0.n_points ) || + BOUNDS( b1, exc->zp0.n_points ) || + BOUNDS( a0, exc->zp1.n_points ) || + BOUNDS( a1, exc->zp1.n_points ) || + BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + /* Cramer's rule */ + + dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x ); + dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y ); + + dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x ); + day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y ); + + dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x ); + dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y ); + + discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( day, dbx, 0x40 ) ); + dotproduct = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ), + FT_MulDiv( day, dby, 0x40 ) ); + + /* The discriminant above is actually a cross product of vectors */ + /* da and db. Together with the dot product, they can be used as */ + /* surrogates for sine and cosine of the angle between the vectors. */ + /* Indeed, */ + /* dotproduct = |da||db|cos(angle) */ + /* discriminant = |da||db|sin(angle) . */ + /* We use these equations to reject grazing intersections by */ + /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */ + if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) ) + { + val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( dy, dbx, 0x40 ) ); + + R.x = FT_MulDiv( val, dax, discriminant ); + R.y = FT_MulDiv( val, day, discriminant ); + + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x ); + exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y ); + } + else + { + /* else, take the middle of the middles of A and B */ + + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ), + ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4; + exc->zp2.cur[point].y = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ), + ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4; + } + + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; + } + + + /************************************************************************** + * + * ALIGNPTS[]: ALIGN PoinTS + * Opcode range: 0x27 + * Stack: uint32 uint32 --> + */ + static void + Ins_ALIGNPTS( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort p1, p2; + FT_F26Dot6 distance; + + + p1 = (FT_UShort)args[0]; + p2 = (FT_UShort)args[1]; + + if ( BOUNDS( p1, exc->zp1.n_points ) || + BOUNDS( p2, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2; + + exc->func_move( exc, &exc->zp1, p1, distance ); + exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) ); + } + + + /************************************************************************** + * + * IP[]: Interpolate Point + * Opcode range: 0x39 + * Stack: uint32... --> + */ + + /* SOMETIMES, DUMBER CODE IS BETTER CODE */ + + static void + Ins_IP( TT_ExecContext exc ) + { + FT_F26Dot6 old_range, cur_range; + FT_Vector* orus_base; + FT_Vector* cur_base; + FT_Int twilight; + + + if ( exc->top < exc->GS.loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + /* + * We need to deal in a special way with the twilight zone. + * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0), + * for every n. + */ + twilight = ( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); + + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + goto Fail; + } + + if ( twilight ) + orus_base = &exc->zp0.org[exc->GS.rp1]; + else + orus_base = &exc->zp0.orus[exc->GS.rp1]; + + cur_base = &exc->zp0.cur[exc->GS.rp1]; + + /* XXX: There are some glyphs in some braindead but popular */ + /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ + /* calling IP[] with bad values of rp[12]. */ + /* Do something sane when this odd thing happens. */ + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) || + BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) + { + old_range = 0; + cur_range = 0; + } + else + { + if ( twilight ) + old_range = DUALPROJ( &exc->zp1.org[exc->GS.rp2], orus_base ); + else if ( exc->metrics.x_scale == exc->metrics.y_scale ) + old_range = DUALPROJ( &exc->zp1.orus[exc->GS.rp2], orus_base ); + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x, + orus_base->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y, + orus_base->y ), + exc->metrics.y_scale ); + + old_range = FAST_DUALPROJ( &vec ); + } + + cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base ); + } + + for ( ; exc->GS.loop > 0; exc->GS.loop-- ) + { + FT_UInt point = (FT_UInt)exc->stack[--exc->args]; + FT_F26Dot6 org_dist, cur_dist, new_dist; + + + /* check point bounds */ + if ( BOUNDS( point, exc->zp2.n_points ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + continue; + } + + if ( twilight ) + org_dist = DUALPROJ( &exc->zp2.org[point], orus_base ); + else if ( exc->metrics.x_scale == exc->metrics.y_scale ) + org_dist = DUALPROJ( &exc->zp2.orus[point], orus_base ); + else + { + FT_Vector vec; + + + vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x, + orus_base->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y, + orus_base->y ), + exc->metrics.y_scale ); + + org_dist = FAST_DUALPROJ( &vec ); + } + + cur_dist = PROJECT( &exc->zp2.cur[point], cur_base ); + + if ( org_dist ) + { + if ( old_range ) + new_dist = FT_MulDiv( org_dist, cur_range, old_range ); + else + { + /* This is the same as what MS does for the invalid case: */ + /* */ + /* delta = (Original_Pt - Original_RP1) - */ + /* (Current_Pt - Current_RP1) ; */ + /* */ + /* In FreeType speak: */ + /* */ + /* delta = org_dist - cur_dist . */ + /* */ + /* We move `point' by `new_dist - cur_dist' after leaving */ + /* this block, thus we have */ + /* */ + /* new_dist - cur_dist = delta , */ + /* new_dist - cur_dist = org_dist - cur_dist , */ + /* new_dist = org_dist . */ + + new_dist = org_dist; + } + } + else + new_dist = 0; + + exc->func_move( exc, + &exc->zp2, + (FT_UShort)point, + SUB_LONG( new_dist, cur_dist ) ); + } + + Fail: + exc->GS.loop = 1; + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * UTP[a]: UnTouch Point + * Opcode range: 0x29 + * Stack: uint32 --> + */ + static void + Ins_UTP( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort point; + FT_Byte mask; + + + point = (FT_UShort)args[0]; + + if ( BOUNDS( point, exc->zp0.n_points ) ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return; + } + + mask = 0xFF; + + if ( exc->GS.freeVector.x != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_X; + + if ( exc->GS.freeVector.y != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_Y; + + exc->zp0.tags[point] &= mask; + } + + + /* Local variables for Ins_IUP: */ + typedef struct IUP_WorkerRec_ + { + FT_Vector* orgs; /* original and current coordinate */ + FT_Vector* curs; /* arrays */ + FT_Vector* orus; + FT_UInt max_points; + + } IUP_WorkerRec, *IUP_Worker; + + + static void + iup_worker_shift_( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt p ) + { + FT_UInt i; + FT_F26Dot6 dx; + + + dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x ); + if ( dx != 0 ) + { + for ( i = p1; i < p; i++ ) + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); + + for ( i = p + 1; i <= p2; i++ ) + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); + } + } + + + static void + iup_worker_interpolate_( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2 ) + { + FT_UInt i; + FT_F26Dot6 orus1, orus2, org1, org2, cur1, cur2, delta1, delta2; + + + if ( p1 > p2 ) + return; + + if ( BOUNDS( ref1, worker->max_points ) || + BOUNDS( ref2, worker->max_points ) ) + return; + + orus1 = worker->orus[ref1].x; + orus2 = worker->orus[ref2].x; + + if ( orus1 > orus2 ) + { + FT_F26Dot6 tmp_o; + FT_UInt tmp_r; + + + tmp_o = orus1; + orus1 = orus2; + orus2 = tmp_o; + + tmp_r = ref1; + ref1 = ref2; + ref2 = tmp_r; + } + + org1 = worker->orgs[ref1].x; + org2 = worker->orgs[ref2].x; + cur1 = worker->curs[ref1].x; + cur2 = worker->curs[ref2].x; + delta1 = SUB_LONG( cur1, org1 ); + delta2 = SUB_LONG( cur2, org2 ); + + if ( cur1 == cur2 || orus1 == orus2 ) + { + + /* trivial snap or shift of untouched points */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x = ADD_LONG( x, delta1 ); + + else if ( x >= org2 ) + x = ADD_LONG( x, delta2 ); + + else + x = cur1; + + worker->curs[i].x = x; + } + } + else + { + FT_Fixed scale = 0; + FT_Bool scale_valid = 0; + + + /* interpolation */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + + if ( x <= org1 ) + x = ADD_LONG( x, delta1 ); + + else if ( x >= org2 ) + x = ADD_LONG( x, delta2 ); + + else + { + if ( !scale_valid ) + { + scale_valid = 1; + scale = FT_DivFix( SUB_LONG( cur2, cur1 ), + SUB_LONG( orus2, orus1 ) ); + } + + x = ADD_LONG( cur1, + FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ), + scale ) ); + } + worker->curs[i].x = x; + } + } + } + + + /************************************************************************** + * + * IUP[a]: Interpolate Untouched Points + * Opcode range: 0x30-0x31 + * Stack: --> + */ + static void + Ins_IUP( TT_ExecContext exc ) + { + IUP_WorkerRec V; + FT_Byte mask; + + FT_UInt first_point; /* first point of contour */ + FT_UInt end_point; /* end point (last+1) of contour */ + + FT_UInt first_touched; /* first touched point in contour */ + FT_UInt cur_touched; /* current touched point in contour */ + + FT_UInt point; /* current point */ + FT_Short contour; /* current contour */ + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* Allow IUP until it has been called on both axes. Immediately */ + /* return on subsequent ones. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( exc->iupx_called && exc->iupy_called ) + return; + + if ( exc->opcode & 1 ) + exc->iupx_called = TRUE; + else + exc->iupy_called = TRUE; + } +#endif + + /* ignore empty outlines */ + if ( exc->pts.n_contours == 0 ) + return; + + if ( exc->opcode & 1 ) + { + mask = FT_CURVE_TAG_TOUCH_X; + V.orgs = exc->pts.org; + V.curs = exc->pts.cur; + V.orus = exc->pts.orus; + } + else + { + mask = FT_CURVE_TAG_TOUCH_Y; + V.orgs = (FT_Vector*)( (FT_Pos*)exc->pts.org + 1 ); + V.curs = (FT_Vector*)( (FT_Pos*)exc->pts.cur + 1 ); + V.orus = (FT_Vector*)( (FT_Pos*)exc->pts.orus + 1 ); + } + V.max_points = exc->pts.n_points; + + contour = 0; + point = 0; + + do + { + end_point = exc->pts.contours[contour] - exc->pts.first_point; + first_point = point; + + if ( BOUNDS( end_point, exc->pts.n_points ) ) + end_point = exc->pts.n_points - 1; + + while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 ) + point++; + + if ( point <= end_point ) + { + first_touched = point; + cur_touched = point; + + point++; + + while ( point <= end_point ) + { + if ( ( exc->pts.tags[point] & mask ) != 0 ) + { + iup_worker_interpolate_( &V, + cur_touched + 1, + point - 1, + cur_touched, + point ); + cur_touched = point; + } + + point++; + } + + if ( cur_touched == first_touched ) + iup_worker_shift_( &V, first_point, end_point, cur_touched ); + else + { + iup_worker_interpolate_( &V, + (FT_UShort)( cur_touched + 1 ), + end_point, + cur_touched, + first_touched ); + + if ( first_touched > 0 ) + iup_worker_interpolate_( &V, + first_point, + first_touched - 1, + cur_touched, + first_touched ); + } + } + contour++; + } while ( contour < exc->pts.n_contours ); + } + + + /************************************************************************** + * + * DELTAPn[]: DELTA exceptions P1, P2, P3 + * Opcode range: 0x5D,0x71,0x72 + * Stack: uint32 (2 * uint32)... --> + */ + static void + Ins_DELTAP( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong nump, k; + FT_UShort A; + FT_ULong C, P; + FT_Long B; + + + P = (FT_ULong)exc->func_cur_ppem( exc ); + nump = (FT_ULong)args[0]; /* some points theoretically may occur more + than once, thus UShort isn't enough */ + + for ( k = 1; k <= nump; k++ ) + { + if ( exc->args < 2 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + exc->args = 0; + goto Fail; + } + + exc->args -= 2; + + A = (FT_UShort)exc->stack[exc->args + 1]; + B = exc->stack[exc->args]; + + /* XXX: Because some popular fonts contain some invalid DeltaP */ + /* instructions, we simply ignore them when the stacked */ + /* point reference is off limit, rather than returning an */ + /* error. As a delta instruction doesn't change a glyph */ + /* in great ways, this shouldn't be a problem. */ + + if ( !BOUNDS( A, exc->zp0.n_points ) ) + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( exc->opcode ) + { + case 0x5D: + break; + + case 0x71: + C += 16; + break; + + case 0x72: + C += 32; + break; + } + + C += exc->GS.delta_base; + + if ( P == C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B *= 1L << ( 6 - exc->GS.delta_shift ); + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility */ + /* mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) + exc->func_move( exc, &exc->zp0, A, B ); + } + else +#endif + exc->func_move( exc, &exc->zp0, A, B ); + } + } + else + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + + Fail: + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * DELTACn[]: DELTA exceptions C1, C2, C3 + * Opcode range: 0x73,0x74,0x75 + * Stack: uint32 (2 * uint32)... --> + */ + static void + Ins_DELTAC( TT_ExecContext exc, + FT_Long* args ) + { + FT_ULong nump, k; + FT_ULong A, C, P; + FT_Long B; + + + P = (FT_ULong)exc->func_cur_ppem( exc ); + nump = (FT_ULong)args[0]; + + for ( k = 1; k <= nump; k++ ) + { + if ( exc->args < 2 ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + exc->args = 0; + goto Fail; + } + + exc->args -= 2; + + A = (FT_ULong)exc->stack[exc->args + 1]; + B = exc->stack[exc->args]; + + if ( BOUNDSL( A, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Invalid_Reference ); + return; + } + } + else + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + + switch ( exc->opcode ) + { + case 0x73: + break; + + case 0x74: + C += 16; + break; + + case 0x75: + C += 32; + break; + } + + C += exc->GS.delta_base; + + if ( P == C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B *= 1L << ( 6 - exc->GS.delta_shift ); + + exc->func_move_cvt( exc, A, B ); + } + } + } + + Fail: + exc->new_top = exc->args; + } + + + /************************************************************************** + * + * MISC. INSTRUCTIONS + * + */ + + + /************************************************************************** + * + * GETINFO[]: GET INFOrmation + * Opcode range: 0x88 + * Stack: uint32 --> uint32 + */ + static void + Ins_GETINFO( TT_ExecContext exc, + FT_Long* args ) + { + FT_Long K; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face ); + + + K = 0; + + if ( ( args[0] & 1 ) != 0 ) + K = driver->interpreter_version; + + /********************************* + * GLYPH ROTATED + * Selector Bit: 1 + * Return Bit(s): 8 + */ + if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated ) + K |= 1 << 8; + + /********************************* + * GLYPH STRETCHED + * Selector Bit: 2 + * Return Bit(s): 9 + */ + if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched ) + K |= 1 << 9; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /********************************* + * VARIATION GLYPH + * Selector Bit: 3 + * Return Bit(s): 10 + */ + if ( (args[0] & 8 ) != 0 && exc->face->blend ) + K |= 1 << 10; +#endif + + /********************************* + * BI-LEVEL HINTING AND + * GRAYSCALE RENDERING + * Selector Bit: 5 + * Return Bit(s): 12 + */ + if ( ( args[0] & 32 ) != 0 && exc->grayscale ) + K |= 1 << 12; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Toggle the following flags only outside of monochrome mode. */ + /* Otherwise, instructions may behave weirdly and rendering results */ + /* may differ between v35 and v40 mode, e.g., in `Times New Roman */ + /* Bold Italic'. */ + if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean ) + { + /********************************* + * HINTING FOR SUBPIXEL + * Selector Bit: 6 + * Return Bit(s): 13 + * + * v40 does subpixel hinting by default. + */ + if ( ( args[0] & 64 ) != 0 ) + K |= 1 << 13; + + /********************************* + * VERTICAL LCD SUBPIXELS? + * Selector Bit: 8 + * Return Bit(s): 15 + */ + if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean ) + K |= 1 << 15; + + /********************************* + * SUBPIXEL POSITIONED? + * Selector Bit: 10 + * Return Bit(s): 17 + * + * XXX: FreeType supports it, dependent on what client does? + */ + if ( ( args[0] & 1024 ) != 0 ) + K |= 1 << 17; + + /********************************* + * SYMMETRICAL SMOOTHING + * Selector Bit: 11 + * Return Bit(s): 18 + * + * The only smoothing method FreeType supports unless someone sets + * FT_LOAD_TARGET_MONO. + */ + if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean ) + K |= 1 << 18; + + /********************************* + * CLEARTYPE HINTING AND + * GRAYSCALE RENDERING + * Selector Bit: 12 + * Return Bit(s): 19 + * + * Grayscale rendering is what FreeType does anyway unless someone + * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) + */ + if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + K |= 1 << 19; + } +#endif + + args[0] = K; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /************************************************************************** + * + * GETVARIATION[]: get normalized variation (blend) coordinates + * Opcode range: 0x91 + * Stack: --> f2.14... + * + * XXX: UNDOCUMENTED! There is no official documentation from Apple for + * this bytecode instruction. Active only if a font has GX + * variation axes. + */ + static void + Ins_GETVARIATION( TT_ExecContext exc, + FT_Long* args ) + { + FT_UInt num_axes = exc->face->blend->num_axis; + FT_Fixed* coords = exc->face->blend->normalizedcoords; + + FT_UInt i; + + + if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + if ( coords ) + { + for ( i = 0; i < num_axes; i++ ) + args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */ + } + else + { + for ( i = 0; i < num_axes; i++ ) + args[i] = 0; + } + } + + + /************************************************************************** + * + * GETDATA[]: no idea what this is good for + * Opcode range: 0x92 + * Stack: --> 17 + * + * XXX: UNDOCUMENTED! There is no documentation from Apple for this + * very weird bytecode instruction. + */ + static void + Ins_GETDATA( FT_Long* args ) + { + args[0] = 17; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static void + Ins_UNKNOWN( TT_ExecContext exc ) + { + TT_DefRecord* def = exc->IDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + + + for ( ; def < limit; def++ ) + { + if ( (FT_Byte)def->opc == exc->opcode && def->active ) + { + TT_CallRec* call; + + + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + call = exc->callStack + exc->callTop++; + + call->Caller_Range = exc->curRange; + call->Caller_IP = exc->IP + 1; + call->Cur_Count = 1; + call->Def = def; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + return; + } + } + + exc->error = FT_THROW( Invalid_Opcode ); + } + + + /************************************************************************** + * + * RUN + * + * This function executes a run of opcodes. It will exit in the + * following cases: + * + * - Errors (in which case it returns FALSE). + * + * - Reaching the end of the main code range (returns TRUE). + * Reaching the end of a code range within a function call is an + * error. + * + * - After executing one single opcode, if the flag `Instruction_Trap' + * is set to TRUE (returns TRUE). + * + * On exit with TRUE, test IP < CodeSize to know whether it comes from + * an instruction trap or a normal termination. + * + * + * Note: The documented DEBUG opcode pops a value from the stack. This + * behaviour is unsupported; here a DEBUG opcode is always an + * error. + * + * + * THIS IS THE INTERPRETER'S MAIN LOOP. + * + */ + + + /* documentation is in ttinterp.h */ + + FT_EXPORT_DEF( FT_Error ) + TT_RunIns( void* exec ) + { + TT_ExecContext exc = (TT_ExecContext)exec; + + FT_ULong ins_counter = 0; /* executed instructions counter */ + FT_ULong num_twilight_points; + FT_UShort i; + + + /* We restrict the number of twilight points to a reasonable, */ + /* heuristic value to avoid slow execution of malformed bytecode. */ + num_twilight_points = FT_MAX( 30, + 2 * ( exc->pts.n_points + exc->cvtSize ) ); + if ( exc->twilight.n_points > num_twilight_points ) + { + if ( num_twilight_points > 0xFFFFU ) + num_twilight_points = 0xFFFFU; + + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); + FT_TRACE5(( " from %d to the more reasonable value %ld\n", + exc->twilight.n_points, + num_twilight_points )); + exc->twilight.n_points = (FT_UShort)num_twilight_points; + } + + /* Set up loop detectors. We restrict the number of LOOPCALL loops */ + /* and the number of JMPR, JROT, and JROF calls with a negative */ + /* argument to values that depend on various parameters like the */ + /* size of the CVT table or the number of points in the current */ + /* glyph (if applicable). */ + /* */ + /* The idea is that in real-world bytecode you either iterate over */ + /* all CVT entries (in the `prep' table), or over all points (or */ + /* contours, in the `glyf' table) of a glyph, and such iterations */ + /* don't happen very often. */ + exc->loopcall_counter = 0; + exc->neg_jump_counter = 0; + + /* The maximum values are heuristic. */ + if ( exc->pts.n_points ) + exc->loopcall_counter_max = FT_MAX( 50, + 10 * exc->pts.n_points ) + + FT_MAX( 50, + exc->cvtSize / 10 ); + else + exc->loopcall_counter_max = 300 + 22 * exc->cvtSize; + + /* as a protection against an unreasonable number of CVT entries */ + /* we assume at most 100 control values per glyph for the counter */ + if ( exc->loopcall_counter_max > + 100 * (FT_ULong)exc->face->root.num_glyphs ) + exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs; + + FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" + " to %ld\n", exc->loopcall_counter_max )); + + exc->neg_jump_counter_max = exc->loopcall_counter_max; + FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" + " to %ld\n", exc->neg_jump_counter_max )); + + /* set PPEM and CVT functions */ + exc->tt_metrics.ratio = 0; + if ( exc->metrics.x_ppem != exc->metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + exc->func_cur_ppem = Current_Ppem_Stretched; + exc->func_read_cvt = Read_CVT_Stretched; + exc->func_write_cvt = Write_CVT_Stretched; + exc->func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + exc->func_cur_ppem = Current_Ppem; + exc->func_read_cvt = Read_CVT; + exc->func_write_cvt = Write_CVT; + exc->func_move_cvt = Move_CVT; + } + + exc->iniRange = exc->curRange; + + Compute_Funcs( exc ); + Compute_Round( exc, (FT_Byte)exc->GS.round_state ); + + /* These flags cancel execution of some opcodes after IUP is called */ +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + exc->iupx_called = FALSE; + exc->iupy_called = FALSE; +#endif + + do + { + exc->opcode = exc->code[exc->IP]; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[trace_ttinterp] >= 6 ) + { + FT_Long cnt = FT_MIN( 8, exc->top ); + FT_Long n; + + + /* if tracing level is 7, show current code position */ + /* and the first few stack elements also */ + FT_TRACE6(( " " )); + FT_TRACE7(( "%06ld ", exc->IP )); + FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 )); + FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A' + ? 2 + : 12 - ( *opcode_name[exc->opcode] - '0' ), + "#" )); + for ( n = 1; n <= cnt; n++ ) + FT_TRACE7(( " %ld", exc->stack[exc->top - n] )); + FT_TRACE6(( "\n" )); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + if ( ( exc->length = opcode_length[exc->opcode] ) < 0 ) + { + if ( exc->IP + 1 >= exc->codeSize ) + goto LErrorCodeOverflow_; + + exc->length = 2 - exc->length * exc->code[exc->IP + 1]; + } + + if ( exc->IP + exc->length > exc->codeSize ) + goto LErrorCodeOverflow_; + + /* First, let's check for empty stack and overflow */ + exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 ); + + /* `args' is the top of the stack once arguments have been popped. */ + /* One can also interpret it as the index of the last argument. */ + if ( exc->args < 0 ) + { + if ( exc->pedantic_hinting ) + { + exc->error = FT_THROW( Too_Few_Arguments ); + goto LErrorLabel_; + } + + /* push zeroes onto the stack */ + for ( i = 0; i < Pop_Push_Count[exc->opcode] >> 4; i++ ) + exc->stack[i] = 0; + exc->args = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( exc->opcode == 0x91 ) + { + /* this is very special: GETVARIATION returns */ + /* a variable number of arguments */ + + /* it is the job of the application to `activate' GX handling, */ + /* that is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + exc->new_top = exc->args + exc->face->blend->num_axis; + } + else +#endif + exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); + + /* `new_top' is the new top of the stack, after the instruction's */ + /* execution. `top' will be set to `new_top' after the `switch' */ + /* statement. */ + if ( exc->new_top > exc->stackSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + goto LErrorLabel_; + } + + exc->step_ins = TRUE; + exc->error = FT_Err_Ok; + + { + FT_Long* args = exc->stack + exc->args; + FT_Byte opcode = exc->opcode; + + + switch ( opcode ) + { + case 0x00: /* SVTCA y */ + case 0x01: /* SVTCA x */ + case 0x02: /* SPvTCA y */ + case 0x03: /* SPvTCA x */ + case 0x04: /* SFvTCA y */ + case 0x05: /* SFvTCA x */ + Ins_SxyTCA( exc ); + break; + + case 0x06: /* SPvTL // */ + case 0x07: /* SPvTL + */ + Ins_SPVTL( exc, args ); + break; + + case 0x08: /* SFvTL // */ + case 0x09: /* SFvTL + */ + Ins_SFVTL( exc, args ); + break; + + case 0x0A: /* SPvFS */ + Ins_SPVFS( exc, args ); + break; + + case 0x0B: /* SFvFS */ + Ins_SFVFS( exc, args ); + break; + + case 0x0C: /* GPv */ + Ins_GPV( exc, args ); + break; + + case 0x0D: /* GFv */ + Ins_GFV( exc, args ); + break; + + case 0x0E: /* SFvTPv */ + Ins_SFVTPV( exc ); + break; + + case 0x0F: /* ISECT */ + Ins_ISECT( exc, args ); + break; + + case 0x10: /* SRP0 */ + Ins_SRP0( exc, args ); + break; + + case 0x11: /* SRP1 */ + Ins_SRP1( exc, args ); + break; + + case 0x12: /* SRP2 */ + Ins_SRP2( exc, args ); + break; + + case 0x13: /* SZP0 */ + Ins_SZP0( exc, args ); + break; + + case 0x14: /* SZP1 */ + Ins_SZP1( exc, args ); + break; + + case 0x15: /* SZP2 */ + Ins_SZP2( exc, args ); + break; + + case 0x16: /* SZPS */ + Ins_SZPS( exc, args ); + break; + + case 0x17: /* SLOOP */ + Ins_SLOOP( exc, args ); + break; + + case 0x18: /* RTG */ + Ins_RTG( exc ); + break; + + case 0x19: /* RTHG */ + Ins_RTHG( exc ); + break; + + case 0x1A: /* SMD */ + Ins_SMD( exc, args ); + break; + + case 0x1B: /* ELSE */ + Ins_ELSE( exc ); + break; + + case 0x1C: /* JMPR */ + Ins_JMPR( exc, args ); + break; + + case 0x1D: /* SCVTCI */ + Ins_SCVTCI( exc, args ); + break; + + case 0x1E: /* SSWCI */ + Ins_SSWCI( exc, args ); + break; + + case 0x1F: /* SSW */ + Ins_SSW( exc, args ); + break; + + case 0x20: /* DUP */ + Ins_DUP( args ); + break; + + case 0x21: /* POP */ + Ins_POP(); + break; + + case 0x22: /* CLEAR */ + Ins_CLEAR( exc ); + break; + + case 0x23: /* SWAP */ + Ins_SWAP( args ); + break; + + case 0x24: /* DEPTH */ + Ins_DEPTH( exc, args ); + break; + + case 0x25: /* CINDEX */ + Ins_CINDEX( exc, args ); + break; + + case 0x26: /* MINDEX */ + Ins_MINDEX( exc, args ); + break; + + case 0x27: /* ALIGNPTS */ + Ins_ALIGNPTS( exc, args ); + break; + + case 0x28: /* RAW */ + Ins_UNKNOWN( exc ); + break; + + case 0x29: /* UTP */ + Ins_UTP( exc, args ); + break; + + case 0x2A: /* LOOPCALL */ + Ins_LOOPCALL( exc, args ); + break; + + case 0x2B: /* CALL */ + Ins_CALL( exc, args ); + break; + + case 0x2C: /* FDEF */ + Ins_FDEF( exc, args ); + break; + + case 0x2D: /* ENDF */ + Ins_ENDF( exc ); + break; + + case 0x2E: /* MDAP */ + case 0x2F: /* MDAP */ + Ins_MDAP( exc, args ); + break; + + case 0x30: /* IUP */ + case 0x31: /* IUP */ + Ins_IUP( exc ); + break; + + case 0x32: /* SHP */ + case 0x33: /* SHP */ + Ins_SHP( exc ); + break; + + case 0x34: /* SHC */ + case 0x35: /* SHC */ + Ins_SHC( exc, args ); + break; + + case 0x36: /* SHZ */ + case 0x37: /* SHZ */ + Ins_SHZ( exc, args ); + break; + + case 0x38: /* SHPIX */ + Ins_SHPIX( exc, args ); + break; + + case 0x39: /* IP */ + Ins_IP( exc ); + break; + + case 0x3A: /* MSIRP */ + case 0x3B: /* MSIRP */ + Ins_MSIRP( exc, args ); + break; + + case 0x3C: /* AlignRP */ + Ins_ALIGNRP( exc ); + break; + + case 0x3D: /* RTDG */ + Ins_RTDG( exc ); + break; + + case 0x3E: /* MIAP */ + case 0x3F: /* MIAP */ + Ins_MIAP( exc, args ); + break; + + case 0x40: /* NPUSHB */ + Ins_NPUSHB( exc, args ); + break; + + case 0x41: /* NPUSHW */ + Ins_NPUSHW( exc, args ); + break; + + case 0x42: /* WS */ + Ins_WS( exc, args ); + break; + + case 0x43: /* RS */ + Ins_RS( exc, args ); + break; + + case 0x44: /* WCVTP */ + Ins_WCVTP( exc, args ); + break; + + case 0x45: /* RCVT */ + Ins_RCVT( exc, args ); + break; + + case 0x46: /* GC */ + case 0x47: /* GC */ + Ins_GC( exc, args ); + break; + + case 0x48: /* SCFS */ + Ins_SCFS( exc, args ); + break; + + case 0x49: /* MD */ + case 0x4A: /* MD */ + Ins_MD( exc, args ); + break; + + case 0x4B: /* MPPEM */ + Ins_MPPEM( exc, args ); + break; + + case 0x4C: /* MPS */ + Ins_MPS( exc, args ); + break; + + case 0x4D: /* FLIPON */ + Ins_FLIPON( exc ); + break; + + case 0x4E: /* FLIPOFF */ + Ins_FLIPOFF( exc ); + break; + + case 0x4F: /* DEBUG */ + Ins_DEBUG( exc ); + break; + + case 0x50: /* LT */ + Ins_LT( args ); + break; + + case 0x51: /* LTEQ */ + Ins_LTEQ( args ); + break; + + case 0x52: /* GT */ + Ins_GT( args ); + break; + + case 0x53: /* GTEQ */ + Ins_GTEQ( args ); + break; + + case 0x54: /* EQ */ + Ins_EQ( args ); + break; + + case 0x55: /* NEQ */ + Ins_NEQ( args ); + break; + + case 0x56: /* ODD */ + Ins_ODD( exc, args ); + break; + + case 0x57: /* EVEN */ + Ins_EVEN( exc, args ); + break; + + case 0x58: /* IF */ + Ins_IF( exc, args ); + break; + + case 0x59: /* EIF */ + Ins_EIF(); + break; + + case 0x5A: /* AND */ + Ins_AND( args ); + break; + + case 0x5B: /* OR */ + Ins_OR( args ); + break; + + case 0x5C: /* NOT */ + Ins_NOT( args ); + break; + + case 0x5D: /* DELTAP1 */ + Ins_DELTAP( exc, args ); + break; + + case 0x5E: /* SDB */ + Ins_SDB( exc, args ); + break; + + case 0x5F: /* SDS */ + Ins_SDS( exc, args ); + break; + + case 0x60: /* ADD */ + Ins_ADD( args ); + break; + + case 0x61: /* SUB */ + Ins_SUB( args ); + break; + + case 0x62: /* DIV */ + Ins_DIV( exc, args ); + break; + + case 0x63: /* MUL */ + Ins_MUL( args ); + break; + + case 0x64: /* ABS */ + Ins_ABS( args ); + break; + + case 0x65: /* NEG */ + Ins_NEG( args ); + break; + + case 0x66: /* FLOOR */ + Ins_FLOOR( args ); + break; + + case 0x67: /* CEILING */ + Ins_CEILING( args ); + break; + + case 0x68: /* ROUND */ + case 0x69: /* ROUND */ + case 0x6A: /* ROUND */ + case 0x6B: /* ROUND */ + Ins_ROUND( exc, args ); + break; + + case 0x6C: /* NROUND */ + case 0x6D: /* NROUND */ + case 0x6E: /* NRRUND */ + case 0x6F: /* NROUND */ + Ins_NROUND( exc, args ); + break; + + case 0x70: /* WCVTF */ + Ins_WCVTF( exc, args ); + break; + + case 0x71: /* DELTAP2 */ + case 0x72: /* DELTAP3 */ + Ins_DELTAP( exc, args ); + break; + + case 0x73: /* DELTAC0 */ + case 0x74: /* DELTAC1 */ + case 0x75: /* DELTAC2 */ + Ins_DELTAC( exc, args ); + break; + + case 0x76: /* SROUND */ + Ins_SROUND( exc, args ); + break; + + case 0x77: /* S45Round */ + Ins_S45ROUND( exc, args ); + break; + + case 0x78: /* JROT */ + Ins_JROT( exc, args ); + break; + + case 0x79: /* JROF */ + Ins_JROF( exc, args ); + break; + + case 0x7A: /* ROFF */ + Ins_ROFF( exc ); + break; + + case 0x7B: /* ???? */ + Ins_UNKNOWN( exc ); + break; + + case 0x7C: /* RUTG */ + Ins_RUTG( exc ); + break; + + case 0x7D: /* RDTG */ + Ins_RDTG( exc ); + break; + + case 0x7E: /* SANGW */ + Ins_SANGW(); + break; + + case 0x7F: /* AA */ + Ins_AA(); + break; + + case 0x80: /* FLIPPT */ + Ins_FLIPPT( exc ); + break; + + case 0x81: /* FLIPRGON */ + Ins_FLIPRGON( exc, args ); + break; + + case 0x82: /* FLIPRGOFF */ + Ins_FLIPRGOFF( exc, args ); + break; + + case 0x83: /* UNKNOWN */ + case 0x84: /* UNKNOWN */ + Ins_UNKNOWN( exc ); + break; + + case 0x85: /* SCANCTRL */ + Ins_SCANCTRL( exc, args ); + break; + + case 0x86: /* SDPvTL */ + case 0x87: /* SDPvTL */ + Ins_SDPVTL( exc, args ); + break; + + case 0x88: /* GETINFO */ + Ins_GETINFO( exc, args ); + break; + + case 0x89: /* IDEF */ + Ins_IDEF( exc, args ); + break; + + case 0x8A: /* ROLL */ + Ins_ROLL( args ); + break; + + case 0x8B: /* MAX */ + Ins_MAX( args ); + break; + + case 0x8C: /* MIN */ + Ins_MIN( args ); + break; + + case 0x8D: /* SCANTYPE */ + Ins_SCANTYPE( exc, args ); + break; + + case 0x8E: /* INSTCTRL */ + Ins_INSTCTRL( exc, args ); + break; + + case 0x8F: /* ADJUST */ + case 0x90: /* ADJUST */ + Ins_UNKNOWN( exc ); + break; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + case 0x91: + /* it is the job of the application to `activate' GX handling, */ + /* that is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + Ins_GETVARIATION( exc, args ); + else + Ins_UNKNOWN( exc ); + break; + + case 0x92: + /* there is at least one MS font (LaoUI.ttf version 5.01) that */ + /* uses IDEFs for 0x91 and 0x92; for this reason we activate */ + /* GETDATA for GX fonts only, similar to GETVARIATION */ + if ( exc->face->blend ) + Ins_GETDATA( args ); + else + Ins_UNKNOWN( exc ); + break; +#endif + + default: + if ( opcode >= 0xE0 ) + Ins_MIRP( exc, args ); + else if ( opcode >= 0xC0 ) + Ins_MDRP( exc, args ); + else if ( opcode >= 0xB8 ) + Ins_PUSHW( exc, args ); + else if ( opcode >= 0xB0 ) + Ins_PUSHB( exc, args ); + else + Ins_UNKNOWN( exc ); + } + } + + if ( exc->error ) + { + switch ( exc->error ) + { + /* looking for redefined instructions */ + case FT_ERR( Invalid_Opcode ): + { + TT_DefRecord* def = exc->IDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + + + for ( ; def < limit; def++ ) + { + if ( def->active && exc->opcode == (FT_Byte)def->opc ) + { + TT_CallRec* callrec; + + + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Invalid_Reference ); + goto LErrorLabel_; + } + + callrec = &exc->callStack[exc->callTop]; + + callrec->Caller_Range = exc->curRange; + callrec->Caller_IP = exc->IP + 1; + callrec->Cur_Count = 1; + callrec->Def = def; + + if ( Ins_Goto_CodeRange( exc, + def->range, + def->start ) == FAILURE ) + goto LErrorLabel_; + + goto LSuiteLabel_; + } + } + } + + exc->error = FT_THROW( Invalid_Opcode ); + goto LErrorLabel_; + +#if 0 + break; /* Unreachable code warning suppression. */ + /* Leave to remind in case a later change the editor */ + /* to consider break; */ +#endif + + default: + goto LErrorLabel_; + +#if 0 + break; +#endif + } + } + + exc->top = exc->new_top; + + if ( exc->step_ins ) + exc->IP += exc->length; + + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) + { + exc->error = FT_THROW( Execution_Too_Long ); + goto LErrorLabel_; + } + + LSuiteLabel_: + if ( exc->IP >= exc->codeSize ) + { + if ( exc->callTop > 0 ) + { + exc->error = FT_THROW( Code_Overflow ); + goto LErrorLabel_; + } + else + goto LNo_Error_; + } + } while ( !exc->instruction_trap ); + + LNo_Error_: + FT_TRACE4(( " %ld instruction%s executed\n", + ins_counter, + ins_counter == 1 ? "" : "s" )); + + return FT_Err_Ok; + + LErrorCodeOverflow_: + exc->error = FT_THROW( Code_Overflow ); + + LErrorLabel_: + if ( exc->error && !exc->instruction_trap ) + FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error )); + + return exc->error; + } + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_interp_dummy_; + +#endif /* !TT_USE_BYTECODE_INTERPRETER */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttinterp.h b/Dependencies/freetype/freetype/src/truetype/ttinterp.h new file mode 100644 index 00000000..4f1a9bbc --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttinterp.h @@ -0,0 +1,465 @@ +/**************************************************************************** + * + * ttinterp.h + * + * TrueType bytecode interpreter (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTINTERP_H_ +#define TTINTERP_H_ + +#include "ttobjs.h" + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * Rounding mode constants. + */ +#define TT_Round_Off 5 +#define TT_Round_To_Half_Grid 0 +#define TT_Round_To_Grid 1 +#define TT_Round_To_Double_Grid 2 +#define TT_Round_Up_To_Grid 4 +#define TT_Round_Down_To_Grid 3 +#define TT_Round_Super 6 +#define TT_Round_Super_45 7 + + + /************************************************************************** + * + * Function types used by the interpreter, depending on various modes + * (e.g. the rounding mode, whether to render a vertical or horizontal + * line etc). + * + */ + + /* Rounding function */ + typedef FT_F26Dot6 + (*TT_Round_Func)( TT_ExecContext exc, + FT_F26Dot6 distance, + FT_Int color ); + + /* Point displacement along the freedom vector routine */ + typedef void + (*TT_Move_Func)( TT_ExecContext exc, + TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ); + + /* Distance projection along one of the projection vectors */ + typedef FT_F26Dot6 + (*TT_Project_Func)( TT_ExecContext exc, + FT_Pos dx, + FT_Pos dy ); + + /* getting current ppem. Take care of non-square pixels if necessary */ + typedef FT_Long + (*TT_Cur_Ppem_Func)( TT_ExecContext exc ); + + /* reading a cvt value. Take care of non-square pixels if necessary */ + typedef FT_F26Dot6 + (*TT_Get_CVT_Func)( TT_ExecContext exc, + FT_ULong idx ); + + /* setting or moving a cvt value. Take care of non-square pixels */ + /* if necessary */ + typedef void + (*TT_Set_CVT_Func)( TT_ExecContext exc, + FT_ULong idx, + FT_F26Dot6 value ); + + + /************************************************************************** + * + * This structure defines a call record, used to manage function calls. + */ + typedef struct TT_CallRec_ + { + FT_Int Caller_Range; + FT_Long Caller_IP; + FT_Long Cur_Count; + + TT_DefRecord *Def; /* either FDEF or IDEF */ + + } TT_CallRec, *TT_CallStack; + + + /************************************************************************** + * + * The main structure for the interpreter which collects all necessary + * variables and states. + * + * Members that are initialized by `TT_Load_Context` are marked with '!'. + * Members that are initialized by `TT_Run_Context` are marked with '@'. + */ + typedef struct TT_ExecContextRec_ + { + TT_Face face; /* ! */ + TT_Size size; /* ! */ + FT_Memory memory; + + /* instructions state */ + + FT_Error error; /* last execution error */ + + FT_Long top; /* @ top of exec. stack */ + + FT_Long stackSize; /* ! size of exec. stack */ + FT_Long* stack; /* ! current exec. stack */ + + FT_Long args; + FT_Long new_top; /* new top after exec. */ + + TT_GlyphZoneRec zp0, /* @! zone records */ + zp1, /* @! */ + zp2, /* @! */ + pts, /* ! */ + twilight; /* ! */ + + FT_Long pointSize; /* ! in 26.6 format */ + FT_Size_Metrics metrics; /* ! */ + TT_Size_Metrics tt_metrics; /* ! size metrics */ + + TT_GraphicsState GS; /* !@ current graphics state */ + + FT_Int iniRange; /* initial code range number */ + FT_Int curRange; /* current code range number */ + FT_Byte* code; /* current code range */ + FT_Long IP; /* current instruction pointer */ + FT_Long codeSize; /* size of current range */ + + FT_Byte opcode; /* current opcode */ + FT_Int length; /* length of current opcode */ + + FT_Bool step_ins; /* true if the interpreter must */ + /* increment IP after ins. exec */ + FT_ULong cvtSize; /* ! */ + FT_Long* cvt; /* ! */ + FT_ULong glyfCvtSize; + FT_Long* glyfCvt; /* cvt working copy for glyph */ + + FT_UInt glyphSize; /* ! glyph instructions buffer size */ + FT_Byte* glyphIns; /* ! glyph instructions buffer */ + + FT_UInt numFDefs; /* ! number of function defs */ + FT_UInt maxFDefs; /* ! maximum number of function defs */ + TT_DefArray FDefs; /* table of FDefs entries */ + + FT_UInt numIDefs; /* ! number of instruction defs */ + FT_UInt maxIDefs; /* ! maximum number of ins defs */ + TT_DefArray IDefs; /* table of IDefs entries */ + + FT_UInt maxFunc; /* ! maximum function index */ + FT_UInt maxIns; /* ! maximum instruction index */ + + FT_Int callTop, /* @ top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ + + FT_UShort maxPoints; /* capacity of this context's `pts' */ + FT_Short maxContours; /* record, expressed in points and */ + /* contours. */ + + TT_CodeRangeTable codeRangeTable; /* ! table of valid code ranges */ + /* useful for the debugger */ + + FT_UShort storeSize; /* ! size of current storage */ + FT_Long* storage; /* ! storage area */ + FT_UShort glyfStoreSize; + FT_Long* glyfStorage; /* storage working copy for glyph */ + + FT_F26Dot6 period; /* values used for the */ + FT_F26Dot6 phase; /* `SuperRounding' */ + FT_F26Dot6 threshold; + + FT_Bool instruction_trap; /* ! If `True', the interpreter */ + /* exits after each instruction */ + + TT_GraphicsState default_GS; /* graphics state resulting from */ + /* the prep program */ + FT_Bool is_composite; /* true if the glyph is composite */ + FT_Bool pedantic_hinting; /* true if pedantic interpretation */ + + /* latest interpreter additions */ + + FT_Long F_dot_P; /* dot product of freedom and projection */ + /* vectors */ + TT_Round_Func func_round; /* current rounding function */ + + TT_Project_Func func_project, /* current projection function */ + func_dualproj, /* current dual proj. function */ + func_freeProj; /* current freedom proj. func */ + + TT_Move_Func func_move; /* current point move function */ + TT_Move_Func func_move_orig; /* move original position function */ + + TT_Cur_Ppem_Func func_cur_ppem; /* get current proj. ppem value */ + + TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ + TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ + + FT_Bool grayscale; /* bi-level hinting and */ + /* grayscale rendering */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * FreeType supports ClearType-like hinting of TrueType fonts through + * the version 40 interpreter. This is achieved through several hacks + * in the base (v35) interpreter, as detailed below. + * + * ClearType is an umbrella term for several rendering techniques + * employed by Microsoft's various GUI and rendering toolkit + * implementations, most importantly: subpixel rendering for using the + * RGB subpixels of LCDs to approximately triple the perceived + * resolution on the x-axis and subpixel hinting for positioning stems + * on subpixel borders. TrueType programming is explicit, i.e., fonts + * must be programmed to take advantage of ClearType's possibilities. + * + * When ClearType was introduced, it seemed unlikely that all fonts + * would be reprogrammed, so Microsoft decided to implement a backward + * compatibility mode. It employs several simple to complicated + * assumptions and tricks, many of them font-dependent, that modify the + * interpretation of the bytecode contained in these fonts to retrofit + * them into a ClearType-y look. The quality of the results varies. + * Most (web)fonts that were released since then have come to rely on + * these hacks to render correctly, even some of Microsoft's flagship + * fonts (e.g., Calibri, Cambria, Segoe UI). + * + * FreeType's minimal subpixel hinting code (interpreter version 40) + * employs a small list of font-agnostic hacks loosely based on the + * public information available on Microsoft's compatibility mode[2]. + * The focus is on modern (web)fonts rather than legacy fonts that were + * made for monochrome rendering. It will not match ClearType rendering + * exactly. Unlike the `Infinality' code (interpreter version 38) that + * came before, it will not try to toggle hacks for specific fonts for + * performance and complexity reasons. It will fall back to version 35 + * behavior for tricky fonts[1] or when monochrome rendering is + * requested. + * + * Major hacks + * + * - Any point movement on the x axis is ignored (cf. `Direct_Move' and + * `Direct_Move_X'). This has the smallest code footprint and single + * biggest effect. The ClearType way to increase resolution is + * supersampling the x axis, the FreeType way is ignoring instructions + * on the x axis, which gives the same result in the majority of + * cases. + * + * - Points are not moved post-IUP (neither on the x nor on the y axis), + * except the x component of diagonal moves post-IUP (cf. + * `Direct_Move', `Direct_Move_Y', `Move_Zp2_Point'). Post-IUP + * changes are commonly used to `fix' pixel patterns which has little + * use outside monochrome rendering. + * + * - SHPIX and DELTAP don't execute unless moving a composite on the + * y axis or moving a previously y touched point. SHPIX additionally + * denies movement on the x axis (cf. `Ins_SHPIX' and `Ins_DELTAP'). + * Both instructions are commonly used to `fix' pixel patterns for + * monochrome or Windows's GDI rendering but make little sense for + * FreeType rendering. Both can distort the outline. See [2] for + * details. + * + * - The hdmx table and modifications to phantom points are ignored. + * Bearings and advance widths remain unchanged (except rounding them + * outside the interpreter!), cf. `compute_glyph_metrics' and + * `TT_Hint_Glyph'. Letting non-native-ClearType fonts modify spacing + * might mess up spacing. + * + * Minor hacks + * + * - FLIPRGON, FLIPRGOFF, and FLIPPT don't execute post-IUP. This + * prevents dents in e.g. Arial-Regular's `D' and `G' glyphs at + * various sizes. + * + * (Post-IUP is the state after both IUP[x] and IUP[y] have been + * executed.) + * + * The best results are achieved for fonts that were from the outset + * designed with ClearType in mind, meaning they leave the x axis mostly + * alone and don't mess with the `final' outline to produce more + * pleasing pixel patterns. The harder the designer tried to produce + * very specific patterns (`superhinting') for pre-ClearType-displays, + * the worse the results. + * + * Microsoft defines a way to turn off backward compatibility and + * interpret instructions as before (called `native ClearType')[2][3]. + * The font designer then regains full control and is responsible for + * making the font work correctly with ClearType without any + * hand-holding by the interpreter or rasterizer[4]. The v40 + * interpreter assumes backward compatibility by default, which can be + * turned off the same way by executing the following in the control + * program (cf. `Ins_INSTCTRL'). + * + * #PUSH 4,3 + * INSTCTRL[] + * + * [1] Tricky fonts as FreeType defines them rely on the bytecode + * interpreter to display correctly. Hacks can interfere with them, + * so they get treated like native ClearType fonts (v40 with + * backward compatibility turned off). Cf. `TT_RunIns'. + * + * [2] Proposed by Microsoft's Greg Hitchcock in + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + * + * [3] Beat Stamm describes it in more detail: + * http://rastertragedy.com/RTRCh4.htm#Sec12. + * + * [4] The list of `native ClearType' fonts is small at the time of this + * writing; I found the following on a Windows 10 Update 1511 + * installation: Constantia, Corbel, Sitka, Malgun Gothic, Microsoft + * JhengHei (Bold and UI Bold), Microsoft YaHei (Bold and UI Bold), + * SimSun, NSimSun, and Yu Gothic. + * + */ + + /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been + * requested. Used to detect interpreter */ + /* version switches. `_lean' to differentiate from the Infinality */ + /* `subpixel_hinting', which is managed differently. */ + FT_Bool subpixel_hinting_lean; + + /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ + /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ + /* is managed differently. */ + FT_Bool vertical_lcd_lean; + + /* Default to backward compatibility mode in v40 interpreter. If */ + /* this is false, it implies the interpreter is in v35 or in native */ + /* ClearType mode. */ + FT_Bool backward_compatibility; + + /* Useful for detecting and denying post-IUP trickery that is usually */ + /* used to fix pixel patterns (`superhinting'). */ + FT_Bool iupx_called; + FT_Bool iupy_called; + + /* ClearType hinting and grayscale rendering, as used by Universal */ + /* Windows Platform apps (Windows 8 and above). Like the standard */ + /* colorful ClearType mode, it utilizes a vastly increased virtual */ + /* resolution on the x axis. Different from bi-level hinting and */ + /* grayscale rendering, the old mode from Win9x days that roughly */ + /* adheres to the physical pixel grid on both axes. */ + FT_Bool grayscale_cleartype; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + + /* We maintain two counters (in addition to the instruction counter) */ + /* that act as loop detectors for LOOPCALL and jump opcodes with */ + /* negative arguments. */ + FT_ULong loopcall_counter; + FT_ULong loopcall_counter_max; + FT_ULong neg_jump_counter; + FT_ULong neg_jump_counter_max; + + } TT_ExecContextRec; + + + extern const TT_GraphicsState tt_default_graphics_state; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_LOCAL( void ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ); + + FT_LOCAL( void ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ); + + FT_LOCAL( void ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ); +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * TT_New_Context + * + * @Description: + * Create a `TT_ExecContext`. Note that there is now an execution + * context per `TT_Size` that is not shared among faces. + * + * @Input: + * driver :: + * A handle to the driver, used for memory allocation. + * + * @Return: + * A handle to a new empty execution context. + * + * @Note: + * Only the glyph loader and debugger should call this function. + * (And right now only the glyph loader uses it.) + */ + FT_EXPORT( TT_ExecContext ) + TT_New_Context( TT_Driver driver ); + + +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_LOCAL( void ) + TT_Done_Context( TT_ExecContext exec ); + + FT_LOCAL( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ); + + FT_LOCAL( void ) + TT_Save_Context( TT_ExecContext exec, + TT_Size ins ); + + FT_LOCAL( FT_Error ) + TT_Run_Context( TT_ExecContext exec ); +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * TT_RunIns + * + * @Description: + * Executes one or more instruction in the execution context. This + * is the main function of the TrueType opcode interpreter. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only the object manager and debugger should call this function. + * + * This function is publicly exported because it is directly + * invoked by the TrueType debugger. + */ + FT_EXPORT( FT_Error ) + TT_RunIns( void* exec ); + + +FT_END_HEADER + +#endif /* TTINTERP_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttobjs.c b/Dependencies/freetype/freetype/src/truetype/ttobjs.c new file mode 100644 index 00000000..d0ac3181 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttobjs.c @@ -0,0 +1,1543 @@ +/**************************************************************************** + * + * ttobjs.c + * + * Objects manager (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "ttgload.h" +#include "ttpload.h" + +#include "tterrors.h" + +#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttinterp.h" +#endif + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttobjs + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /************************************************************************** + * + * GLYPH ZONE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * tt_glyphzone_done + * + * @Description: + * Deallocate a glyph zone. + * + * @Input: + * zone :: + * A pointer to the target glyph zone. + */ + FT_LOCAL_DEF( void ) + tt_glyphzone_done( TT_GlyphZone zone ) + { + FT_Memory memory = zone->memory; + + + if ( memory ) + { + FT_FREE( zone->contours ); + FT_FREE( zone->tags ); + FT_FREE( zone->cur ); + FT_FREE( zone->org ); + FT_FREE( zone->orus ); + + zone->max_points = zone->n_points = 0; + zone->max_contours = zone->n_contours = 0; + zone->memory = NULL; + } + } + + + /************************************************************************** + * + * @Function: + * tt_glyphzone_new + * + * @Description: + * Allocate a new glyph zone. + * + * @Input: + * memory :: + * A handle to the current memory object. + * + * maxPoints :: + * The capacity of glyph zone in points. + * + * maxContours :: + * The capacity of glyph zone in contours. + * + * @Output: + * zone :: + * A pointer to the target glyph zone record. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_UShort maxContours, + TT_GlyphZone zone ) + { + FT_Error error; + + + FT_ZERO( zone ); + zone->memory = memory; + + if ( FT_NEW_ARRAY( zone->org, maxPoints ) || + FT_NEW_ARRAY( zone->cur, maxPoints ) || + FT_NEW_ARRAY( zone->orus, maxPoints ) || + FT_NEW_ARRAY( zone->tags, maxPoints ) || + FT_NEW_ARRAY( zone->contours, maxContours ) ) + { + tt_glyphzone_done( zone ); + } + else + { + zone->max_points = maxPoints; + zone->max_contours = maxContours; + } + + return error; + } + + + /* + * Fonts embedded in PDFs are made unique by prepending randomization + * prefixes to their names: as defined in Section 5.5.3, 'Font Subsets', + * of the PDF Reference, they consist of 6 uppercase letters followed by + * the `+` sign. For safety, we do not skip prefixes violating this rule. + */ + + static const FT_String* + tt_skip_pdffont_random_tag( const FT_String* name ) + { + if ( ft_isupper( name[0] ) && + ft_isupper( name[1] ) && + ft_isupper( name[2] ) && + ft_isupper( name[3] ) && + ft_isupper( name[4] ) && + ft_isupper( name[5] ) && + '+' == name[6] && + name[7] ) + { + FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); + return name + 7; + } + + return name; + } + + + /* Compare the face with a list of well-known `tricky' fonts. */ + /* This list shall be expanded as we find more of them. */ + + static FT_Bool + tt_check_trickyness_family( const FT_String* name ) + { + +#define TRICK_NAMES_MAX_CHARACTERS 19 +#define TRICK_NAMES_COUNT 20 + + static const char trick_names[TRICK_NAMES_COUNT] + [TRICK_NAMES_MAX_CHARACTERS + 1] = + { + /* + PostScript names are given in brackets if they differ from the + family name. The version numbers, together with the copyright or + release year data, are taken from fonts available to the + developers. + + Note that later versions of the fonts might be no longer tricky; + for example, `MingLiU' version 7.00 (file `mingliu.ttc' from + Windows 7) is an ordinary TTC with non-tricky subfonts. + */ + + "cpop", /* dftt-p7.ttf; version 1.00, 1992 [DLJGyShoMedium] */ + "DFGirl-W6-WIN-BF", /* dftt-h6.ttf; version 1.00, 1993 */ + "DFGothic-EB", /* DynaLab Inc. 1992-1995 */ + "DFGyoSho-Lt", /* DynaLab Inc. 1992-1995 */ + "DFHei", /* DynaLab Inc. 1992-1995 [DFHei-Bd-WIN-HK-BF] */ + /* covers "DFHei-Md-HK-BF", maybe DynaLab Inc. */ + + "DFHSGothic-W5", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W3", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W7", /* DynaLab Inc. 1992-1995 */ + "DFKaiSho-SB", /* dfkaisb.ttf */ + "DFKaiShu", /* covers "DFKaiShu-Md-HK-BF", maybe DynaLab Inc. */ + "DFKai-SB", /* kaiu.ttf; version 3.00, 1998 [DFKaiShu-SB-Estd-BF] */ + + "DFMing", /* DynaLab Inc. 1992-1995 [DFMing-Md-WIN-HK-BF] */ + /* covers "DFMing-Bd-HK-BF", maybe DynaLab Inc. */ + + "DLC", /* dftt-m7.ttf; version 1.00, 1993 [DLCMingBold] */ + /* dftt-f5.ttf; version 1.00, 1993 [DLCFongSung] */ + /* covers following */ + /* "DLCHayMedium", dftt-b5.ttf; version 1.00, 1993 */ + /* "DLCHayBold", dftt-b7.ttf; version 1.00, 1993 */ + /* "DLCKaiMedium", dftt-k5.ttf; version 1.00, 1992 */ + /* "DLCLiShu", dftt-l5.ttf; version 1.00, 1992 */ + /* "DLCRoundBold", dftt-r7.ttf; version 1.00, 1993 */ + + "HuaTianKaiTi?", /* htkt2.ttf */ + "HuaTianSongTi?", /* htst3.ttf */ + "Ming(for ISO10646)", /* hkscsiic.ttf; version 0.12, 2007 [Ming] */ + /* iicore.ttf; version 0.07, 2007 [Ming] */ + "MingLiU", /* mingliu.ttf */ + /* mingliu.ttc; version 3.21, 2001 */ + "MingMedium", /* dftt-m5.ttf; version 1.00, 1993 [DLCMingMedium] */ + "PMingLiU", /* mingliu.ttc; version 3.21, 2001 */ + "MingLi43", /* mingli.ttf; version 1.00, 1992 */ + }; + + int nn; + const FT_String* name_without_tag; + + + name_without_tag = tt_skip_pdffont_random_tag( name ); + for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) + if ( ft_strstr( name_without_tag, trick_names[nn] ) ) + return TRUE; + + return FALSE; + } + + + /* XXX: This function should be in the `sfnt' module. */ + + /* Some PDF generators clear the checksums in the TrueType header table. */ + /* For example, Quartz ContextPDF clears all entries, or Bullzip PDF */ + /* Printer clears the entries for subsetted subtables. We thus have to */ + /* recalculate the checksums where necessary. */ + + static FT_UInt32 + tt_synth_sfnt_checksum( FT_Stream stream, + FT_ULong length ) + { + FT_Error error; + FT_UInt32 checksum = 0; + FT_Byte* p; + FT_Int shift; + + + if ( FT_FRAME_ENTER( length ) ) + return 0; + + p = (FT_Byte*)stream->cursor; + + for ( ; length > 3; length -= 4 ) + checksum += FT_NEXT_ULONG( p ); + + for ( shift = 24; length > 0; length--, shift -=8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( p ) << shift; + + FT_FRAME_EXIT(); + + return checksum; + } + + + /* XXX: This function should be in the `sfnt' module. */ + + static FT_ULong + tt_get_sfnt_checksum( TT_Face face, + FT_UShort i ) + { +#if 0 /* if we believe the written value, use following part. */ + if ( face->dir_tables[i].CheckSum ) + return face->dir_tables[i].CheckSum; +#endif + + if ( !face->goto_table ) + return 0; + + if ( face->goto_table( face, + face->dir_tables[i].Tag, + face->root.stream, + NULL ) ) + return 0; + + return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, + face->dir_tables[i].Length ); + } + + + typedef struct tt_sfnt_id_rec_ + { + FT_ULong CheckSum; + FT_ULong Length; + + } tt_sfnt_id_rec; + + + static FT_Bool + tt_check_trickyness_sfnt_ids( TT_Face face ) + { +#define TRICK_SFNT_IDS_PER_FACE 3 +#define TRICK_SFNT_IDS_NUM_FACES 31 + + static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] + [TRICK_SFNT_IDS_PER_FACE] = + { + +#define TRICK_SFNT_ID_cvt 0 +#define TRICK_SFNT_ID_fpgm 1 +#define TRICK_SFNT_ID_prep 2 + + { /* MingLiU 1995 */ + { 0x05BCF058UL, 0x000002E4UL }, /* cvt */ + { 0x28233BF1UL, 0x000087C4UL }, /* fpgm */ + { 0xA344A1EAUL, 0x000001E1UL } /* prep */ + }, + { /* MingLiU 1996- */ + { 0x05BCF058UL, 0x000002E4UL }, /* cvt */ + { 0x28233BF1UL, 0x000087C4UL }, /* fpgm */ + { 0xA344A1EBUL, 0x000001E1UL } /* prep */ + }, + { /* DFGothic-EB */ + { 0x12C3EBB2UL, 0x00000350UL }, /* cvt */ + { 0xB680EE64UL, 0x000087A7UL }, /* fpgm */ + { 0xCE939563UL, 0x00000758UL } /* prep */ + }, + { /* DFGyoSho-Lt */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xCE5956E9UL, 0x0000BC85UL }, /* fpgm */ + { 0x8272F416UL, 0x00000045UL } /* prep */ + }, + { /* DFHei-Md-HK-BF */ + { 0x1257EB46UL, 0x00000350UL }, /* cvt */ + { 0xF699D160UL, 0x0000715FUL }, /* fpgm */ + { 0xD222F568UL, 0x000003BCUL } /* prep */ + }, + { /* DFHSGothic-W5 */ + { 0x1262EB4EUL, 0x00000350UL }, /* cvt */ + { 0xE86A5D64UL, 0x00007940UL }, /* fpgm */ + { 0x7850F729UL, 0x000005FFUL } /* prep */ + }, + { /* DFHSMincho-W3 */ + { 0x122DEB0AUL, 0x00000350UL }, /* cvt */ + { 0x3D16328AUL, 0x0000859BUL }, /* fpgm */ + { 0xA93FC33BUL, 0x000002CBUL } /* prep */ + }, + { /* DFHSMincho-W7 */ + { 0x125FEB26UL, 0x00000350UL }, /* cvt */ + { 0xA5ACC982UL, 0x00007EE1UL }, /* fpgm */ + { 0x90999196UL, 0x0000041FUL } /* prep */ + }, + { /* DFKaiShu */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0x5A30CA3BUL, 0x00009063UL }, /* fpgm */ + { 0x13A42602UL, 0x0000007EUL } /* prep */ + }, + { /* DFKaiShu, variant */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xA6E78C01UL, 0x00008998UL }, /* fpgm */ + { 0x13A42602UL, 0x0000007EUL } /* prep */ + }, + { /* DFKaiShu-Md-HK-BF */ + { 0x11E5EAD4UL, 0x00000360UL }, /* cvt */ + { 0x9DB282B2UL, 0x0000C06EUL }, /* fpgm */ + { 0x53E6D7CAUL, 0x00000082UL } /* prep */ + }, + { /* DFMing-Bd-HK-BF */ + { 0x1243EB18UL, 0x00000350UL }, /* cvt */ + { 0xBA0A8C30UL, 0x000074ADUL }, /* fpgm */ + { 0xF3D83409UL, 0x0000037BUL } /* prep */ + }, + { /* DLCLiShu */ + { 0x07DCF546UL, 0x00000308UL }, /* cvt */ + { 0x40FE7C90UL, 0x00008E2AUL }, /* fpgm */ + { 0x608174B5UL, 0x0000007AUL } /* prep */ + }, + { /* DLCHayBold */ + { 0xEB891238UL, 0x00000308UL }, /* cvt */ + { 0xD2E4DCD4UL, 0x0000676FUL }, /* fpgm */ + { 0x8EA5F293UL, 0x000003B8UL } /* prep */ + }, + { /* HuaTianKaiTi */ + { 0xFFFBFFFCUL, 0x00000008UL }, /* cvt */ + { 0x9C9E48B8UL, 0x0000BEA2UL }, /* fpgm */ + { 0x70020112UL, 0x00000008UL } /* prep */ + }, + { /* HuaTianSongTi */ + { 0xFFFBFFFCUL, 0x00000008UL }, /* cvt */ + { 0x0A5A0483UL, 0x00017C39UL }, /* fpgm */ + { 0x70020112UL, 0x00000008UL } /* prep */ + }, + { /* NEC fadpop7.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40C92555UL, 0x000000E5UL }, /* fpgm */ + { 0xA39B58E3UL, 0x0000117CUL } /* prep */ + }, + { /* NEC fadrei5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x33C41652UL, 0x000000E5UL }, /* fpgm */ + { 0x26D6C52AUL, 0x00000F6AUL } /* prep */ + }, + { /* NEC fangot7.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x6DB1651DUL, 0x0000019DUL }, /* fpgm */ + { 0x6C6E4B03UL, 0x00002492UL } /* prep */ + }, + { /* NEC fangyo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40C92555UL, 0x000000E5UL }, /* fpgm */ + { 0xDE51FAD0UL, 0x0000117CUL } /* prep */ + }, + { /* NEC fankyo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x85E47664UL, 0x000000E5UL }, /* fpgm */ + { 0xA6C62831UL, 0x00001CAAUL } /* prep */ + }, + { /* NEC fanrgo5.ttf */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x2D891CFDUL, 0x0000019DUL }, /* fpgm */ + { 0xA0604633UL, 0x00001DE8UL } /* prep */ + }, + { /* NEC fangot5.ttc */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x40AA774CUL, 0x000001CBUL }, /* fpgm */ + { 0x9B5CAA96UL, 0x00001F9AUL } /* prep */ + }, + { /* NEC fanmin3.ttc */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x0D3DE9CBUL, 0x00000141UL }, /* fpgm */ + { 0xD4127766UL, 0x00002280UL } /* prep */ + }, + { /* NEC FA-Gothic, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x4A692698UL, 0x000001F0UL }, /* fpgm */ + { 0x340D4346UL, 0x00001FCAUL } /* prep */ + }, + { /* NEC FA-Minchou, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0xCD34C604UL, 0x00000166UL }, /* fpgm */ + { 0x6CF31046UL, 0x000022B0UL } /* prep */ + }, + { /* NEC FA-RoundGothicB, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0x5DA75315UL, 0x0000019DUL }, /* fpgm */ + { 0x40745A5FUL, 0x000022E0UL } /* prep */ + }, + { /* NEC FA-RoundGothicM, 1996 */ + { 0x00000000UL, 0x00000000UL }, /* cvt */ + { 0xF055FC48UL, 0x000001C2UL }, /* fpgm */ + { 0x3900DED3UL, 0x00001E18UL } /* prep */ + }, + { /* MINGLI.TTF, 1992 */ + { 0x00170003UL, 0x00000060UL }, /* cvt */ + { 0xDBB4306EUL, 0x000058AAUL }, /* fpgm */ + { 0xD643482AUL, 0x00000035UL } /* prep */ + }, + { /* DFHei-Bd-WIN-HK-BF, issue #1087 */ + { 0x1269EB58UL, 0x00000350UL }, /* cvt */ + { 0x5CD5957AUL, 0x00006A4EUL }, /* fpgm */ + { 0xF758323AUL, 0x00000380UL } /* prep */ + }, + { /* DFMing-Md-WIN-HK-BF, issue #1087 */ + { 0x122FEB0BUL, 0x00000350UL }, /* cvt */ + { 0x7F10919AUL, 0x000070A9UL }, /* fpgm */ + { 0x7CD7E7B7UL, 0x0000025CUL } /* prep */ + } + }; + + FT_ULong checksum; + int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; + FT_Bool has_cvt, has_fpgm, has_prep; + FT_UShort i; + int j, k; + + + FT_MEM_SET( num_matched_ids, 0, + sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); + has_cvt = FALSE; + has_fpgm = FALSE; + has_prep = FALSE; + + for ( i = 0; i < face->num_tables; i++ ) + { + checksum = 0; + + switch( face->dir_tables[i].Tag ) + { + case TTAG_cvt: + k = TRICK_SFNT_ID_cvt; + has_cvt = TRUE; + break; + + case TTAG_fpgm: + k = TRICK_SFNT_ID_fpgm; + has_fpgm = TRUE; + break; + + case TTAG_prep: + k = TRICK_SFNT_ID_prep; + has_prep = TRUE; + break; + + default: + continue; + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) + { + if ( !checksum ) + checksum = tt_get_sfnt_checksum( face, i ); + + if ( sfnt_id[j][k].CheckSum == checksum ) + num_matched_ids[j]++; + + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + { + if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) + num_matched_ids[j]++; + if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) + num_matched_ids[j]++; + if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) + num_matched_ids[j]++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + + return FALSE; + } + + + static FT_Bool + tt_check_trickyness( FT_Face face ) + { + if ( !face ) + return FALSE; + + /* For first, check the face name for quick check. */ + if ( face->family_name && + tt_check_trickyness_family( face->family_name ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its family name: %s\n", face->family_name )); + return TRUE; + } + + /* Type42 fonts may lack `name' tables, we thus try to identify */ + /* tricky fonts by checking the checksums of Type42-persistent */ + /* sfnt tables (`cvt', `fpgm', and `prep'). */ + if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its cvt/fpgm/prep table checksum\n" )); + return TRUE; + } + + return FALSE; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* Check whether `.notdef' is the only glyph in the `loca' table. */ + static FT_Bool + tt_check_single_notdef( FT_Face ttface ) + { + FT_Bool result = FALSE; + + TT_Face face = (TT_Face)ttface; + FT_ULong asize; + FT_ULong i; + FT_ULong glyph_index = 0; + FT_UInt count = 0; + + + for( i = 0; i < face->num_locations; i++ ) + { + tt_face_get_location( ttface, i, &asize ); + if ( asize > 0 ) + { + count += 1; + if ( count > 1 ) + break; + glyph_index = i; + } + } + + /* Only have a single outline. */ + if ( count == 1 ) + { + if ( glyph_index == 0 ) + result = TRUE; + else + { + /* FIXME: Need to test glyphname == .notdef ? */ + FT_Error error; + char buf[8]; + + + error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); + if ( !error && + buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) + result = TRUE; + } + } + + return result; + } + + + /************************************************************************** + * + * @Function: + * tt_face_init + * + * @Description: + * Initialize a given TrueType face object. + * + * @Input: + * stream :: + * The source font stream. + * + * face_index :: + * The index of the TrueType font, if we are opening a + * collection, in bits 0-15. The numbered instance + * index~+~1 of a GX (sub)font, if applicable, in bits + * 16-30. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The newly built face object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library; + SFNT_Service sfnt; + TT_Face face = (TT_Face)ttface; + + + FT_TRACE2(( "TTF driver\n" )); + + library = ttface->driver->root.library; + + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + /* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + /* check that we have a valid TrueType file */ + FT_TRACE2(( " " )); + error = sfnt->init_face( stream, face, face_index, num_params, params ); + + /* Stream may have changed. */ + stream = face->root.stream; + + if ( error ) + goto Exit; + + /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ + /* The 0x00020000 tag is completely undocumented; some fonts from */ + /* Arphic made for Chinese Windows 3.1 have this. */ + if ( face->format_tag != 0x00010000L && /* MS fonts */ + face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ + face->format_tag != TTAG_true && /* Mac fonts */ + face->format_tag != TTAG_0xA5kbd && /* `Keyboard.dfont' (legacy Mac OS X) */ + face->format_tag != TTAG_0xA5lst ) /* `LastResort.dfont' (legacy Mac OS X) */ + { + FT_TRACE2(( " not a TTF font\n" )); + goto Bad_Format; + } + +#ifdef TT_USE_BYTECODE_INTERPRETER + ttface->face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return FT_Err_Ok; + + /* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + +#ifdef TT_USE_BYTECODE_INTERPRETER + if ( tt_check_trickyness( ttface ) ) + ttface->face_flags |= FT_FACE_FLAG_TRICKY; +#endif + + error = tt_face_load_hdmx( face, stream ); + if ( error ) + goto Exit; + + if ( FT_IS_SCALABLE( ttface ) || + FT_HAS_SBIX( ttface ) ) + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !ttface->internal->incremental_interface ) +#endif + { + error = tt_face_load_loca( face, stream ); + + /* having a (non-zero) `glyf' table without */ + /* a `loca' table is not valid */ + if ( face->glyf_len && FT_ERR_EQ( error, Table_Missing ) ) + goto Exit; + if ( error ) + goto Exit; + } + + /* `fpgm', `cvt', and `prep' are optional */ + error = tt_face_load_cvt( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + error = tt_face_load_fpgm( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + error = tt_face_load_prep( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + /* Check the scalable flag based on `loca'. */ +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !ttface->internal->incremental_interface ) +#endif + { + if ( ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" )); + FT_TRACE5(( " " + " Resetting scalable flag to FALSE.\n" )); + + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } + } + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_UInt instance_index = (FT_UInt)face_index >> 16; + + + if ( FT_HAS_MULTIPLE_MASTERS( ttface ) ) + { + error = FT_Set_Named_Instance( ttface, instance_index ); + if ( error ) + goto Exit; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* initialize standard glyph loading routines */ + TT_Init_Glyph_Loading( face ); + + Exit: + return error; + + Bad_Format: + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + + /************************************************************************** + * + * @Function: + * tt_face_done + * + * @Description: + * Finalize a given face object. + * + * @Input: + * face :: + * A pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + tt_face_done( FT_Face ttface ) /* TT_Face */ + { + TT_Face face = (TT_Face)ttface; + FT_Memory memory; + FT_Stream stream; + SFNT_Service sfnt; + + + if ( !face ) + return; + + memory = ttface->memory; + stream = ttface->stream; + sfnt = (SFNT_Service)face->sfnt; + + /* for `extended TrueType formats' (i.e. compressed versions) */ + if ( face->extra.finalizer ) + face->extra.finalizer( face->extra.data ); + + if ( sfnt ) + sfnt->done_face( face ); + + /* freeing the locations table */ + tt_face_done_loca( face ); + + tt_face_free_hdmx( face ); + + /* freeing the CVT */ + FT_FREE( face->cvt ); + face->cvt_size = 0; + + /* freeing the programs */ + FT_FRAME_RELEASE( face->font_program ); + FT_FRAME_RELEASE( face->cvt_program ); + face->font_program_size = 0; + face->cvt_program_size = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + tt_done_blend( ttface ); + face->blend = NULL; +#endif + } + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + /************************************************************************** + * + * @Function: + * tt_size_run_fpgm + * + * @Description: + * Run the font program. + * + * @Input: + * size :: + * A handle to the size object. + * + * pedantic :: + * Set if bytecode execution should be pedantic. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + + + exec = size->context; + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + exec->callTop = 0; + exec->top = 0; + + exec->period = 64; + exec->phase = 0; + exec->threshold = 0; + + exec->instruction_trap = FALSE; + exec->F_dot_P = 0x4000L; + + exec->pedantic_hinting = pedantic; + + { + FT_Size_Metrics* size_metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + + + size_metrics->x_ppem = 0; + size_metrics->y_ppem = 0; + size_metrics->x_scale = 0; + size_metrics->y_scale = 0; + + tt_metrics->ppem = 0; + tt_metrics->scale = 0; + tt_metrics->ratio = 0x10000L; + } + + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + (FT_Long)face->font_program_size ); + + /* disable CVT and glyph programs coderange */ + TT_Clear_CodeRange( exec, tt_coderange_cvt ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->font_program_size > 0 ) + { + TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + + FT_TRACE4(( "Executing `fpgm' table.\n" )); + error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif + } + else + error = FT_Err_Ok; + + size->bytecode_ready = error; + + if ( !error ) + TT_Save_Context( exec, size ); + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_size_run_prep + * + * @Description: + * Run the control value program. + * + * @Input: + * size :: + * A handle to the size object. + * + * pedantic :: + * Set if bytecode execution should be pedantic. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; + FT_UInt i; + + + /* Scale the cvt values to the new ppem. */ + /* By default, we use the y ppem value for scaling. */ + FT_TRACE6(( "CVT values:\n" )); + for ( i = 0; i < size->cvt_size; i++ ) + { + /* Unscaled CVT values are already stored in 26.6 format. */ + /* Note that this scaling operation is very sensitive to rounding; */ + /* the integer division by 64 must be applied to the first argument. */ + size->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale ); + FT_TRACE6(( " %3d: %f (%f)\n", + i, (double)face->cvt[i] / 64, (double)size->cvt[i] / 64 )); + } + FT_TRACE6(( "\n" )); + + exec = size->context; + + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + + exec->callTop = 0; + exec->top = 0; + + exec->instruction_trap = FALSE; + + exec->pedantic_hinting = pedantic; + + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + (FT_Long)face->cvt_program_size ); + + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + if ( face->cvt_program_size > 0 ) + { + TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + + FT_TRACE4(( "Executing `prep' table.\n" )); + error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif + } + else + error = FT_Err_Ok; + + size->cvt_ready = error; + + /* UNDOCUMENTED! The MS rasterizer doesn't allow the following */ + /* graphics state variables to be modified by the CVT program. */ + + exec->GS.dualVector.x = 0x4000; + exec->GS.dualVector.y = 0; + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0; + exec->GS.freeVector.x = 0x4000; + exec->GS.freeVector.y = 0x0; + + exec->GS.rp0 = 0; + exec->GS.rp1 = 0; + exec->GS.rp2 = 0; + + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + + exec->GS.loop = 1; + + /* save as default graphics state */ + size->GS = exec->GS; + + TT_Save_Context( exec, size ); + + return error; + } + + + static void + tt_size_done_bytecode( FT_Size ftsize ) + { + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + + if ( size->context ) + { + TT_Done_Context( size->context ); + size->context = NULL; + } + + FT_FREE( size->cvt ); + size->cvt_size = 0; + + /* free storage area */ + FT_FREE( size->storage ); + size->storage_size = 0; + + /* twilight zone */ + tt_glyphzone_done( &size->twilight ); + + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + + size->num_function_defs = 0; + size->max_function_defs = 0; + size->num_instruction_defs = 0; + size->max_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->bytecode_ready = -1; + size->cvt_ready = -1; + } + + + /* Initialize bytecode-related fields in the size object. */ + /* We do this only if bytecode interpretation is really needed. */ + static FT_Error + tt_size_init_bytecode( FT_Size ftsize, + FT_Bool pedantic ) + { + FT_Error error; + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + + FT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; + + + /* clean up bytecode related data */ + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + FT_FREE( size->cvt ); + FT_FREE( size->storage ); + + if ( size->context ) + TT_Done_Context( size->context ); + tt_glyphzone_done( &size->twilight ); + + size->bytecode_ready = -1; + size->cvt_ready = -1; + + size->context = TT_New_Context( (TT_Driver)face->root.driver ); + + size->max_function_defs = maxp->maxFunctionDefs; + size->max_instruction_defs = maxp->maxInstructionDefs; + + size->num_function_defs = 0; + size->num_instruction_defs = 0; + + size->max_func = 0; + size->max_ins = 0; + + size->cvt_size = face->cvt_size; + size->storage_size = maxp->maxStorage; + + /* Set default metrics */ + { + TT_Size_Metrics* tt_metrics = &size->ttmetrics; + + + tt_metrics->rotated = FALSE; + tt_metrics->stretched = FALSE; + + /* Set default engine compensation. Value 3 is not described */ + /* in the OpenType specification (as of Mai 2019), but Greg */ + /* says that MS handles it the same as `gray'. */ + /* */ + /* The Apple specification says that the compensation for */ + /* `gray' is always zero. FreeType doesn't do any */ + /* compensation at all. */ + tt_metrics->compensations[0] = 0; /* gray */ + tt_metrics->compensations[1] = 0; /* black */ + tt_metrics->compensations[2] = 0; /* white */ + tt_metrics->compensations[3] = 0; /* zero */ + } + + /* allocate function defs, instruction defs, cvt, and storage area */ + if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || + FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || + FT_NEW_ARRAY( size->cvt, size->cvt_size ) || + FT_NEW_ARRAY( size->storage, size->storage_size ) ) + goto Exit; + + /* reserve twilight zone */ + n_twilight = maxp->maxTwilightPoints; + + /* there are 4 phantom points (do we need this?) */ + n_twilight += 4; + + error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); + if ( error ) + goto Exit; + + size->twilight.n_points = n_twilight; + + size->GS = tt_default_graphics_state; + + /* set `face->interpreter' according to the debug hook present */ + { + FT_Library library = face->root.driver->root.library; + + + face->interpreter = (TT_Interpreter) + library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + if ( !face->interpreter ) + face->interpreter = (TT_Interpreter)TT_RunIns; + } + + /* Fine, now run the font program! */ + + /* In case of an error while executing `fpgm', we intentionally don't */ + /* clean up immediately – bugs in the `fpgm' are so fundamental that */ + /* all following hinting calls should fail. Additionally, `fpgm' is */ + /* to be executed just once; calling it again is completely useless */ + /* and might even lead to extremely slow behaviour if it is malformed */ + /* (containing an infinite loop, for example). */ + error = tt_size_run_fpgm( size, pedantic ); + return error; + + Exit: + if ( error ) + tt_size_done_bytecode( ftsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ) + { + FT_Error error = FT_Err_Ok; + + + if ( size->bytecode_ready < 0 ) + error = tt_size_init_bytecode( (FT_Size)size, pedantic ); + else + error = size->bytecode_ready; + + if ( error ) + goto Exit; + + /* rescale CVT when needed */ + if ( size->cvt_ready < 0 ) + { + FT_UShort i; + + + /* all twilight points are originally zero */ + for ( i = 0; i < size->twilight.n_points; i++ ) + { + size->twilight.org[i].x = 0; + size->twilight.org[i].y = 0; + size->twilight.cur[i].x = 0; + size->twilight.cur[i].y = 0; + } + + /* clear storage area */ + for ( i = 0; i < size->storage_size; i++ ) + size->storage[i] = 0; + + size->GS = tt_default_graphics_state; + + error = tt_size_run_prep( size, pedantic ); + } + else + error = size->cvt_ready; + + Exit: + return error; + } + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /************************************************************************** + * + * @Function: + * tt_size_init + * + * @Description: + * Initialize a new TrueType size object. + * + * @InOut: + * size :: + * A handle to the size object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_init( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + FT_Error error = FT_Err_Ok; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->bytecode_ready = -1; + size->cvt_ready = -1; +#endif + + size->ttmetrics.valid = FALSE; + size->strike_index = 0xFFFFFFFFUL; + + return error; + } + + + /************************************************************************** + * + * @Function: + * tt_size_done + * + * @Description: + * The TrueType size object finalizer. + * + * @Input: + * size :: + * A handle to the target size object. + */ + FT_LOCAL_DEF( void ) + tt_size_done( FT_Size ttsize ) /* TT_Size */ + { + TT_Size size = (TT_Size)ttsize; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + tt_size_done_bytecode( ttsize ); +#endif + + size->ttmetrics.valid = FALSE; + } + + + /************************************************************************** + * + * @Function: + * tt_size_reset_height + * + * @Description: + * Recompute a TrueType size's ascender, descender, and height + * when resolutions and character dimensions have been changed. + * Used for variation fonts as an iterator function. + * + * @Input: + * ft_size :: + * A handle to the target TT_Size object. This function will be called + * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This + * function must take `FT_Size` as a result. The passed `FT_Size` is + * expected to point to a `TT_Size`. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset_height( FT_Size ft_size ) + { + TT_Size size = (TT_Size)ft_size; + TT_Face face = (TT_Face)size->root.face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; + + size->ttmetrics.valid = FALSE; + + /* copy the result from base layer */ + *size_metrics = size->root.metrics; + + if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 ) + return FT_THROW( Invalid_PPem ); + + /* This bit flag, if set, indicates that the ppems must be */ + /* rounded to integers. Nearly all TrueType fonts have this bit */ + /* set, as hinting won't work really well otherwise. */ + /* */ + if ( face->header.Flags & 8 ) + { + /* the TT spec always asks for ROUND, not FLOOR or CEIL */ + size_metrics->ascender = FT_PIX_ROUND( + FT_MulFix( face->root.ascender, + size_metrics->y_scale ) ); + size_metrics->descender = FT_PIX_ROUND( + FT_MulFix( face->root.descender, + size_metrics->y_scale ) ); + size_metrics->height = FT_PIX_ROUND( + FT_MulFix( face->root.height, + size_metrics->y_scale ) ); + } + + size->ttmetrics.valid = TRUE; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_size_reset + * + * @Description: + * Reset a TrueType size when resolutions and character dimensions + * have been changed. + * + * @Input: + * size :: + * A handle to the target size object. + */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset( TT_Size size ) + { + FT_Error error; + TT_Face face = (TT_Face)size->root.face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; + + + error = tt_size_reset_height( (FT_Size)size ); + if ( error ) + return error; + + if ( face->header.Flags & 8 ) + { + /* base scaling values on integer ppem values, */ + /* as mandated by the TrueType specification */ + size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, + face->root.units_per_EM ); + size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, + face->root.units_per_EM ); + + size_metrics->max_advance = FT_PIX_ROUND( + FT_MulFix( face->root.max_advance_width, + size_metrics->x_scale ) ); + } + + /* compute new transformation */ + if ( size_metrics->x_ppem >= size_metrics->y_ppem ) + { + size->ttmetrics.scale = size_metrics->x_scale; + size->ttmetrics.ppem = size_metrics->x_ppem; + size->ttmetrics.x_ratio = 0x10000L; + size->ttmetrics.y_ratio = FT_DivFix( size_metrics->y_ppem, + size_metrics->x_ppem ); + } + else + { + size->ttmetrics.scale = size_metrics->y_scale; + size->ttmetrics.ppem = size_metrics->y_ppem; + size->ttmetrics.x_ratio = FT_DivFix( size_metrics->x_ppem, + size_metrics->y_ppem ); + size->ttmetrics.y_ratio = 0x10000L; + } + + size->widthp = tt_face_get_device_metrics( face, size_metrics->x_ppem, 0 ); + + size->metrics = size_metrics; + +#ifdef TT_USE_BYTECODE_INTERPRETER + size->cvt_ready = -1; +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_driver_init + * + * @Description: + * Initialize a given TrueType driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_driver_init( FT_Module ttdriver ) /* TT_Driver */ + { + +#ifdef TT_USE_BYTECODE_INTERPRETER + + TT_Driver driver = (TT_Driver)ttdriver; + + driver->interpreter_version = TT_INTERPRETER_VERSION_35; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + driver->interpreter_version = TT_INTERPRETER_VERSION_40; +#endif + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( ttdriver ); + +#endif /* !TT_USE_BYTECODE_INTERPRETER */ + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_driver_done + * + * @Description: + * Finalize a given TrueType driver. + * + * @Input: + * driver :: + * A handle to the target TrueType driver. + */ + FT_LOCAL_DEF( void ) + tt_driver_done( FT_Module ttdriver ) /* TT_Driver */ + { + FT_UNUSED( ttdriver ); + } + + + /************************************************************************** + * + * @Function: + * tt_slot_init + * + * @Description: + * Initialize a new slot object. + * + * @InOut: + * slot :: + * A handle to the slot object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ) + { + return FT_GlyphLoader_CreateExtra( slot->internal->loader ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttobjs.h b/Dependencies/freetype/freetype/src/truetype/ttobjs.h new file mode 100644 index 00000000..9c36ca78 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttobjs.h @@ -0,0 +1,426 @@ +/**************************************************************************** + * + * ttobjs.h + * + * Objects manager (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTOBJS_H_ +#define TTOBJS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Type: + * TT_Driver + * + * @Description: + * A handle to a TrueType driver object. + */ + typedef struct TT_DriverRec_* TT_Driver; + + + /************************************************************************** + * + * @Type: + * TT_GlyphSlot + * + * @Description: + * A handle to a TrueType glyph slot object. + * + * @Note: + * This is a direct typedef of FT_GlyphSlot, as there is nothing + * specific about the TrueType glyph slot. + */ + typedef FT_GlyphSlot TT_GlyphSlot; + + + /************************************************************************** + * + * @Struct: + * TT_GraphicsState + * + * @Description: + * The TrueType graphics state used during bytecode interpretation. + */ + typedef struct TT_GraphicsState_ + { + FT_UShort rp0; + FT_UShort rp1; + FT_UShort rp2; + + FT_UnitVector dualVector; + FT_UnitVector projVector; + FT_UnitVector freeVector; + + FT_Long loop; + FT_F26Dot6 minimum_distance; + FT_Int round_state; + + FT_Bool auto_flip; + FT_F26Dot6 control_value_cutin; + FT_F26Dot6 single_width_cutin; + FT_F26Dot6 single_width_value; + FT_UShort delta_base; + FT_UShort delta_shift; + + FT_Byte instruct_control; + /* According to Greg Hitchcock from Microsoft, the `scan_control' */ + /* variable as documented in the TrueType specification is a 32-bit */ + /* integer; the high-word part holds the SCANTYPE value, the low-word */ + /* part the SCANCTRL value. We separate it into two fields. */ + FT_Bool scan_control; + FT_Int scan_type; + + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + + } TT_GraphicsState; + + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( void ) + tt_glyphzone_done( TT_GlyphZone zone ); + + FT_LOCAL( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_UShort maxContours, + TT_GlyphZone zone ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + + /************************************************************************** + * + * EXECUTION SUBTABLES + * + * These sub-tables relate to instruction execution. + * + */ + + +#define TT_MAX_CODE_RANGES 3 + + + /************************************************************************** + * + * There can only be 3 active code ranges at once: + * - the Font Program + * - the CVT Program + * - a glyph's instructions set + */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + + } TT_CodeRange_Tag; + + + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_Long size; + + } TT_CodeRange; + + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; + + + /************************************************************************** + * + * Defines a function/instruction definition record. + */ + typedef struct TT_DefRecord_ + { + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_Long end; /* where does it end? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + + /************************************************************************** + * + * Subglyph transformation record. + */ + typedef struct TT_Transform_ + { + FT_Fixed xx, xy; /* transformation matrix coefficients */ + FT_Fixed yx, yy; + FT_F26Dot6 ox, oy; /* offsets */ + + } TT_Transform; + + + /************************************************************************** + * + * A note regarding non-squared pixels: + * + * (This text will probably go into some docs at some time; for now, it + * is kept here to explain some definitions in the TT_Size_Metrics + * record). + * + * The CVT is a one-dimensional array containing values that control + * certain important characteristics in a font, like the height of all + * capitals, all lowercase letter, default spacing or stem width/height. + * + * These values are found in FUnits in the font file, and must be scaled + * to pixel coordinates before being used by the CVT and glyph programs. + * Unfortunately, when using distinct x and y resolutions (or distinct x + * and y pointsizes), there are two possible scalings. + * + * A first try was to implement a `lazy' scheme where all values were + * scaled when first used. However, while some values are always used + * in the same direction, some others are used under many different + * circumstances and orientations. + * + * I have found a simpler way to do the same, and it even seems to work + * in most of the cases: + * + * - All CVT values are scaled to the maximum ppem size. + * + * - When performing a read or write in the CVT, a ratio factor is used + * to perform adequate scaling. Example: + * + * x_ppem = 14 + * y_ppem = 10 + * + * We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt + * entries are scaled to it. + * + * x_ratio = 1.0 + * y_ratio = y_ppem/ppem (< 1.0) + * + * We compute the current ratio like: + * + * - If projVector is horizontal, + * ratio = x_ratio = 1.0 + * + * - if projVector is vertical, + * ratio = y_ratio + * + * - else, + * ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) + * + * Reading a cvt value returns + * ratio * cvt[index] + * + * Writing a cvt value in pixels: + * cvt[index] / ratio + * + * The current ppem is simply + * ratio * ppem + * + */ + + + /************************************************************************** + * + * Metrics used by the TrueType size and context objects. + */ + typedef struct TT_Size_Metrics_ + { + /* for non-square pixels */ + FT_Long x_ratio; + FT_Long y_ratio; + + FT_UShort ppem; /* maximum ppem size */ + FT_Long ratio; /* current ratio */ + FT_Fixed scale; + + FT_F26Dot6 compensations[4]; /* device-specific compensations */ + + FT_Bool valid; + + FT_Bool rotated; /* `is the glyph rotated?'-flag */ + FT_Bool stretched; /* `is the glyph stretched?'-flag */ + + } TT_Size_Metrics; + + + /************************************************************************** + * + * TrueType size class. + */ + typedef struct TT_SizeRec_ + { + FT_SizeRec root; + + /* we have our own copy of metrics so that we can modify */ + /* it without affecting auto-hinting (when used) */ + FT_Size_Metrics* metrics; /* for the current rendering mode */ + FT_Size_Metrics hinted_metrics; /* for the hinted rendering mode */ + + TT_Size_Metrics ttmetrics; + + FT_Byte* widthp; /* glyph widths from the hdmx table */ + + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Long point_size; /* for the `MPS' bytecode instruction */ + + FT_UInt num_function_defs; /* number of function definitions */ + FT_UInt max_function_defs; + TT_DefArray function_defs; /* table of function definitions */ + + FT_UInt num_instruction_defs; /* number of ins. definitions */ + FT_UInt max_instruction_defs; + TT_DefArray instruction_defs; /* table of ins. definitions */ + + FT_UInt max_func; + FT_UInt max_ins; + + TT_CodeRangeTable codeRangeTable; + + TT_GraphicsState GS; + + FT_ULong cvt_size; /* the scaled control value table */ + FT_Long* cvt; + + FT_UShort storage_size; /* The storage area is now part of */ + FT_Long* storage; /* the instance */ + + TT_GlyphZoneRec twilight; /* The instance's twilight zone */ + + TT_ExecContext context; + + /* if negative, `fpgm' (resp. `prep'), wasn't executed yet; */ + /* otherwise it is the returned error code */ + FT_Error bytecode_ready; + FT_Error cvt_ready; + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + } TT_SizeRec; + + + /************************************************************************** + * + * TrueType driver class. + */ + typedef struct TT_DriverRec_ + { + FT_DriverRec root; + + TT_GlyphZoneRec zone; /* glyph loader points zone */ + + FT_UInt interpreter_version; + + } TT_DriverRec; + + + /* Note: All of the functions below (except tt_size_reset()) are used */ + /* as function pointers in a FT_Driver_ClassRec. Therefore their */ + /* parameters are of types FT_Face, FT_Size, etc., rather than TT_Face, */ + /* TT_Size, etc., so that the compiler can confirm that the types and */ + /* number of parameters are correct. In all cases the FT_xxx types are */ + /* cast to their TT_xxx counterparts inside the functions since FreeType */ + /* will always use the TT driver to create them. */ + + + /************************************************************************** + * + * Face functions + */ + FT_LOCAL( FT_Error ) + tt_face_init( FT_Stream stream, + FT_Face ttface, /* TT_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + tt_face_done( FT_Face ttface ); /* TT_Face */ + + + /************************************************************************** + * + * Size functions + */ + FT_LOCAL( FT_Error ) + tt_size_init( FT_Size ttsize ); /* TT_Size */ + + FT_LOCAL( void ) + tt_size_done( FT_Size ttsize ); /* TT_Size */ + +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_LOCAL( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ); + + FT_LOCAL( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ); + + FT_LOCAL( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ); + +#endif /* TT_USE_BYTECODE_INTERPRETER */ + + FT_LOCAL( FT_Error ) + tt_size_reset_height( FT_Size size ); + + FT_LOCAL( FT_Error ) + tt_size_reset( TT_Size size ); + + + /************************************************************************** + * + * Driver functions + */ + FT_LOCAL( FT_Error ) + tt_driver_init( FT_Module ttdriver ); /* TT_Driver */ + + FT_LOCAL( void ) + tt_driver_done( FT_Module ttdriver ); /* TT_Driver */ + + + /************************************************************************** + * + * Slot functions + */ + FT_LOCAL( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ); + + + /* auxiliary */ +#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) + + +FT_END_HEADER + +#endif /* TTOBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttpload.c b/Dependencies/freetype/freetype/src/truetype/ttpload.c new file mode 100644 index 00000000..9505b5f1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttpload.c @@ -0,0 +1,665 @@ +/**************************************************************************** + * + * ttpload.c + * + * TrueType-specific tables loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include + +#include "ttpload.h" + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif + +#include "tterrors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttpload + + + /************************************************************************** + * + * @Function: + * tt_face_load_loca + * + * @Description: + * Load the locations table. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * The input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + FT_Int shift; + + + /* we need the size of the `glyf' table for malformed `loca' tables */ + error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); + + /* it is possible that a font doesn't have a glyf table at all */ + /* or its size is zero */ + if ( FT_ERR_EQ( error, Table_Missing ) ) + { + face->glyf_len = 0; + face->glyf_offset = 0; + } + else if ( error ) + goto Exit; + else + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + face->glyf_offset = 0; + else +#endif + face->glyf_offset = FT_STREAM_POS(); + } + + FT_TRACE2(( "Locations " )); + error = face->goto_table( face, TTAG_loca, stream, &table_len ); + if ( error ) + { + error = FT_THROW( Locations_Missing ); + goto Exit; + } + + shift = face->header.Index_To_Loc_Format != 0 ? 2 : 1; + + if ( table_len > 0x10000UL << shift ) + { + FT_TRACE2(( "table too large\n" )); + table_len = 0x10000UL << shift; + } + + face->num_locations = table_len >> shift; + + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) + { + FT_TRACE2(( "glyph count mismatch! loca: %ld, maxp: %ld\n", + face->num_locations - 1, face->root.num_glyphs )); + + /* we only handle the case where `maxp' gives a larger value */ + if ( face->num_locations < (FT_ULong)face->root.num_glyphs + 1 ) + { + FT_ULong new_loca_len = + ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; + + TT_Table entry = face->dir_tables; + TT_Table limit = entry + face->num_tables; + + FT_Long pos = (FT_Long)FT_STREAM_POS(); + FT_Long dist = 0x7FFFFFFFL; + FT_Bool found = 0; + + + /* compute the distance to next table in font file */ + for ( ; entry < limit; entry++ ) + { + FT_Long diff = (FT_Long)entry->Offset - pos; + + + if ( diff > 0 && diff < dist ) + { + dist = diff; + found = 1; + } + } + + if ( !found ) + { + /* `loca' is the last table */ + dist = (FT_Long)stream->size - pos; + } + + if ( new_loca_len <= (FT_ULong)dist ) + { + face->num_locations = (FT_ULong)face->root.num_glyphs + 1; + table_len = new_loca_len; + + FT_TRACE2(( "adjusting num_locations to %ld\n", + face->num_locations )); + } + else + { + face->root.num_glyphs = face->num_locations + ? (FT_Long)face->num_locations - 1 : 0; + + FT_TRACE2(( "adjusting num_glyphs to %ld\n", + face->root.num_glyphs )); + } + } + } + + /* + * Extract the frame. We don't need to decompress it since + * we are able to parse it directly. + */ + if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) + goto Exit; + + FT_TRACE2(( "loaded\n" )); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_ULong ) + tt_face_get_location( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_ULong *asize ) + { + TT_Face ttface = (TT_Face)face; + FT_ULong pos1, pos2; + FT_Byte* p; + FT_Byte* p_limit; + + + pos1 = pos2 = 0; + + if ( gindex < ttface->num_locations ) + { + if ( ttface->header.Index_To_Loc_Format != 0 ) + { + p = ttface->glyph_locations + gindex * 4; + p_limit = ttface->glyph_locations + ttface->num_locations * 4; + + pos1 = FT_NEXT_ULONG( p ); + pos2 = pos1; + + if ( p + 4 <= p_limit ) + pos2 = FT_NEXT_ULONG( p ); + } + else + { + p = ttface->glyph_locations + gindex * 2; + p_limit = ttface->glyph_locations + ttface->num_locations * 2; + + pos1 = FT_NEXT_USHORT( p ); + pos2 = pos1; + + if ( p + 2 <= p_limit ) + pos2 = FT_NEXT_USHORT( p ); + + pos1 <<= 1; + pos2 <<= 1; + } + } + + /* Check broken location data. */ + if ( pos1 > ttface->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %d,\n", + pos1, gindex )); + FT_TRACE1(( " " + " exceeding the end of `glyf' table (0x%08lx)\n", + ttface->glyf_len )); + *asize = 0; + return 0; + } + + if ( pos2 > ttface->glyf_len ) + { + /* We try to sanitize the last `loca' entry. */ + if ( gindex == ttface->num_locations - 2 ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large size (%ld bytes) found for glyph index %d,\n", + pos2 - pos1, gindex )); + FT_TRACE1(( " " + " truncating at the end of `glyf' table to %ld bytes\n", + ttface->glyf_len - pos1 )); + pos2 = ttface->glyf_len; + } + else + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %d,\n", + pos2, gindex + 1 )); + FT_TRACE1(( " " + " exceeding the end of `glyf' table (0x%08lx)\n", + ttface->glyf_len )); + *asize = 0; + return 0; + } + } + + /* The `loca' table must be ordered; it refers to the length of */ + /* an entry as the difference between the current and the next */ + /* position. However, there do exist (malformed) fonts which */ + /* don't obey this rule, so we are only able to provide an */ + /* upper bound for the size. */ + /* */ + /* We get (intentionally) a wrong, non-zero result in case the */ + /* `glyf' table is missing. */ + if ( pos2 >= pos1 ) + *asize = (FT_ULong)( pos2 - pos1 ); + else + *asize = (FT_ULong)( ttface->glyf_len - pos1 ); + + return pos1; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_loca( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->glyph_locations ); + face->num_locations = 0; + } + + + + /************************************************************************** + * + * @Function: + * tt_face_load_cvt + * + * @Description: + * Load the control value table into a face object. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_len; + + + FT_TRACE2(( "CVT " )); + + error = face->goto_table( face, TTAG_cvt, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + + face->cvt_size = 0; + face->cvt = NULL; + error = FT_Err_Ok; + + goto Exit; + } + + face->cvt_size = table_len / 2; + + if ( FT_QNEW_ARRAY( face->cvt, face->cvt_size ) ) + goto Exit; + + if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) + goto Exit; + + { + FT_Int32* cur = face->cvt; + FT_Int32* limit = cur + face->cvt_size; + + + for ( ; cur < limit; cur++ ) + *cur = FT_GET_SHORT() * 64; + } + + FT_FRAME_EXIT(); + FT_TRACE2(( "loaded\n" )); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( face->doblend ) + error = tt_face_vary_cvt( face, stream ); +#endif + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_fpgm + * + * @Description: + * Load the font program. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Font program " )); + + /* The font program is optional */ + error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); + if ( error ) + { + face->font_program = NULL; + face->font_program_size = 0; + error = FT_Err_Ok; + + FT_TRACE2(( "is missing\n" )); + } + else + { + face->font_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12ld bytes\n", face->font_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_prep + * + * @Description: + * Load the cvt program. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ) + { +#ifdef TT_USE_BYTECODE_INTERPRETER + + FT_Error error; + FT_ULong table_len; + + + FT_TRACE2(( "Prep program " )); + + error = face->goto_table( face, TTAG_prep, stream, &table_len ); + if ( error ) + { + face->cvt_program = NULL; + face->cvt_program_size = 0; + error = FT_Err_Ok; + + FT_TRACE2(( "is missing\n" )); + } + else + { + face->cvt_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) + goto Exit; + + FT_TRACE2(( "loaded, %12ld bytes\n", face->cvt_program_size )); + } + + Exit: + return error; + +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif + } + + + FT_COMPARE_DEF( int ) + compare_ppem( const void* a, + const void* b ) + { + return **(FT_Byte**)a - **(FT_Byte**)b; + } + + + /************************************************************************** + * + * @Function: + * tt_face_load_hdmx + * + * @Description: + * Load the `hdmx' table into the face object. + * + * @Input: + * face :: + * A handle to the target face object. + * + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + */ + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt nn, num_records; + FT_ULong table_size, record_size; + FT_Byte* p; + FT_Byte* limit; + + + /* this table is optional */ + error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); + if ( error || table_size < 8 ) + return FT_Err_Ok; + + if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) + goto Exit; + + p = face->hdmx_table; + limit = p + table_size; + + /* Given that `hdmx' tables are losing its importance (for example, */ + /* variation fonts introduced in OpenType 1.8 must not have this */ + /* table) we no longer test for a correct `version' field. */ + p += 2; + num_records = FT_NEXT_USHORT( p ); + record_size = FT_NEXT_ULONG( p ); + + /* There are at least two fonts, HANNOM-A and HANNOM-B version */ + /* 2.0 (2005), which get this wrong: The upper two bytes of */ + /* the size value are set to 0xFF instead of 0x00. We catch */ + /* and fix this. */ + + if ( record_size >= 0xFFFF0000UL ) + record_size &= 0xFFFFU; + + FT_TRACE2(( "Hdmx " )); + + /* The limit for `num_records' is a heuristic value. */ + if ( num_records > 255 || num_records == 0 ) + { + FT_TRACE2(( "with unreasonable %u records rejected\n", num_records )); + goto Fail; + } + + /* Out-of-spec tables are rejected. The record size must be */ + /* equal to the number of glyphs + 2 + 32-bit padding. */ + if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) ) + { + FT_TRACE2(( "with record size off by %ld bytes rejected\n", + (FT_Long)record_size - + ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) )); + goto Fail; + } + + if ( FT_QNEW_ARRAY( face->hdmx_records, num_records ) ) + goto Fail; + + for ( nn = 0; nn < num_records; nn++ ) + { + if ( p + record_size > limit ) + break; + face->hdmx_records[nn] = p; + p += record_size; + } + + /* The records must be already sorted by ppem but it does not */ + /* hurt to make sure so that the binary search works later. */ + ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem ); + + face->hdmx_record_count = nn; + face->hdmx_table_size = table_size; + face->hdmx_record_size = record_size; + + FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size )); + + Exit: + return error; + + Fail: + FT_FRAME_RELEASE( face->hdmx_table ); + face->hdmx_table_size = 0; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_hdmx( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + + + FT_FREE( face->hdmx_records ); + FT_FRAME_RELEASE( face->hdmx_table ); + } + + + /************************************************************************** + * + * Return the advance width table for a given pixel size if it is found + * in the font's `hdmx' table (if any). The records must be sorted for + * the binary search to work properly. + */ + FT_LOCAL_DEF( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ) + { + FT_UInt min = 0; + FT_UInt max = face->hdmx_record_count; + FT_UInt mid; + FT_Byte* result = NULL; + + + while ( min < max ) + { + mid = ( min + max ) >> 1; + + if ( face->hdmx_records[mid][0] > ppem ) + max = mid; + else if ( face->hdmx_records[mid][0] < ppem ) + min = mid + 1; + else + { + result = face->hdmx_records[mid] + 2 + gindex; + break; + } + } + + return result; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/truetype/ttpload.h b/Dependencies/freetype/freetype/src/truetype/ttpload.h new file mode 100644 index 00000000..bc32b580 --- /dev/null +++ b/Dependencies/freetype/freetype/src/truetype/ttpload.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * + * ttpload.h + * + * TrueType-specific tables loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef TTPLOAD_H_ +#define TTPLOAD_H_ + + +#include + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_ULong ) + tt_face_get_location( FT_Face face, + FT_UInt gindex, + FT_ULong *asize ); + + FT_LOCAL( void ) + tt_face_done_loca( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ); + + + FT_LOCAL( void ) + tt_face_free_hdmx( TT_Face face ); + + + FT_LOCAL( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ); + +FT_END_HEADER + +#endif /* TTPLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1afm.c b/Dependencies/freetype/freetype/src/type1/t1afm.c new file mode 100644 index 00000000..a63cd4dc --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1afm.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * t1afm.c + * + * AFM support for Type 1 fonts (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1afm.h" +#include +#include +#include +#include "t1errors.h" + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1afm + + + FT_LOCAL_DEF( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + + FT_FREE( fi ); + } + + + /* read a glyph name and return the equivalent glyph index */ + static FT_Int + t1_get_index( const char* name, + FT_Offset len, + void* user_data ) + { + T1_Font type1 = (T1_Font)user_data; + FT_Int n; + + + /* PS string/name length must be < 16-bit */ + if ( len > 0xFFFFU ) + return 0; + + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + + if ( gname && gname[0] == name[0] && + ft_strlen( gname ) == len && + ft_strncmp( gname, name, len ) == 0 ) + return n; + } + + return 0; + } + + +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + + /* compare two kerning pairs */ + FT_COMPARE_DEF( int ) + compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair pair1 = (AFM_KernPair)a; + AFM_KernPair pair2 = (AFM_KernPair)b; + + FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); + FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); + + + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } + + + /* parse a PFM file -- for now, only read the kerning pairs */ + static FT_Error + T1_Read_PFM( FT_Face t1_face, + FT_Stream stream, + AFM_FontInfo fi ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + AFM_KernPair kp; + FT_Int width_table_length; + FT_CharMap oldcharmap; + FT_CharMap charmap; + FT_Int n; + + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + + /* Figure out how long the width table is. */ + /* This info is a little-endian short at offset 99. */ + p = start + 99; + if ( p + 2 > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + width_table_length = FT_PEEK_USHORT_LE( p ); + + p += 18 + width_table_length; + if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) + /* extension table is probably optional */ + goto Exit; + + /* Kerning offset is 14 bytes from start of extensions table. */ + p += 14; + p = start + FT_PEEK_ULONG_LE( p ); + + if ( p == start ) + /* zero offset means no table */ + goto Exit; + + if ( p + 2 > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + fi->NumKernPair = FT_PEEK_USHORT_LE( p ); + p += 2; + if ( p + 4 * fi->NumKernPair > limit ) + { + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Actually, kerning pairs are simply optional! */ + if ( fi->NumKernPair == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + goto Exit; + + /* now, read each kern pair */ + kp = fi->KernPairs; + limit = p + 4 * fi->NumKernPair; + + /* PFM kerning data are stored by encoding rather than glyph index, */ + /* so find the PostScript charmap of this font and install it */ + /* temporarily. If we find no PostScript charmap, then just use */ + /* the default and hope it is the right one. */ + oldcharmap = t1_face->charmap; + + for ( n = 0; n < t1_face->num_charmaps; n++ ) + { + charmap = t1_face->charmaps[n]; + /* check against PostScript pseudo platform */ + if ( charmap->platform_id == 7 ) + { + t1_face->charmap = charmap; + break; + } + } + + /* Kerning info is stored as: */ + /* */ + /* encoding of first glyph (1 byte) */ + /* encoding of second glyph (1 byte) */ + /* offset (little-endian short) */ + for ( ; p < limit; p += 4 ) + { + kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); + kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); + + kp->x = (FT_Int)FT_PEEK_SHORT_LE( p + 2 ); + kp->y = 0; + + kp++; + } + + t1_face->charmap = oldcharmap; + + /* now, sort the kern pairs according to their glyph indices */ + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), + compare_kern_pairs ); + + Exit: + if ( error ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + } + + return error; + } + + + /* parse a metrics file -- either AFM or PFM depending on what */ + /* it turns out to be */ + FT_LOCAL_DEF( FT_Error ) + T1_Read_Metrics( FT_Face t1_face, + FT_Stream stream ) + { + PSAux_Service psaux; + FT_Memory memory = stream->memory; + AFM_ParserRec parser; + AFM_FontInfo fi = NULL; + FT_Error error = FT_ERR( Unknown_File_Format ); + T1_Face face = (T1_Face)t1_face; + T1_Font t1_font = &face->type1; + + + if ( face->afm_data ) + { + FT_TRACE1(( "T1_Read_Metrics:" + " Freeing previously attached metrics data.\n" )); + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); + + face->afm_data = NULL; + } + + if ( FT_NEW( fi ) || + FT_FRAME_ENTER( stream->size ) ) + goto Exit; + + fi->FontBBox = t1_font->font_bbox; + fi->Ascender = t1_font->font_bbox.yMax; + fi->Descender = t1_font->font_bbox.yMin; + + psaux = (PSAux_Service)face->psaux; + if ( psaux->afm_parser_funcs ) + { + error = psaux->afm_parser_funcs->init( &parser, + stream->memory, + stream->cursor, + stream->limit ); + + if ( !error ) + { + parser.FontInfo = fi; + parser.get_index = t1_get_index; + parser.user_data = t1_font; + + error = psaux->afm_parser_funcs->parse( &parser ); + psaux->afm_parser_funcs->done( &parser ); + } + } + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + FT_Byte* start = stream->cursor; + + + /* MS Windows allows versions up to 0x3FF without complaining */ + if ( stream->size > 6 && + start[1] < 4 && + FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) + error = T1_Read_PFM( t1_face, stream, fi ); + } + + if ( !error ) + { + t1_font->font_bbox = fi->FontBBox; + + t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; + t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; + t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; + + /* ascender and descender are optional and could both be zero */ + /* check if values are meaningful before overriding defaults */ + if ( fi->Ascender > fi->Descender ) + { + /* no `U' suffix here to 0x8000! */ + t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); + t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); + } + + if ( fi->NumKernPair ) + { + t1_face->face_flags |= FT_FACE_FLAG_KERNING; + face->afm_data = fi; + fi = NULL; + } + } + + FT_FRAME_EXIT(); + + Exit: + if ( fi ) + T1_Done_Metrics( memory, fi ); + + return error; + } + + + /* find the kerning for a given glyph pair */ + FT_LOCAL_DEF( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + AFM_KernPair min, mid, max; + FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); + + + /* simple binary search */ + min = fi->KernPairs; + max = min + fi->NumKernPair - 1; + + while ( min <= max ) + { + FT_ULong midi; + + + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->index1, mid->index2 ); + + if ( midi == idx ) + { + kerning->x = mid->x; + kerning->y = mid->y; + + return; + } + + if ( midi < idx ) + min = mid + 1; + else + max = mid - 1; + } + + kerning->x = 0; + kerning->y = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ) + { + AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; + FT_UInt i; + + + if ( !fi ) + return FT_THROW( Invalid_Argument ); + + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + + + if ( tk->degree != degree ) + continue; + + if ( ptsize < tk->min_ptsize ) + *kerning = tk->min_kern; + else if ( ptsize > tk->max_ptsize ) + *kerning = tk->max_kern; + else + { + *kerning = FT_MulDiv( ptsize - tk->min_ptsize, + tk->max_kern - tk->min_kern, + tk->max_ptsize - tk->min_ptsize ) + + tk->min_kern; + } + } + + return FT_Err_Ok; + } + +#else /* T1_CONFIG_OPTION_NO_AFM */ + + /* ANSI C doesn't like empty source files */ + typedef int t1_afm_dummy_; + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1afm.h b/Dependencies/freetype/freetype/src/type1/t1afm.h new file mode 100644 index 00000000..7f5cdda1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1afm.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * + * t1afm.h + * + * AFM support for Type 1 fonts (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1AFM_H_ +#define T1AFM_H_ + +#include "t1objs.h" +#include + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Read_Metrics( FT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ); + + FT_LOCAL( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + + FT_LOCAL( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ); + +FT_END_HEADER + +#endif /* T1AFM_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1driver.c b/Dependencies/freetype/freetype/src/type1/t1driver.c new file mode 100644 index 00000000..8ed01914 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1driver.c @@ -0,0 +1,807 @@ +/**************************************************************************** + * + * t1driver.c + * + * Type 1 driver interface (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1driver.h" +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1driver + + /* + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t1_get_glyph_name( FT_Face face, /* T1_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + T1_Face t1face = (T1_Face)face; + + + FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max ); + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t1_get_name_index( FT_Face face, /* T1_Face */ + const FT_String* glyph_name ) + { + T1_Face t1face = (T1_Face)face; + FT_Int i; + + + for ( i = 0; i < t1face->type1.num_glyphs; i++ ) + { + FT_String* gname = t1face->type1.glyph_names[i]; + + + if ( !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)i; + } + + return 0; + } + + + static const FT_Service_GlyphDictRec t1_service_glyph_dict = + { + t1_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + t1_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ + }; + + + /* + * POSTSCRIPT NAME SERVICE + * + */ + + static const char* + t1_get_ps_name( FT_Face face ) /* T1_Face */ + { + T1_Face t1face = (T1_Face)face; + + + return (const char*) t1face->type1.font_name; + } + + + static const FT_Service_PsFontNameRec t1_service_ps_name = + { + (FT_PsName_GetFunc)t1_get_ps_name /* get_ps_font_name */ + }; + + + /* + * MULTIPLE MASTERS SERVICE + * + */ + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + static const FT_Service_MultiMastersRec t1_service_multi_masters = + { + T1_Get_Multi_Master, /* FT_Get_MM_Func get_mm */ + T1_Set_MM_Design, /* FT_Set_MM_Design_Func set_mm_design */ + T1_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + T1_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + T1_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + T1_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + T1_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + T1_Reset_MM_Blend, /* FT_Set_Named_Instance_Func set_named_instance */ + NULL, /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + T1_Set_MM_WeightVector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + T1_Get_MM_WeightVector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + + NULL, /* FT_Construct_PS_Name_Func construct_ps_name */ + NULL, /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + NULL, /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + NULL, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + NULL, /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + NULL, /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + NULL, /* FT_Get_Var_Blend_Func get_var_blend */ + T1_Done_Blend /* FT_Done_Blend_Func done_blend */ + }; +#endif + + + /* + * POSTSCRIPT INFO SERVICE + * + */ + + static FT_Error + t1_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T1_Face)face)->type1.font_info; + + return FT_Err_Ok; + } + + + static FT_Error + t1_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T1_Face)face)->type1.font_extra; + + return FT_Err_Ok; + } + + + static FT_Int + t1_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + + return 1; + } + + + static FT_Error + t1_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T1_Face)face)->type1.private_dict; + + return FT_Err_Ok; + } + + + static FT_Long + t1_ps_get_font_value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len_ ) + { + FT_ULong retval = 0; /* always >= 1 if valid */ + FT_ULong value_len = value_len_ < 0 ? 0 : (FT_ULong)value_len_; + + T1_Face t1face = (T1_Face)face; + T1_Font type1 = &t1face->type1; + + + switch ( key ) + { + case PS_DICT_FONT_TYPE: + retval = sizeof ( type1->font_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->font_type; + break; + + case PS_DICT_FONT_MATRIX: + if ( idx < sizeof ( type1->font_matrix ) / + sizeof ( type1->font_matrix.xx ) ) + { + FT_Fixed val = 0; + + + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_matrix.xx; + break; + case 1: + val = type1->font_matrix.xy; + break; + case 2: + val = type1->font_matrix.yx; + break; + case 3: + val = type1->font_matrix.yy; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + + case PS_DICT_FONT_BBOX: + if ( idx < sizeof ( type1->font_bbox ) / + sizeof ( type1->font_bbox.xMin ) ) + { + FT_Fixed val = 0; + + + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_bbox.xMin; + break; + case 1: + val = type1->font_bbox.yMin; + break; + case 2: + val = type1->font_bbox.xMax; + break; + case 3: + val = type1->font_bbox.yMax; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + + case PS_DICT_PAINT_TYPE: + retval = sizeof ( type1->paint_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->paint_type; + break; + + case PS_DICT_FONT_NAME: + if ( type1->font_name ) + { + retval = ft_strlen( type1->font_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_name ), retval ); + } + break; + + case PS_DICT_UNIQUE_ID: + retval = sizeof ( type1->private_dict.unique_id ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.unique_id; + break; + + case PS_DICT_NUM_CHAR_STRINGS: + retval = sizeof ( type1->num_glyphs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_glyphs; + break; + + case PS_DICT_CHAR_STRING_KEY: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = ft_strlen( type1->glyph_names[idx] ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->glyph_names[idx] ), retval ); + } + break; + + case PS_DICT_CHAR_STRING: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = type1->charstrings_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->charstrings[idx] ), + retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + + case PS_DICT_ENCODING_TYPE: + retval = sizeof ( type1->encoding_type ); + if ( value && value_len >= retval ) + *((T1_EncodingType *)value) = type1->encoding_type; + break; + + case PS_DICT_ENCODING_ENTRY: + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY && + idx < (FT_UInt)type1->encoding.num_chars ) + { + retval = ft_strlen( type1->encoding.char_name[idx] ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->encoding.char_name[idx] ), + retval ); + } + break; + + case PS_DICT_NUM_SUBRS: + retval = sizeof ( type1->num_subrs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_subrs; + break; + + case PS_DICT_SUBR: + { + FT_Bool ok = 0; + + + if ( type1->subrs_hash ) + { + /* convert subr index to array index */ + size_t* val = ft_hash_num_lookup( (FT_Int)idx, + type1->subrs_hash ); + + + if ( val ) + { + idx = *val; + ok = 1; + } + } + else + { + if ( idx < (FT_UInt)type1->num_subrs ) + ok = 1; + } + + if ( ok && type1->subrs ) + { + retval = type1->subrs_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + } + break; + + case PS_DICT_STD_HW: + retval = sizeof ( type1->private_dict.standard_width[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_width[0]; + break; + + case PS_DICT_STD_VW: + retval = sizeof ( type1->private_dict.standard_height[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_height[0]; + break; + + case PS_DICT_NUM_BLUE_VALUES: + retval = sizeof ( type1->private_dict.num_blue_values ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_blue_values; + break; + + case PS_DICT_BLUE_VALUE: + if ( idx < type1->private_dict.num_blue_values ) + { + retval = sizeof ( type1->private_dict.blue_values[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.blue_values[idx]; + } + break; + + case PS_DICT_BLUE_SCALE: + retval = sizeof ( type1->private_dict.blue_scale ); + if ( value && value_len >= retval ) + *((FT_Fixed *)value) = type1->private_dict.blue_scale; + break; + + case PS_DICT_BLUE_FUZZ: + retval = sizeof ( type1->private_dict.blue_fuzz ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_fuzz; + break; + + case PS_DICT_BLUE_SHIFT: + retval = sizeof ( type1->private_dict.blue_shift ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_shift; + break; + + case PS_DICT_NUM_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_other_blues; + break; + + case PS_DICT_OTHER_BLUE: + if ( idx < type1->private_dict.num_other_blues ) + { + retval = sizeof ( type1->private_dict.other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.other_blues[idx]; + } + break; + + case PS_DICT_NUM_FAMILY_BLUES: + retval = sizeof ( type1->private_dict.num_family_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_blues; + break; + + case PS_DICT_FAMILY_BLUE: + if ( idx < type1->private_dict.num_family_blues ) + { + retval = sizeof ( type1->private_dict.family_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_blues[idx]; + } + break; + + case PS_DICT_NUM_FAMILY_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_family_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_other_blues; + break; + + case PS_DICT_FAMILY_OTHER_BLUE: + if ( idx < type1->private_dict.num_family_other_blues ) + { + retval = sizeof ( type1->private_dict.family_other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_other_blues[idx]; + } + break; + + case PS_DICT_NUM_STEM_SNAP_H: + retval = sizeof ( type1->private_dict.num_snap_widths ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_widths; + break; + + case PS_DICT_STEM_SNAP_H: + if ( idx < type1->private_dict.num_snap_widths ) + { + retval = sizeof ( type1->private_dict.snap_widths[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_widths[idx]; + } + break; + + case PS_DICT_NUM_STEM_SNAP_V: + retval = sizeof ( type1->private_dict.num_snap_heights ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_heights; + break; + + case PS_DICT_STEM_SNAP_V: + if ( idx < type1->private_dict.num_snap_heights ) + { + retval = sizeof ( type1->private_dict.snap_heights[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_heights[idx]; + } + break; + + case PS_DICT_RND_STEM_UP: + retval = sizeof ( type1->private_dict.round_stem_up ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.round_stem_up; + break; + + case PS_DICT_FORCE_BOLD: + retval = sizeof ( type1->private_dict.force_bold ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.force_bold; + break; + + case PS_DICT_MIN_FEATURE: + if ( idx < sizeof ( type1->private_dict.min_feature ) / + sizeof ( type1->private_dict.min_feature[0] ) ) + { + retval = sizeof ( type1->private_dict.min_feature[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.min_feature[idx]; + } + break; + + case PS_DICT_LEN_IV: + retval = sizeof ( type1->private_dict.lenIV ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.lenIV; + break; + + case PS_DICT_PASSWORD: + retval = sizeof ( type1->private_dict.password ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.password; + break; + + case PS_DICT_LANGUAGE_GROUP: + retval = sizeof ( type1->private_dict.language_group ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.language_group; + break; + + case PS_DICT_IS_FIXED_PITCH: + retval = sizeof ( type1->font_info.is_fixed_pitch ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->font_info.is_fixed_pitch; + break; + + case PS_DICT_UNDERLINE_POSITION: + retval = sizeof ( type1->font_info.underline_position ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->font_info.underline_position; + break; + + case PS_DICT_UNDERLINE_THICKNESS: + retval = sizeof ( type1->font_info.underline_thickness ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_info.underline_thickness; + break; + + case PS_DICT_FS_TYPE: + retval = sizeof ( type1->font_extra.fs_type ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_extra.fs_type; + break; + + case PS_DICT_VERSION: + if ( type1->font_info.version ) + { + retval = ft_strlen( type1->font_info.version ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.version ), retval ); + } + break; + + case PS_DICT_NOTICE: + if ( type1->font_info.notice ) + { + retval = ft_strlen( type1->font_info.notice ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.notice ), retval ); + } + break; + + case PS_DICT_FULL_NAME: + if ( type1->font_info.full_name ) + { + retval = ft_strlen( type1->font_info.full_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.full_name ), retval ); + } + break; + + case PS_DICT_FAMILY_NAME: + if ( type1->font_info.family_name ) + { + retval = ft_strlen( type1->font_info.family_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.family_name ), + retval ); + } + break; + + case PS_DICT_WEIGHT: + if ( type1->font_info.weight ) + { + retval = ft_strlen( type1->font_info.weight ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.weight ), retval ); + } + break; + + case PS_DICT_ITALIC_ANGLE: + retval = sizeof ( type1->font_info.italic_angle ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->font_info.italic_angle; + break; + } + + return retval == 0 ? -1 : (FT_Long)retval; + } + + + static const FT_Service_PsInfoRec t1_service_ps_info = + { + t1_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + t1_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + t1_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + t1_ps_get_font_private, /* PS_GetFontPrivateFunc ps_get_font_private */ + t1_ps_get_font_value, /* PS_GetFontValueFunc ps_get_font_value */ + }; + + +#ifndef T1_CONFIG_OPTION_NO_AFM + static const FT_Service_KerningRec t1_service_kerning = + { + T1_Get_Track_Kerning, /* get_track */ + }; +#endif + + + /* + * PROPERTY SERVICE + * + */ + + FT_DEFINE_SERVICE_PROPERTIESREC( + t1_service_properties, + + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t1_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t1_service_ps_name }, + { FT_SERVICE_ID_GLYPH_DICT, &t1_service_glyph_dict }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TYPE_1 }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t1_service_ps_info }, + { FT_SERVICE_ID_PROPERTIES, &t1_service_properties }, + +#ifndef T1_CONFIG_OPTION_NO_AFM + { FT_SERVICE_ID_KERNING, &t1_service_kerning }, +#endif + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + { FT_SERVICE_ID_MULTI_MASTERS, &t1_service_multi_masters }, +#endif + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + Get_Interface( FT_Module module, + const FT_String* t1_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( t1_services, t1_interface ); + } + + +#ifndef T1_CONFIG_OPTION_NO_AFM + + /************************************************************************** + * + * @Function: + * Get_Kerning + * + * @Description: + * A driver method used to return the kerning vector between two + * glyphs of the same face. + * + * @Input: + * face :: + * A handle to the source face object. + * + * left_glyph :: + * The index of the left glyph in the kern pair. + * + * right_glyph :: + * The index of the right glyph in the kern pair. + * + * @Output: + * kerning :: + * The kerning vector. This is in font units for + * scalable formats, and in pixels for fixed-sizes + * formats. + * + * @Return: + * FreeType error code. 0 means success. + * + * @Note: + * Only horizontal layouts (left-to-right & right-to-left) are + * supported by this function. Other layouts, or more sophisticated + * kernings are out of scope of this method (the basic driver + * interface is meant to be simple). + * + * They can be implemented by format-specific interfaces. + */ + static FT_Error + Get_Kerning( FT_Face t1face, /* T1_Face */ + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + T1_Face face = (T1_Face)t1face; + + + kerning->x = 0; + kerning->y = 0; + + if ( face->afm_data ) + T1_Get_Kerning( (AFM_FontInfo)face->afm_data, + left_glyph, + right_glyph, + kerning ); + + return FT_Err_Ok; + } + + +#endif /* T1_CONFIG_OPTION_NO_AFM */ + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + + sizeof ( PS_DriverRec ), + + "type1", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + T1_Driver_Init, /* FT_Module_Constructor module_init */ + T1_Driver_Done, /* FT_Module_Destructor module_done */ + Get_Interface, /* FT_Module_Requester get_interface */ + }, + + sizeof ( T1_FaceRec ), + sizeof ( T1_SizeRec ), + sizeof ( T1_GlyphSlotRec ), + + T1_Face_Init, /* FT_Face_InitFunc init_face */ + T1_Face_Done, /* FT_Face_DoneFunc done_face */ + T1_Size_Init, /* FT_Size_InitFunc init_size */ + T1_Size_Done, /* FT_Size_DoneFunc done_size */ + T1_GlyphSlot_Init, /* FT_Slot_InitFunc init_slot */ + T1_GlyphSlot_Done, /* FT_Slot_DoneFunc done_slot */ + + T1_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ + +#ifdef T1_CONFIG_OPTION_NO_AFM + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ +#else + Get_Kerning, /* FT_Face_GetKerningFunc get_kerning */ + T1_Read_Metrics, /* FT_Face_AttachFunc attach_file */ +#endif + T1_Get_Advances, /* FT_Face_GetAdvancesFunc get_advances */ + + T1_Size_Request, /* FT_Size_RequestFunc request_size */ + NULL /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1driver.h b/Dependencies/freetype/freetype/src/type1/t1driver.h new file mode 100644 index 00000000..5ff52b55 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1driver.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * t1driver.h + * + * High-level Type 1 driver interface (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1DRIVER_H_ +#define T1DRIVER_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t1_driver_class; + +FT_END_HEADER + +#endif /* T1DRIVER_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1errors.h b/Dependencies/freetype/freetype/src/type1/t1errors.h new file mode 100644 index 00000000..8aeb24ae --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1errors.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * t1errors.h + * + * Type 1 error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Type 1 error enumeration constants. + * + */ + +#ifndef T1ERRORS_H_ +#define T1ERRORS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T1_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type1 + +#include + +#endif /* T1ERRORS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1gload.c b/Dependencies/freetype/freetype/src/type1/t1gload.c new file mode 100644 index 00000000..c29e6825 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1gload.c @@ -0,0 +1,606 @@ +/**************************************************************************** + * + * t1gload.c + * + * Type 1 Glyph Loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t1gload.h" +#include +#include +#include +#include +#include +#include +#include + +#include "t1errors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1gload + + + static FT_Error + T1_Parse_Glyph_And_Get_Char_String( T1_Decoder decoder, + FT_UInt glyph_index, + FT_Data* char_string, + FT_Bool* force_scaling ) + { + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + FT_Error error = FT_Err_Ok; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + PS_Decoder psdecoder; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; +#endif + +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); +#endif + + + decoder->font_matrix = type1->font_matrix; + decoder->font_offset = type1->font_offset; + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* For incremental fonts get the character data using the */ + /* callback function. */ + if ( inc ) + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, char_string ); + else + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + /* For ordinary fonts get the character data stored in the face record. */ + { + char_string->pointer = type1->charstrings[glyph_index]; + char_string->length = type1->charstrings_len[glyph_index]; + } + + if ( !error ) + { + /* choose which renderer to use */ +#ifdef T1_CONFIG_OPTION_OLD_ENGINE + if ( driver->hinting_engine == FT_HINTING_FREETYPE || + decoder->builder.metrics_only ) + error = decoder_funcs->parse_charstrings_old( + decoder, + (FT_Byte*)char_string->pointer, + (FT_UInt)char_string->length ); +#else + if ( decoder->builder.metrics_only ) + error = decoder_funcs->parse_metrics( + decoder, + (FT_Byte*)char_string->pointer, + (FT_UInt)char_string->length ); +#endif + else + { + CFF_SubFontRec subfont; + + + psaux->ps_decoder_init( &psdecoder, decoder, TRUE ); + + psaux->t1_make_subfont( FT_FACE( face ), + &face->type1.private_dict, &subfont ); + psdecoder.current_subfont = &subfont; + + error = decoder_funcs->parse_charstrings( + &psdecoder, + (FT_Byte*)char_string->pointer, + (FT_ULong)char_string->length ); + + /* Adobe's engine uses 16.16 numbers everywhere; */ + /* as a consequence, glyphs larger than 2000ppem get rejected */ + if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) + { + /* this time, we retry unhinted and scale up the glyph later on */ + /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ + /* 0x400 for both `x_scale' and `y_scale' in this case) */ + ((T1_GlyphSlot)decoder->builder.glyph)->hint = FALSE; + + *force_scaling = TRUE; + + error = decoder_funcs->parse_charstrings( + &psdecoder, + (FT_Byte*)char_string->pointer, + (FT_ULong)char_string->length ); + } + } + } + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + /* Incremental fonts can optionally override the metrics. */ + if ( !error && inc && inc->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + + + metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x ); + metrics.bearing_y = 0; + metrics.advance = FIXED_TO_INT( decoder->builder.advance.x ); + metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y ); + + error = inc->funcs->get_glyph_metrics( inc->object, + glyph_index, FALSE, &metrics ); + + decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x ); + decoder->builder.advance.x = INT_TO_FIXED( metrics.advance ); + decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + FT_CALLBACK_DEF( FT_Error ) + T1_Parse_Glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + FT_Data glyph_data; + FT_Bool force_scaling = FALSE; + FT_Error error = T1_Parse_Glyph_And_Get_Char_String( + decoder, glyph_index, &glyph_data, + &force_scaling ); + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + + if ( !error ) + { + T1_Face face = (T1_Face)decoder->builder.face; + + + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + } + +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + + return error; + } + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly processes each glyph charstring to *********/ + /********** extract the value from either a `sbw' or `seac' *********/ + /********** operator. *********/ + /********** *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + *max_advance = 0; + + /* initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + *max_advance = 0; + + FT_TRACE6(( "T1_Compute_Max_Advance:\n" )); + + /* for each glyph, parse the glyph charstring and extract */ + /* the advance width */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + (void)T1_Parse_Glyph( &decoder, (FT_UInt)glyph_index ); + if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance ) + *max_advance = decoder.builder.advance.x; + + /* ignore the error if one occurred - skip to next glyph */ + } + + FT_TRACE6(( "T1_Compute_Max_Advance: max advance: %f\n", + (double)*max_advance / 65536 )); + + psaux->t1_decoder_funcs->done( &decoder ); + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Advances( FT_Face t1face, /* T1_Face */ + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ) + { + T1_Face face = (T1_Face)t1face; + T1_DecoderRec decoder; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_UInt nn; + FT_Error error; + + + FT_TRACE5(( "T1_Get_Advances:\n" )); + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + for ( nn = 0; nn < count; nn++ ) + { + advances[nn] = 0; + + FT_TRACE5(( " idx %d: advance height 0 font units\n", + first + nn )); + } + + return FT_Err_Ok; + } + + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + for ( nn = 0; nn < count; nn++ ) + { + error = T1_Parse_Glyph( &decoder, first + nn ); + if ( !error ) + advances[nn] = FIXED_TO_INT( decoder.builder.advance.x ); + else + advances[nn] = 0; + + FT_TRACE5(( " idx %d: advance width %ld font unit%s\n", + first + nn, + advances[nn], + advances[nn] == 1 ? "" : "s" )); + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Load_Glyph( FT_GlyphSlot t1glyph, /* T1_GlyphSlot */ + FT_Size t1size, /* T1_Size */ + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + T1_GlyphSlot glyph = (T1_GlyphSlot)t1glyph; + FT_Error error; + T1_DecoderRec decoder; + T1_Face face = (T1_Face)t1glyph->face; + FT_Bool hinting; + FT_Bool scaled; + FT_Bool force_scaling = FALSE; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Data glyph_data; + FT_Bool must_finish_decoder = FALSE; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + FT_Bool glyph_data_loaded = 0; +#endif + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_index >= (FT_UInt)face->root.num_glyphs && + !face->root.internal->incremental_interface ) +#else + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) +#endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index )); + + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + if ( t1size ) + { + glyph->x_scale = t1size->metrics.x_scale; + glyph->y_scale = t1size->metrics.y_scale; + } + else + { + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + } + + t1glyph->outline.n_points = 0; + t1glyph->outline.n_contours = 0; + + hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) && + !( load_flags & FT_LOAD_NO_HINTING ) ); + scaled = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + + glyph->hint = hinting; + glyph->scaled = scaled; + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + error = decoder_funcs->init( &decoder, + t1glyph->face, + t1size, + t1glyph, + (FT_Byte**)type1->glyph_names, + face->blend, + hinting, + FT_LOAD_TARGET_MODE( load_flags ), + T1_Parse_Glyph ); + if ( error ) + goto Exit; + + must_finish_decoder = TRUE; + + decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); + + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.subrs_hash = type1->subrs_hash; + + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + + /* now load the unscaled outline */ + error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, + &glyph_data, + &force_scaling ); + if ( error ) + goto Exit; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + glyph_data_loaded = 1; +#endif + + hinting = glyph->hint; + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; + + /* save new glyph tables */ + decoder_funcs->done( &decoder ); + + must_finish_decoder = FALSE; + + /* now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax */ + if ( !error ) + { + t1glyph->outline.flags &= FT_OUTLINE_OWNER; + t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + + /* for composite glyphs, return only left side bearing and */ + /* advance width */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + FT_Slot_Internal internal = t1glyph->internal; + + + t1glyph->metrics.horiBearingX = + FIXED_TO_INT( decoder.builder.left_bearing.x ); + t1glyph->metrics.horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + + internal->glyph_matrix = font_matrix; + internal->glyph_delta = font_offset; + internal->glyph_transformed = 1; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &t1glyph->metrics; + + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->linearHoriAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->internal->glyph_transformed = 0; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + metrics->vertAdvance = ( face->type1.font_bbox.yMax - + face->type1.font_bbox.yMin ) >> 16; + t1glyph->linearVertAdvance = metrics->vertAdvance; + } + else + { + metrics->vertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + t1glyph->linearVertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + } + + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + if ( t1size && t1size->metrics.y_ppem < 24 ) + t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + +#if 1 + /* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + { + FT_Outline_Transform( &t1glyph->outline, &font_matrix ); + + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, + font_matrix.xx ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, + font_matrix.yy ); + } + + if ( font_offset.x || font_offset.y ) + { + FT_Outline_Translate( &t1glyph->outline, + font_offset.x, + font_offset.y ); + + metrics->horiAdvance += font_offset.x; + metrics->vertAdvance += font_offset.y; + } +#endif + + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = decoder.builder.base; + FT_Vector* vec = cur->points; + FT_Fixed x_scale = glyph->x_scale; + FT_Fixed y_scale = glyph->y_scale; + + + /* First of all, scale the points, if we are not hinting */ + if ( !hinting || !decoder.builder.hints_funcs ) + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } + + /* compute the other metrics */ + FT_Outline_Get_CBox( &t1glyph->outline, &cbox ); + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* make up vertical ones */ + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + + /* Set control data to the glyph charstrings. Note that this is */ + /* _not_ zero-terminated. */ + t1glyph->control_data = (FT_Byte*)glyph_data.pointer; + t1glyph->control_len = glyph_data.length; + } + + + Exit: + +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( glyph_data_loaded && face->root.internal->incremental_interface ) + { + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + + /* Set the control data to null - it is no longer available if */ + /* loaded incrementally. */ + t1glyph->control_data = NULL; + t1glyph->control_len = 0; + } +#endif + + if ( must_finish_decoder ) + decoder_funcs->done( &decoder ); + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1gload.h b/Dependencies/freetype/freetype/src/type1/t1gload.h new file mode 100644 index 00000000..17a6a594 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1gload.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * t1gload.h + * + * Type 1 Glyph Loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1GLOAD_H_ +#define T1GLOAD_H_ + + +#include "t1objs.h" + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ); + + FT_LOCAL( FT_Error ) + T1_Get_Advances( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ); + + FT_LOCAL( FT_Error ) + T1_Load_Glyph( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + +FT_END_HEADER + +#endif /* T1GLOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1load.c b/Dependencies/freetype/freetype/src/type1/t1load.c new file mode 100644 index 00000000..ee7fb42a --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1load.c @@ -0,0 +1,2755 @@ +/**************************************************************************** + * + * t1load.c + * + * Type 1 font loader (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This is the new and improved Type 1 data loader for FreeType 2. The + * old loader has several problems: it is slow, complex, difficult to + * maintain, and contains incredible hacks to make it accept some + * ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of + * the Type 1 fonts on my machine still aren't loaded correctly by it. + * + * This version is much simpler, much faster and also easier to read and + * maintain by a great order of magnitude. The idea behind it is to + * _not_ try to read the Type 1 token stream with a state machine (i.e. + * a Postscript-like interpreter) but rather to perform simple pattern + * matching. + * + * Indeed, nearly all data definitions follow a simple pattern like + * + * ... /Field ... + * + * where can be a number, a boolean, a string, or an array of + * numbers. There are a few exceptions, namely the encoding, font name, + * charstrings, and subrs; they are handled with a special pattern + * matching routine. + * + * All other common cases are handled very simply. The matching rules + * are defined in the file `t1tokens.h' through the use of several + * macros calls PARSE_XXX. This file is included twice here; the first + * time to generate parsing callback functions, the second time to + * generate a table of keywords (with pointers to the associated + * callback functions). + * + * The function `parse_dict' simply scans *linearly* a given dictionary + * (either the top-level or private one) and calls the appropriate + * callback when it encounters an immediate keyword. + * + * This is by far the fastest way one can find to parse and read all + * data. + * + * This led to tremendous code size reduction. Note that later, the + * glyph loader will also be _greatly_ simplified, and the automatic + * hinter will replace the clumsy `t1hinter'. + * + */ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include +#include +#include +#include + +#include "t1load.h" +#include "t1errors.h" + + +#ifdef FT_CONFIG_OPTION_INCREMENTAL +#define IS_INCREMENTAL \ + FT_BOOL( FT_FACE( face )->internal->incremental_interface ) +#else +#define IS_INCREMENTAL 0 +#endif + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1load + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SUPPORT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_allocate_blend( T1_Face face, + FT_UInt num_designs, + FT_UInt num_axis ) + { + PS_Blend blend; + FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + + + blend = face->blend; + if ( !blend ) + { + if ( FT_NEW( blend ) ) + goto Exit; + + blend->num_default_design_vector = 0; + blend->weight_vector = NULL; + blend->default_weight_vector = NULL; + blend->design_pos[0] = NULL; + + face->blend = blend; + } + + /* allocate design data if needed */ + if ( num_designs > 0 ) + { + if ( blend->num_designs == 0 ) + { + FT_UInt nn; + + + /* allocate the blend `private' and `font_info' dictionaries */ + if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || + FT_NEW_ARRAY( blend->privates [1], num_designs ) || + FT_NEW_ARRAY( blend->bboxes [1], num_designs ) ) + goto Exit; + + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + blend->bboxes [0] = &face->type1.font_bbox; + + for ( nn = 2; nn <= num_designs; nn++ ) + { + blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; + blend->privates [nn] = blend->privates [nn - 1] + 1; + blend->bboxes [nn] = blend->bboxes [nn - 1] + 1; + } + + blend->num_designs = num_designs; + } + else if ( blend->num_designs != num_designs ) + goto Fail; + } + + /* allocate axis data if needed */ + if ( num_axis > 0 ) + { + if ( blend->num_axis != 0 && blend->num_axis != num_axis ) + goto Fail; + + blend->num_axis = num_axis; + } + + Exit: + return error; + + Fail: + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Multi_Master( FT_Face face, /* T1_Face */ + FT_Multi_Master* master ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt n; + FT_Error error; + + + error = FT_THROW( Invalid_Argument ); + + if ( blend ) + { + master->num_axis = blend->num_axis; + master->num_designs = blend->num_designs; + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_MM_Axis* axis = master->axis + n; + PS_DesignMap map = blend->design_map + n; + + + axis->name = blend->axis_names[n]; + axis->minimum = map->design_points[0]; + axis->maximum = map->design_points[map->num_points - 1]; + } + + error = FT_Err_Ok; + } + + return error; + } + + + /************************************************************************** + * + * Given a normalized (blend) coordinate, figure out the design + * coordinate appropriate for that value. + */ + static FT_Fixed + mm_axis_unmap( PS_DesignMap axismap, + FT_Fixed ncv ) + { + int j; + + + if ( ncv <= axismap->blend_points[0] ) + return INT_TO_FIXED( axismap->design_points[0] ); + + for ( j = 1; j < axismap->num_points; j++ ) + { + if ( ncv <= axismap->blend_points[j] ) + return INT_TO_FIXED( axismap->design_points[j - 1] + + FT_MulDiv( ncv - axismap->blend_points[j - 1], + axismap->design_points[j] - + axismap->design_points[j - 1], + axismap->blend_points[j] - + axismap->blend_points[j - 1] ) ); + } + + return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); + } + + + /************************************************************************** + * + * Given a vector of weights, one for each design, figure out the + * normalized axis coordinates which gave rise to those weights. + */ + static void + mm_weights_unmap( FT_Fixed* weights, + FT_Fixed* axiscoords, + FT_UInt axis_count ) + { + FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); + + if ( axis_count == 1 ) + axiscoords[0] = weights[1]; + + else if ( axis_count == 2 ) + { + axiscoords[0] = weights[3] + weights[1]; + axiscoords[1] = weights[3] + weights[2]; + } + + else if ( axis_count == 3 ) + { + axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; + } + + else + { + axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + + weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + + weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[7] + weights[6] + weights[5] + weights[4]; + axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[11] + weights[10] + weights[9] + weights[8]; + } + } + + + /************************************************************************** + * + * Just a wrapper around T1_Get_Multi_Master to support the different + * arguments needed by the GX var distortable fonts. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( FT_Face face, /* T1_Face */ + FT_MM_Var* *master ) + { + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_MM_Var *mmvar = NULL; + FT_Multi_Master mmaster; + FT_Error error; + FT_UInt i; + FT_Fixed axiscoords[T1_MAX_MM_AXIS]; + PS_Blend blend = t1face->blend; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; + + + error = T1_Get_Multi_Master( face, &mmaster ); + if ( error ) + goto Exit; + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmvar' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( mmaster.num_axis * + sizeof ( FT_UShort ) ); + axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis ); + + if ( FT_QALLOC( mmvar, mmvar_size + + axis_flags_size + + axis_size ) ) + goto Exit; + + mmvar->num_axis = mmaster.num_axis; + mmvar->num_designs = mmaster.num_designs; + mmvar->num_namedstyles = 0; /* Not supported */ + + /* while axis flags are meaningless here, we have to provide the array */ + /* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */ + /* values directly follow the data of `FT_MM_Var' */ + axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); + FT_ARRAY_ZERO( axis_flags, mmaster.num_axis ); + + mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = NULL; + + for ( i = 0; i < mmaster.num_axis; i++ ) + { + mmvar->axis[i].name = mmaster.axis[i].name; + mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum ); + mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum ); + mmvar->axis[i].strid = ~0U; /* Does not apply */ + mmvar->axis[i].tag = ~0U; /* Does not apply */ + + if ( !mmvar->axis[i].name ) + continue; + + if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); + else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Slant" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 's', 'l', 'n', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Italic" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'i', 't', 'a', 'l' ); + } + + mm_weights_unmap( blend->default_weight_vector, + axiscoords, + blend->num_axis ); + + for ( i = 0; i < mmaster.num_axis; i++ ) + mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], + axiscoords[i] ); + + *master = mmvar; + + Exit: + return error; + } + + + static FT_Error + t1_set_mm_blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + PS_Blend blend = face->blend; + FT_UInt n, m; + + FT_Bool have_diff = 0; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( num_coords > blend->num_axis ) + num_coords = blend->num_axis; + + /* recompute the weight vector from the blend coordinates */ + for ( n = 0; n < blend->num_designs; n++ ) + { + FT_Fixed result = 0x10000L; /* 1.0 fixed */ + FT_Fixed factor; + + + for ( m = 0; m < blend->num_axis; m++ ) + { + /* use a default value if we don't have a coordinate */ + if ( m >= num_coords ) + { + result >>= 1; + continue; + } + + /* get current blend axis position */ + factor = coords[m]; + if ( ( n & ( 1 << m ) ) == 0 ) + factor = 0x10000L - factor; + + if ( factor <= 0 ) + { + result = 0; + break; + } + else if ( factor >= 0x10000L ) + continue; + + result = FT_MulFix( result, factor ); + } + + if ( blend->weight_vector[n] != result ) + { + blend->weight_vector[n] = result; + have_diff = 1; + } + } + + /* return value -1 indicates `no change' */ + return have_diff ? FT_Err_Ok : -1; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Blend( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + return t1_set_mm_blend( (T1_Face)face, num_coords, coords ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Blend( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + + FT_Fixed axiscoords[4]; + FT_UInt i, nc; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + mm_weights_unmap( blend->weight_vector, + axiscoords, + blend->num_axis ); + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + coords[i] = axiscoords[i]; + for ( ; i < num_coords; i++ ) + coords[i] = 0x8000; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */ + FT_UInt len, + FT_Fixed* weightvector ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt i, n; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( !len && !weightvector ) + { + for ( i = 0; i < blend->num_designs; i++ ) + blend->weight_vector[i] = blend->default_weight_vector[i]; + } + else + { + if ( !weightvector ) + return FT_THROW( Invalid_Argument ); + + n = len < blend->num_designs ? len : blend->num_designs; + + for ( i = 0; i < n; i++ ) + blend->weight_vector[i] = weightvector[i]; + + for ( ; i < blend->num_designs; i++ ) + blend->weight_vector[i] = (FT_Fixed)0; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */ + FT_UInt* len, + FT_Fixed* weightvector ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + FT_UInt i; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( *len < blend->num_designs ) + { + *len = blend->num_designs; + return FT_THROW( Invalid_Argument ); + } + + for ( i = 0; i < blend->num_designs; i++ ) + weightvector[i] = blend->weight_vector[i]; + for ( ; i < *len; i++ ) + weightvector[i] = (FT_Fixed)0; + + *len = blend->num_designs; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Long* coords ) + { + T1_Face t1face = (T1_Face)face; + FT_Error error; + PS_Blend blend = t1face->blend; + FT_UInt n; + FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( num_coords > blend->num_axis ) + num_coords = blend->num_axis; + + /* compute the blend coordinates through the blend design map */ + + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_Long design; + FT_Fixed the_blend; + PS_DesignMap map = blend->design_map + n; + FT_Long* designs = map->design_points; + FT_Fixed* blends = map->blend_points; + FT_Int p, before = -1, after = -1; + + + /* use a default value if we don't have a coordinate */ + if ( n < num_coords ) + design = coords[n]; + else + design = ( designs[map->num_points - 1] - designs[0] ) / 2; + + for ( p = 0; p < (FT_Int)map->num_points; p++ ) + { + FT_Long p_design = designs[p]; + + + /* exact match? */ + if ( design == p_design ) + { + the_blend = blends[p]; + goto Found; + } + + if ( design < p_design ) + { + after = p; + break; + } + + before = p; + } + + /* now interpolate if necessary */ + if ( before < 0 ) + the_blend = blends[0]; + + else if ( after < 0 ) + the_blend = blends[map->num_points - 1]; + + else + the_blend = FT_MulDiv( design - designs[before], + blends [after] - blends [before], + designs[after] - designs[before] ); + + Found: + final_blends[n] = the_blend; + } + + error = t1_set_mm_blend( t1face, blend->num_axis, final_blends ); + if ( error ) + return error; + + return FT_Err_Ok; + } + + + /* MM fonts don't have named instances, so only the design is reset */ + + FT_LOCAL_DEF( FT_Error ) + T1_Reset_MM_Blend( FT_Face face, + FT_UInt instance_index ) + { + FT_UNUSED( instance_index ); + + return T1_Set_MM_Blend( face, 0, NULL ); + } + + + /************************************************************************** + * + * Just a wrapper around T1_Set_MM_Design to support the different + * arguments needed by the GX var distortable fonts. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Long lcoords[T1_MAX_MM_AXIS]; + FT_UInt i; + + + if ( num_coords > T1_MAX_MM_AXIS ) + num_coords = T1_MAX_MM_AXIS; + + for ( i = 0; i < num_coords; i++ ) + lcoords[i] = FIXED_TO_INT( coords[i] ); + + return T1_Set_MM_Design( face, num_coords, lcoords ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Var_Design( FT_Face face, /* T1_Face */ + FT_UInt num_coords, + FT_Fixed* coords ) + { + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; + + FT_Fixed axiscoords[4]; + FT_UInt i, nc; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + mm_weights_unmap( blend->weight_vector, + axiscoords, + blend->num_axis ); + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "T1_Get_Var_Design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + coords[i] = mm_axis_unmap( &blend->design_map[i], axiscoords[i] ); + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T1_Done_Blend( FT_Face face ) /* T1_Face */ + { + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Blend blend = t1face->blend; + + + if ( blend ) + { + FT_UInt num_designs = blend->num_designs; + FT_UInt num_axis = blend->num_axis; + FT_UInt n; + + + /* release design pos table */ + FT_FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = NULL; + + /* release blend `private' and `font info' dictionaries */ + FT_FREE( blend->privates[1] ); + FT_FREE( blend->font_infos[1] ); + FT_FREE( blend->bboxes[1] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = NULL; + blend->font_infos[n] = NULL; + blend->bboxes [n] = NULL; + } + + /* release weight vectors */ + FT_FREE( blend->weight_vector ); + blend->default_weight_vector = NULL; + + /* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FT_FREE( blend->axis_names[n] ); + + /* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap dmap = blend->design_map + n; + + + FT_FREE( dmap->blend_points ); + FT_FREE( dmap->design_points ); + dmap->num_points = 0; + } + + FT_FREE( t1face->blend ); + } + } + + + static void + parse_blend_axis_types( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Error error = FT_Err_Ok; + PS_Blend blend; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + /* take an array of objects */ + T1_ToTokenArray( &loader->parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", + num_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allocate blend if necessary */ + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + FT_TRACE4(( " [" )); + + blend = t1face->blend; + + /* each token is an immediate containing the name of the axis */ + for ( n = 0; n < num_axis; n++ ) + { + T1_Token token = axis_tokens + n; + FT_Byte* name; + FT_UInt len; + + + /* skip first slash, if any */ + if ( token->start[0] == '/' ) + token->start++; + + len = (FT_UInt)( token->limit - token->start ); + if ( len == 0 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE4(( " /%.*s", len, token->start )); + + name = (FT_Byte*)blend->axis_names[n]; + if ( name ) + { + FT_TRACE0(( "parse_blend_axis_types:" + " overwriting axis name `%s' with `%.*s'\n", + name, len, token->start )); + FT_FREE( name ); + } + + if ( FT_QALLOC( blend->axis_names[n], len + 1 ) ) + goto Exit; + + name = (FT_Byte*)blend->axis_names[n]; + FT_MEM_COPY( name, token->start, len ); + name[len] = '\0'; + } + + FT_TRACE4(( "]\n" )); + + Exit: + loader->parser.root.error = error; + } + + + static void + parse_blend_design_positions( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Int num_axis = 0; /* make compiler happy */ + T1_Parser parser = &loader->parser; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + + + design_pos[0] = NULL; + + /* get the array of design tokens -- compute number of designs */ + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " incorrect number of designs: %d\n", + num_designs )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + { + FT_Byte* old_cursor = parser->root.cursor; + FT_Byte* old_limit = parser->root.limit; + FT_Int n, nn; + PS_Blend blend; + + + FT_TRACE4(( " [" )); + + for ( n = 0; n < num_designs; n++ ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + T1_Token token; + FT_Int axis, n_axis; + + + /* read axis/coordinates tokens */ + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); + + if ( n == 0 ) + { + if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " invalid number of axes: %d\n", + n_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + num_axis = n_axis; + error = t1_allocate_blend( t1face, + (FT_UInt)num_designs, + (FT_UInt)num_axis ); + if ( error ) + goto Exit; + + /* allocate a blend design pos table */ + if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) ) + goto Exit; + + for ( nn = 1; nn < num_designs; nn++ ) + design_pos[nn] = design_pos[0] + num_axis * nn; + } + else if ( n_axis != num_axis ) + { + FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* now read each axis token into the design position */ + FT_TRACE4(( " [" )) ; + for ( axis = 0; axis < n_axis; axis++ ) + { + T1_Token token2 = axis_tokens + axis; + + + parser->root.cursor = token2->start; + parser->root.limit = token2->limit; + design_pos[n][axis] = T1_ToFixed( parser, 0 ); + FT_TRACE4(( " %f", (double)design_pos[n][axis] / 65536 )); + } + FT_TRACE4(( "]" )) ; + } + + FT_TRACE4(( "]\n" )); + + loader->parser.root.cursor = old_cursor; + loader->parser.root.limit = old_limit; + + /* a valid BlendDesignPosition has been parsed */ + blend = t1face->blend; + if ( blend->design_pos[0] ) + FT_FREE( blend->design_pos[0] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->design_pos[n] = design_pos[n]; + design_pos[n] = NULL; + } + } + + Exit: + FT_FREE( design_pos[0] ); + loader->parser.root.error = error; + } + + + static void + parse_blend_design_map( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + FT_Error error = FT_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Byte* old_cursor; + FT_Byte* old_limit; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + T1_ToTokenArray( parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", + num_axis )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + blend = t1face->blend; + + FT_TRACE4(( " [" )); + + /* now read each axis design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap map = blend->design_map + n; + T1_Token axis_token; + T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; + FT_Int p, num_points; + + + axis_token = axis_tokens + n; + + parser->root.cursor = axis_token->start; + parser->root.limit = axis_token->limit; + T1_ToTokenArray( parser, point_tokens, + T1_MAX_MM_MAP_POINTS, &num_points ); + + FT_TRACE4(( " [" )); + + if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( map->design_points ) + { + FT_ERROR(( "parse_blend_design_map: duplicate table\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* allocate design map data */ + if ( FT_QNEW_ARRAY( map->design_points, num_points ) || + FT_QNEW_ARRAY( map->blend_points, num_points ) ) + goto Exit; + map->num_points = (FT_Byte)num_points; + + for ( p = 0; p < num_points; p++ ) + { + T1_Token point_token; + + + point_token = point_tokens + p; + + /* don't include delimiting brackets */ + parser->root.cursor = point_token->start + 1; + parser->root.limit = point_token->limit - 1; + + map->design_points[p] = T1_ToInt( parser ); + map->blend_points [p] = T1_ToFixed( parser, 0 ); + + FT_TRACE4(( " [%ld %f]", + map->design_points[p], + (double)map->blend_points[p] / 65536 )); + } + + FT_TRACE4(( "]" )); + } + + FT_TRACE4(( "]\n" )); + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + static void + parse_weight_vector( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_FACE_MEMORY( face ); + T1_Parser parser = &loader->parser; + PS_Blend blend = t1face->blend; + T1_Token token; + FT_Int n; + FT_Byte* old_cursor; + FT_Byte* old_limit; + + + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = FT_ERR( Ignore ); + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_weight_vector:" + " incorrect number of designs: %d\n", + num_designs )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !blend || !blend->num_designs ) + { + error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 ); + if ( error ) + goto Exit; + blend = t1face->blend; + } + else if ( blend->num_designs != (FT_UInt)num_designs ) + { + FT_ERROR(( "parse_weight_vector:" + " /BlendDesignPosition and /WeightVector have\n" )); + FT_ERROR(( " " + " different number of elements\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( !blend->weight_vector ) + if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + + FT_TRACE4(( "[" )); + + for ( n = 0; n < num_designs; n++ ) + { + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + + blend->default_weight_vector[n] = + blend->weight_vector[n] = T1_ToFixed( parser, 0 ); + + FT_TRACE4(( " %f", (double)blend->weight_vector[n] / 65536 )); + } + + FT_TRACE4(( "]\n" )); + + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + + Exit: + parser->root.error = error; + } + + + /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ + /* we're only interested in the number of array elements */ + static void + parse_buildchar( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + + + t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser, + 0, NULL, 0 ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + FT_TRACE4(( " [" )); + for ( i = 0; i < t1face->len_buildchar; i++ ) + FT_TRACE4(( " 0" )); + + FT_TRACE4(( "]\n" )); + } +#endif + + return; + } + + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_Error + t1_load_keyword( T1_Face face, + T1_Loader loader, + const T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects; + PS_Blend blend = face->blend; + + + if ( blend && blend->num_designs == 0 ) + blend = NULL; + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + FT_TRACE4(( " %s", field->ident )); + + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields; */ + /* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_PRIVATE: + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + objects = &dummy_object; + max_objects = 0; + + if ( blend ) + { + objects = (void**)blend->bboxes; + max_objects = blend->num_designs; + } + break; + + case T1_FIELD_LOCATION_LOADER: + dummy_object = loader; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_FACE: + dummy_object = face; + objects = &dummy_object; + max_objects = 0; + break; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + case T1_FIELD_LOCATION_BLEND: + dummy_object = face->blend; + objects = &dummy_object; + max_objects = 0; + break; +#endif + + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + + FT_TRACE4(( " %s", field->ident )); + + if ( *objects ) + { + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + } + else + { + FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" + " which is not valid at this point\n", + field->ident )); + FT_TRACE1(( " (probably due to missing keywords)\n" )); + error = FT_Err_Ok; + } + + FT_TRACE4(( "\n" )); + + Exit: + return error; + } + + + static void + parse_private( FT_Face face, + void* loader_ ) + { + T1_Loader loader = (T1_Loader)loader_; + FT_UNUSED( face ); + + loader->keywords_encountered |= T1_PRIVATE; + + FT_TRACE4(( "\n" )); + } + + + /* return 1 in case of success */ + + static int + read_binary_data( T1_Parser parser, + FT_ULong* size, + FT_Byte** base, + FT_Bool incremental ) + { + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + + /* the binary data has one of the following formats */ + /* */ + /* `size' [white*] RD white ....... ND */ + /* `size' [white*] -| white ....... |- */ + /* */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + + if ( cur < limit && ft_isdigit( *cur ) ) + { + FT_Long s = T1_ToInt( parser ); + + + T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ + + /* there is only one whitespace char after the */ + /* `RD' or `-|' token */ + *base = parser->root.cursor + 1; + + if ( s >= 0 && s < limit - *base ) + { + parser->root.cursor += s + 1; + *size = (FT_ULong)s; + return !parser->root.error; + } + } + + if( !incremental ) + { + FT_ERROR(( "read_binary_data: invalid size field\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + } + + return 0; + } + + + /* We now define the routines to handle the `/Encoding', `/Subrs', */ + /* and `/CharStrings' dictionaries. */ + + static void + t1_parse_font_matrix( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + FT_Matrix* matrix = &t1face->type1.font_matrix; + FT_Vector* offset = &t1face->type1.font_offset; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + + + /* input is scaled by 1000 to accommodate default FontMatrix */ + result = T1_ToFixedArray( parser, 6, temp, 3 ); + + if ( result < 6 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)temp[0] / 65536 / 1000, + (double)temp[1] / 65536 / 1000, + (double)temp[2] / 65536 / 1000, + (double)temp[3] / 65536 / 1000, + (double)temp[4] / 65536 / 1000, + (double)temp[5] / 65536 / 1000 )); + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + /* set units per EM based on FontMatrix values */ + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + parse_encoding( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "parse_encoding: out of bounds\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &t1face->type1.encoding; + FT_Int count, array_size, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + + array_size = count; + if ( count > 256 ) + { + FT_TRACE2(( "parse_encoding:" + " only using first 256 encoding array entries\n" )); + array_size = 256; + } + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* PostScript happily allows overwriting of encoding arrays */ + if ( encode->char_index ) + { + FT_FREE( encode->char_index ); + FT_FREE( encode->char_name ); + T1_Release_Table( char_table ); + } + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = array_size; + if ( FT_QNEW_ARRAY( encode->char_index, array_size ) || + FT_QNEW_ARRAY( encode->char_name, array_size ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, array_size, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < array_size; n++ ) + (void)T1_Add_Table( char_table, n, ".notdef", 8 ); + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type1 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter a `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + IS_PS_DELIM( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we've found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + + /* protect against invalid charcode */ + if ( cur == parser->root.cursor ) + { + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + + cur = parser->root.cursor; + + if ( cur + 2 < limit && *cur == '/' && n < count ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + return; + if ( parser->root.error ) + return; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( n < array_size ) + { + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + } + + n++; + } + else if ( only_immediates ) + { + /* Since the current position is not updated for */ + /* immediates-only mode we would get an infinite loop if */ + /* we don't do anything here. */ + /* */ + /* This encoding array is not valid according to the type1 */ + /* specification (it might be an encoding for a CID type1 */ + /* font, however), so we conclude that this font is NOT a */ + /* type1 font. */ + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " [" )); + + /* XXX show encoding vector */ + FT_TRACE4(( "..." )); + + FT_TRACE4(( "]\n" )); +#endif + + t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + FT_TRACE4(( " StandardEncoding\n" )); + } + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + FT_TRACE4(( " ExpertEncoding\n" )); + } + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + { + t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + FT_TRACE4(( " ISOLatin1Encoding\n" )); + } + + else + { + parser->root.error = FT_ERR( Ignore ); + FT_TRACE4(( "\n" )); + } + } + } + + + static void + parse_subrs( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + PS_Table table = &loader->subrs; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Int num_subrs; + FT_UInt count; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + + T1_Skip_Spaces( parser ); + + /* test for empty array */ + if ( parser->root.cursor < parser->root.limit && + *parser->root.cursor == '[' ) + { + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor >= parser->root.limit || + *parser->root.cursor != ']' ) + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + num_subrs = (FT_Int)T1_ToInt( parser ); + if ( num_subrs < 0 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* we certainly need more than 8 bytes per subroutine */ + if ( parser->root.limit >= parser->root.cursor && + num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 ) + { + /* + * There are two possibilities. Either the font contains an invalid + * value for `num_subrs', or we have a subsetted font where the + * subroutine indices are not adjusted, e.g. + * + * /Subrs 812 array + * dup 0 { ... } NP + * dup 51 { ... } NP + * dup 681 { ... } NP + * ND + * + * In both cases, we use a number hash that maps from subr indices to + * actual array elements. + */ + + FT_TRACE0(( "parse_subrs: adjusting number of subroutines" + " (from %d to %zu)\n", + num_subrs, + ( parser->root.limit - parser->root.cursor ) >> 3 )); + num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3; + + if ( !loader->subrs_hash ) + { + if ( FT_QNEW( loader->subrs_hash ) ) + goto Fail; + + error = ft_hash_num_init( loader->subrs_hash, memory ); + if ( error ) + goto Fail; + } + } + + /* position the parser right before the `dup' of the first subr */ + T1_Skip_PS_Token( parser ); /* `array' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + + /* initialize subrs array -- with synthetic fonts it is possible */ + /* we get here twice */ + if ( !loader->num_subrs ) + { + error = psaux->ps_table_funcs->init( table, num_subrs, memory ); + if ( error ) + goto Fail; + } + + /* the format is simple: */ + /* */ + /* `index' + binary data */ + /* */ + for ( count = 0; ; count++ ) + { + FT_Long idx; + FT_ULong size; + FT_Byte* base; + + + /* If we are out of data, or if the next token isn't `dup', */ + /* we are done. */ + if ( parser->root.cursor + 4 >= parser->root.limit || + ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) + break; + + T1_Skip_PS_Token( parser ); /* `dup' */ + + idx = T1_ToInt( parser ); + + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; + + /* The binary string is followed by one token, e.g. `NP' */ + /* (bound to `noaccess put') or by two separate tokens: */ + /* `noaccess' & `put'. We position the parser right */ + /* before the next `dup', if any. */ + T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ + if ( parser->root.error ) + return; + T1_Skip_Spaces ( parser ); + + if ( parser->root.cursor + 4 < parser->root.limit && + ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) + { + T1_Skip_PS_Token( parser ); /* skip `put' */ + T1_Skip_Spaces ( parser ); + } + + /* if we use a hash, the subrs index is the key, and a running */ + /* counter specified for `T1_Add_Table' acts as the value */ + if ( loader->subrs_hash ) + { + ft_hash_num_insert( idx, count, loader->subrs_hash, memory ); + idx = count; + } + + /* with synthetic fonts it is possible we get here twice */ + if ( loader->num_subrs ) + continue; + + /* some fonts use a value of -1 for lenIV to indicate that */ + /* the charstrings are unencoded */ + /* */ + /* thanks to Tom Kacvinsky for pointing this out */ + /* */ + if ( t1face->type1.private_dict.lenIV >= 0 ) + { + FT_Byte* temp = NULL; + + + /* some fonts define empty subr records -- this is not totally */ + /* compliant to the specification (which says they should at */ + /* least contain a `return'), but we support them anyway */ + if ( size < (FT_ULong)t1face->type1.private_dict.lenIV ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_DUP( temp, base, size ) ) + goto Fail; + psaux->t1_decrypt( temp, size, 4330 ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( table, + (FT_Int)idx, + temp + t1face->type1.private_dict.lenIV, + size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( table, (FT_Int)idx, base, size ); + if ( error ) + goto Fail; + } + + if ( !loader->num_subrs ) + loader->num_subrs = num_subrs; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " <" )); + + /* XXX show subrs? */ + FT_TRACE4(( "%d elements", num_subrs )); + + FT_TRACE4(( ">\n" )); +#endif + + return; + + Fail: + parser->root.error = error; + } + + +#define TABLE_EXTEND 5 + + + static void + parse_charstrings( FT_Face face, /* T1_Face */ + void* loader_ ) + { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + T1_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)t1face->psaux; + + FT_Byte* cur = parser->root.cursor; + FT_Byte* limit = parser->root.limit; + FT_Int n, num_glyphs; + FT_Int notdef_index = 0; + FT_Byte notdef_found = 0; + + + num_glyphs = (FT_Int)T1_ToInt( parser ); + if ( num_glyphs < 0 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we certainly need more than 8 bytes per glyph */ + if ( num_glyphs > ( limit - cur ) >> 3 ) + { + FT_TRACE0(( "parse_charstrings: adjusting number of glyphs" + " (from %d to %zu)\n", + num_glyphs, ( limit - cur ) >> 3 )); + num_glyphs = ( limit - cur ) >> 3; + } + + /* some fonts like Optima-Oblique not only define the /CharStrings */ + /* array but access it also */ + if ( num_glyphs == 0 || parser->root.error ) + return; + + /* initialize tables, leaving space for addition of .notdef, */ + /* if necessary, and a few other glyphs to handle buggy */ + /* fonts which have more glyphs than specified. */ + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( !loader->num_glyphs ) + { + error = psaux->ps_table_funcs->init( + code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( + name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + } + + n = 0; + + for (;;) + { + FT_ULong size; + FT_Byte* base; + + + /* the format is simple: */ + /* `/glyphname' + binary data */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* we stop when we find a `def' or `end' keyword */ + if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) + { + if ( cur[0] == 'd' && + cur[1] == 'e' && + cur[2] == 'f' ) + { + /* There are fonts which have this: */ + /* */ + /* /CharStrings 118 dict def */ + /* Private begin */ + /* CharStrings begin */ + /* ... */ + /* */ + /* To catch this we ignore `def' if */ + /* no charstring has actually been */ + /* seen. */ + if ( n ) + break; + } + + if ( cur[0] == 'e' && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( parser->root.error ) + return; + + if ( *cur == '/' ) + { + FT_UInt len; + + + if ( cur + 2 >= limit ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + cur++; /* skip `/' */ + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; + + /* for some non-standard fonts like `Optima' which provides */ + /* different outlines depending on the resolution it is */ + /* possible to get here twice */ + if ( loader->num_glyphs ) + continue; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)( name_table->elements[n] ) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + if ( t1face->type1.private_dict.lenIV >= 0 && + n < num_glyphs + TABLE_EXTEND ) + { + FT_Byte* temp = NULL; + + + if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_DUP( temp, base, size ) ) + goto Fail; + psaux->t1_decrypt( temp, size, 4330 ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( code_table, + n, + temp + t1face->type1.private_dict.lenIV, + size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( code_table, n, base, size ); + if ( error ) + goto Fail; + + n++; + } + } + + if ( !n ) + { + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + loader->num_glyphs = n; + + /* if /.notdef is found but does not occupy index 0, do our magic. */ + if ( notdef_found && + ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + else if ( !notdef_found ) + { + /* notdef_index is already 0, or /.notdef is undefined in */ + /* charstrings dictionary. Worry about /.notdef undefined. */ + /* We take index 0 and add it to the end of the table(s) */ + /* and add our own /.notdef glyph to index 0. */ + + /* 0 333 hsbw endchar */ + FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; + + + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, ".notdef", 8 ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); + + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, n, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, n, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + /* we added a glyph. */ + loader->num_glyphs += 1; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " <" )); + + /* XXX show charstrings? */ + FT_TRACE4(( "%d elements", loader->num_glyphs )); + + FT_TRACE4(( ">\n" )); +#endif + + return; + + Fail: + parser->root.error = error; + } + + + /************************************************************************** + * + * Define the token field static variables. This is a set of + * T1_FieldRec variables. + * + */ + + + static + const T1_FieldRec t1_keywords[] = + { + +#include "t1tokens.h" + + /* now add the special functions... */ + T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Encoding", parse_encoding, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Subrs", parse_subrs, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "Private", parse_private, + T1_FIELD_DICT_FONTDICT ) + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, + T1_FIELD_DICT_PRIVATE ) +#endif + + T1_FIELD_ZERO + }; + + + static FT_Error + parse_dict( T1_Face face, + T1_Loader loader, + FT_Byte* base, + FT_ULong size ) + { + T1_Parser parser = &loader->parser; + FT_Byte *limit, *start_binary = NULL; + FT_Bool have_integer = 0; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `eexec' */ + if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) + break; + + /* look for `closefile' which ends the eexec section */ + else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) + break; + + /* in a synthetic font the base font starts after a */ + /* `FontDictionary' token that is placed after a Private dict */ + else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) + { + if ( loader->keywords_encountered & T1_PRIVATE ) + loader->keywords_encountered |= + T1_FONTDIR_AFTER_PRIVATE; + parser->root.cursor += 13; + } + + /* check whether we have an integer */ + else if ( ft_isdigit( *cur ) ) + { + start_binary = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 1; + } + + /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ + /* since those tokens are handled by parse_subrs and */ + /* parse_charstrings */ + else if ( *cur == 'R' && cur + 6 < limit && *( cur + 1 ) == 'D' && + have_integer ) + { + FT_ULong s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return FT_THROW( Invalid_File_Format ); + have_integer = 0; + } + + else if ( *cur == '-' && cur + 6 < limit && *( cur + 1 ) == '|' && + have_integer ) + { + FT_ULong s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return FT_THROW( Invalid_File_Format ); + have_integer = 0; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + /* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)t1_keywords; + + + while ( keyword->len ) + { + FT_Byte* name = (FT_Byte*)keyword->ident; + + + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) + { + /* We found it -- run the parsing callback! */ + /* We record every instance of every field */ + /* (until we reach the base font of a */ + /* synthetic font) to deal adequately with */ + /* multiple master fonts; this is also */ + /* necessary because later PostScript */ + /* definitions override earlier ones. */ + + /* Once we encounter `FontDirectory' after */ + /* `/Private', we know that this is a synthetic */ + /* font; except for `/CharStrings' we are not */ + /* interested in anything that follows this */ + /* `FontDirectory'. */ + + /* MM fonts have more than one /Private token at */ + /* the top level; let's hope that all the junk */ + /* that follows the first /Private token is not */ + /* interesting to us. */ + + /* According to Adobe Tech Note #5175 (CID-Keyed */ + /* Font Installation for ATM Software) a `begin' */ + /* must be followed by exactly one `end', and */ + /* `begin' -- `end' pairs must be accurately */ + /* paired. We could use this to distinguish */ + /* between the global Private and the Private */ + /* dict that is a member of the Blend dict. */ + + const FT_UInt dict = + ( loader->keywords_encountered & T1_PRIVATE ) + ? T1_FIELD_DICT_PRIVATE + : T1_FIELD_DICT_FONTDICT; + + + if ( !( dict & keyword->dict ) ) + { + FT_TRACE1(( "parse_dict: found `%s' but ignoring it" + " since it is in the wrong dictionary\n", + keyword->ident )); + break; + } + + if ( !( loader->keywords_encountered & + T1_FONTDIR_AFTER_PRIVATE ) || + ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) + { + parser->root.error = t1_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + { + if ( FT_ERR_EQ( parser->root.error, Ignore ) ) + parser->root.error = FT_Err_Ok; + else + return parser->root.error; + } + } + break; + } + + keyword++; + } + } + + have_integer = 0; + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 0; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + static void + t1_init_loader( T1_Loader loader, + T1_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + } + + + static void + t1_done_loader( T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + T1_Release_Table( &loader->subrs ); + + /* finalize hash */ + ft_hash_num_free( loader->subrs_hash, memory ); + FT_FREE( loader->subrs_hash ); + + /* finalize parser */ + T1_Finalize_Parser( parser ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Open_Face( T1_Face face ) + { + T1_LoaderRec loader; + T1_Parser parser; + T1_Font type1 = &face->type1; + PS_Private priv = &type1->private_dict; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t1_init_loader( &loader, face ); + + /* default values */ + face->ndv_idx = -1; + face->cdv_idx = -1; + face->len_buildchar = 0; + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = 4; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + parser = &loader.parser; + error = T1_New_Parser( parser, + face->root.stream, + face->root.memory, + psaux ); + if ( error ) + goto Exit; + + FT_TRACE4(( " top dictionary:\n" )); + error = parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + error = T1_Get_Private_Dict( parser, psaux ); + if ( error ) + goto Exit; + + FT_TRACE4(( " private dictionary:\n" )); + error = parse_dict( face, &loader, + parser->private_dict, parser->private_len ); + if ( error ) + goto Exit; + + /* ensure even-ness of `num_blue_values' */ + priv->num_blue_values &= ~1; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + /* we don't support Multiple Master fonts with intermediate designs; */ + /* this implies that `num_designs' must be equal to `2^^num_axis' */ + if ( face->blend && + face->blend->num_designs != ( 1U << face->blend->num_axis ) ) + { + FT_ERROR(( "T1_Open_Face:" + " number-of-designs != 2 ^^ number-of-axes\n" )); + T1_Done_Blend( FT_FACE( face ) ); + } + + if ( face->blend && + face->blend->num_default_design_vector != 0 && + face->blend->num_default_design_vector != face->blend->num_axis ) + { + /* we don't use it currently so just warn, reset, and ignore */ + FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " + "while there are %u axes.\n", + face->blend->num_default_design_vector, + face->blend->num_axis )); + + face->blend->num_default_design_vector = 0; + } + + /* the following can happen for MM instances; we then treat the */ + /* font as a normal PS font */ + if ( face->blend && + ( !face->blend->num_designs || !face->blend->num_axis ) ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid WeightVector */ + if ( face->blend && !face->blend->weight_vector ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignPositions */ + if ( face->blend && !face->blend->design_pos[0] ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignMap */ + if ( face->blend ) + { + FT_UInt i; + + + for ( i = 0; i < face->blend->num_axis; i++ ) + if ( !face->blend->design_map[i].num_points ) + { + T1_Done_Blend( FT_FACE( face ) ); + break; + } + } + + if ( face->blend ) + { + if ( face->len_buildchar > 0 ) + { + FT_Memory memory = face->root.memory; + + + if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) + { + FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); + face->len_buildchar = 0; + goto Exit; + } + } + } + else + face->len_buildchar = 0; + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + /* now, propagate the subrs, charstrings, and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( loader.subrs.init ) + { + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + type1->subrs_hash = loader.subrs_hash; + + /* prevent `t1_done_loader' from freeing the propagated data */ + loader.subrs.init = 0; + loader.subrs_hash = NULL; + } + + if ( !IS_INCREMENTAL ) + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); + error = FT_THROW( Invalid_File_Format ); + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = NULL; + loader.glyph_names.elements = NULL; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* the index is then stored in type1.encoding.char_index, and */ + /* the name to type1.encoding.char_name */ + + min_char = 0; + max_char = 0; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + const FT_String* char_name = + (const FT_String*)loader.encoding_table.elements[charcode]; + + + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + const FT_String* glyph_name = type1->glyph_names[idx]; + + + if ( ft_strcmp( char_name, glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( ".notdef", glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + /* some sanitizing to avoid overflows later on; */ + /* the upper limits are ad-hoc values */ + if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) + { + FT_TRACE2(( "T1_Open_Face:" + " setting unlikely BlueShift value %d to default (7)\n", + priv->blue_shift )); + priv->blue_shift = 7; + } + + if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) + { + FT_TRACE2(( "T1_Open_Face:" + " setting unlikely BlueFuzz value %d to default (1)\n", + priv->blue_fuzz )); + priv->blue_fuzz = 1; + } + + Exit: + t1_done_loader( &loader ); + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1load.h b/Dependencies/freetype/freetype/src/type1/t1load.h new file mode 100644 index 00000000..a45efa7c --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1load.h @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * t1load.h + * + * Type 1 font loader (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1LOAD_H_ +#define T1LOAD_H_ + + +#include +#include +#include + +#include "t1parse.h" + + +FT_BEGIN_HEADER + + + typedef struct T1_Loader_ + { + T1_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + FT_Int num_subrs; + PS_TableRec subrs; + FT_Hash subrs_hash; + FT_Bool fontdata; + + FT_UInt keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */ + + } T1_LoaderRec, *T1_Loader; + + + /* treatment of some keywords differs depending on whether */ + /* they precede or follow certain other keywords */ + +#define T1_PRIVATE ( 1 << 0 ) +#define T1_FONTDIR_AFTER_PRIVATE ( 1 << 1 ) + + + FT_LOCAL( FT_Error ) + T1_Open_Face( T1_Face face ); + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + + FT_LOCAL( FT_Error ) + T1_Get_Multi_Master( FT_Face face, + FT_Multi_Master* master ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_Var( FT_Face face, + FT_MM_Var* *master ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_Blend( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_Design( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + + FT_LOCAL( FT_Error ) + T1_Reset_MM_Blend( FT_Face face, + FT_UInt instance_index ); + + FT_LOCAL( FT_Error ) + T1_Get_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + T1_Set_Var_Design( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( void ) + T1_Done_Blend( FT_Face face ); + + FT_LOCAL( FT_Error ) + T1_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + +#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +FT_END_HEADER + +#endif /* T1LOAD_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1objs.c b/Dependencies/freetype/freetype/src/type1/t1objs.c new file mode 100644 index 00000000..b1b27c31 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1objs.c @@ -0,0 +1,655 @@ +/**************************************************************************** + * + * t1objs.c + * + * Type 1 objects manager (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "t1gload.h" +#include "t1load.h" + +#include "t1errors.h" + +#ifndef T1_CONFIG_OPTION_NO_AFM +#include "t1afm.h" +#endif + +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1objs + + + /************************************************************************** + * + * SIZE FUNCTIONS + * + */ + + + static PSH_Globals_Funcs + T1_Size_Get_Globals_Funcs( T1_Size size ) + { + T1_Face face = (T1_Face)size->root.face; + PSHinter_Service pshinter = (PSHinter_Service)face->pshinter; + FT_Module module; + + + module = FT_Get_Module( size->root.face->driver->root.library, + "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) + ? pshinter->get_globals_funcs( module ) + : 0; + } + + + FT_LOCAL_DEF( void ) + T1_Size_Done( FT_Size t1size ) /* T1_Size */ + { + T1_Size size = (T1_Size)t1size; + + + if ( t1size->internal->module_data ) + { + PSH_Globals_Funcs funcs; + + + funcs = T1_Size_Get_Globals_Funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)t1size->internal->module_data ); + + t1size->internal->module_data = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Init( FT_Size t1size ) /* T1_Size */ + { + T1_Size size = (T1_Size)t1size; + FT_Error error = FT_Err_Ok; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + if ( funcs ) + { + PSH_Globals globals; + T1_Face face = (T1_Face)size->root.face; + + + error = funcs->create( size->root.face->memory, + &face->type1.private_dict, &globals ); + if ( !error ) + t1size->internal->module_data = globals; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Size_Request( FT_Size t1size, /* T1_Size */ + FT_Size_Request req ) + { + FT_Error error; + + T1_Size size = (T1_Size)t1size; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + + + error = FT_Request_Metrics( size->root.face, req ); + if ( error ) + goto Exit; + + if ( funcs ) + funcs->set_scale( (PSH_Globals)t1size->internal->module_data, + size->root.metrics.x_scale, + size->root.metrics.y_scale, + 0, 0 ); + + Exit: + return error; + } + + + /************************************************************************** + * + * SLOT FUNCTIONS + * + */ + + FT_LOCAL_DEF( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ) + { + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal ) + slot->internal->glyph_hints = NULL; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ) + { + T1_Face face; + PSHinter_Service pshinter; + + + face = (T1_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + + if ( pshinter ) + { + FT_Module module; + + + module = FT_Get_Module( slot->library, "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + + + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + + return 0; + } + + + /************************************************************************** + * + * FACE FUNCTIONS + * + */ + + + /************************************************************************** + * + * @Function: + * T1_Face_Done + * + * @Description: + * The face object destructor. + * + * @Input: + * face :: + * A typeless pointer to the face object to destroy. + */ + FT_LOCAL_DEF( void ) + T1_Face_Done( FT_Face t1face ) /* T1_Face */ + { + T1_Face face = (T1_Face)t1face; + FT_Memory memory; + T1_Font type1; + + + if ( !face ) + return; + + memory = face->root.memory; + type1 = &face->type1; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + /* release multiple masters information */ + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + + if ( face->buildchar ) + { + FT_FREE( face->buildchar ); + + face->len_buildchar = 0; + } + + T1_Done_Blend( t1face ); + face->blend = NULL; +#endif + + /* release font info strings */ + { + PS_FontInfo info = &type1->font_info; + + + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + } + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->subrs ); + FT_FREE( type1->subrs_len ); + + ft_hash_num_free( type1->subrs_hash, memory ); + FT_FREE( type1->subrs_hash ); + + FT_FREE( type1->subrs_block ); + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + +#ifndef T1_CONFIG_OPTION_NO_AFM + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); +#endif + + /* release unicode map, if any */ +#if 0 + FT_FREE( face->unicode_map_rec.maps ); + face->unicode_map_rec.num_maps = 0; + face->unicode_map = NULL; +#endif + + face->root.family_name = NULL; + face->root.style_name = NULL; + } + + + /************************************************************************** + * + * @Function: + * T1_Face_Init + * + * @Description: + * The face object constructor. + * + * @Input: + * stream :: + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. + * + * face_index :: + * The index of the font face in the resource. + * + * num_params :: + * Number of additional generic parameters. Ignored. + * + * params :: + * Additional generic parameters. Ignored. + * + * @InOut: + * face :: + * The face record to build. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Face_Init( FT_Stream stream, + FT_Face t1face, /* T1_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T1_Face face = (T1_Face)t1face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T1_Face_Init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "pshinter" ); + + FT_TRACE2(( "Type 1 driver\n" )); + + /* open the tokenizer; this will also check the font format */ + error = T1_Open_Face( face ); + if ( error ) + goto Exit; + + FT_TRACE2(( "T1_Face_Init: %p (index %d)\n", + (void *)face, + face_index )); + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "T1_Face_Init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* now load the font program into the face object */ + + /* initialize the face object fields */ + + /* set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + + + root->num_glyphs = type1->num_glyphs; + root->face_index = 0; + + root->face_flags |= FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES | + FT_FACE_FLAG_HINTER; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( face->blend ) + root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + + /* The following code to extract the family and the style is very */ + /* simplistic and might get some things wrong. For a full-featured */ + /* algorithm you might have a look at the whitepaper given at */ + /* */ + /* https://blogs.msdn.com/text/archive/2007/04/23/wpf-font-selection-model.aspx */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + root->style_name = NULL; + + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + FT_Bool the_same = TRUE; + + + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + the_same = FALSE; + + if ( !*family ) + root->style_name = full; + break; + } + } + } + + if ( the_same ) + root->style_name = (char *)"Regular"; + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + if ( !root->style_name ) + { + if ( info->weight ) + root->style_name = info->weight; + else + /* assume `Regular' style because we don't know better */ + root->style_name = (char *)"Regular"; + } + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = NULL; + + root->bbox.xMin = type1->font_bbox.xMin >> 16; + root->bbox.yMin = type1->font_bbox.yMin >> 16; + /* no `U' suffix here to 0xFFFF! */ + root->bbox.xMax = ( type1->font_bbox.xMax + 0xFFFF ) >> 16; + root->bbox.yMax = ( type1->font_bbox.yMax + 0xFFFF ) >> 16; + + /* Set units_per_EM if we didn't set it in t1_parse_font_matrix. */ + if ( !root->units_per_EM ) + root->units_per_EM = 1000; + + root->ascender = (FT_Short)( root->bbox.yMax ); + root->descender = (FT_Short)( root->bbox.yMin ); + + root->height = (FT_Short)( ( root->units_per_EM * 12 ) / 10 ); + if ( root->height < root->ascender - root->descender ) + root->height = (FT_Short)( root->ascender - root->descender ); + + /* now compute the maximum advance width */ + root->max_advance_width = + (FT_Short)( root->bbox.xMax ); + { + FT_Pos max_advance; + + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = (FT_Short)FIXED_TO_INT( max_advance ); + else + error = FT_Err_Ok; /* clear error */ + } + + root->max_advance_height = root->height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + } + + { + FT_Face root = &face->root; + + + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * T1_Driver_Init + * + * @Description: + * Initializes a given Type 1 driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T1_Driver_Init( FT_Module module ) + { + PS_Driver driver = (PS_Driver)module; + + FT_UInt32 seed; + + + /* set default property values, cf. `ftt1drv.h' */ + driver->hinting_engine = FT_HINTING_ADOBE; + + driver->no_stem_darkening = TRUE; + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; + driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; + driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; + driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; + driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; + driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; + driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; + + /* compute random seed from some memory addresses */ + seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^ + (FT_Offset)(char*)&module ^ + (FT_Offset)(char*)module->memory ); + seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 ); + + driver->random_seed = (FT_Int32)seed; + if ( driver->random_seed < 0 ) + driver->random_seed = -driver->random_seed; + else if ( driver->random_seed == 0 ) + driver->random_seed = 123456789; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * T1_Driver_Done + * + * @Description: + * Finalizes a given Type 1 driver. + * + * @Input: + * driver :: + * A handle to the target Type 1 driver. + */ + FT_LOCAL_DEF( void ) + T1_Driver_Done( FT_Module driver ) + { + FT_UNUSED( driver ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1objs.h b/Dependencies/freetype/freetype/src/type1/t1objs.h new file mode 100644 index 00000000..3809370c --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1objs.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * + * t1objs.h + * + * Type 1 objects manager (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1OBJS_H_ +#define T1OBJS_H_ + + +#include +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + + /************************************************************************** + * + * @Type: + * T1_Size + * + * @Description: + * A handle to a Type 1 size object. + */ + typedef struct T1_SizeRec_* T1_Size; + + + /************************************************************************** + * + * @Type: + * T1_GlyphSlot + * + * @Description: + * A handle to a Type 1 glyph slot object. + */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /************************************************************************** + * + * @Type: + * T1_CharMap + * + * @Description: + * A handle to a Type 1 character mapping object. + * + * @Note: + * The Type 1 format doesn't use a charmap but an encoding table. + * The driver is responsible for making up charmap objects + * corresponding to these tables. + */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + /************************************************************************** + * + * HERE BEGINS THE TYPE1 SPECIFIC STUFF + * + */ + + + /************************************************************************** + * + * @Type: + * T1_SizeRec + * + * @Description: + * Type 1 size record. + */ + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + + } T1_SizeRec; + + + FT_LOCAL( void ) + T1_Size_Done( FT_Size size ); + + FT_LOCAL( FT_Error ) + T1_Size_Request( FT_Size size, + FT_Size_Request req ); + + FT_LOCAL( FT_Error ) + T1_Size_Init( FT_Size size ); + + + /************************************************************************** + * + * @Type: + * T1_GlyphSlotRec + * + * @Description: + * Type 1 glyph slot record. + */ + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + FT_Bool hint; + FT_Bool scaled; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + FT_Int max_points; + FT_Int max_contours; + + } T1_GlyphSlotRec; + + + FT_LOCAL( FT_Error ) + T1_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + FT_LOCAL( void ) + T1_Face_Done( FT_Face face ); + + FT_LOCAL( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ); + + FT_LOCAL( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ); + + FT_LOCAL( FT_Error ) + T1_Driver_Init( FT_Module driver ); + + FT_LOCAL( void ) + T1_Driver_Done( FT_Module driver ); + + +FT_END_HEADER + +#endif /* T1OBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1parse.c b/Dependencies/freetype/freetype/src/type1/t1parse.c new file mode 100644 index 00000000..3717ea7c --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1parse.c @@ -0,0 +1,487 @@ +/**************************************************************************** + * + * t1parse.c + * + * Type 1 parser (body). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * The Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of objects called + * a `T1_Table' (used to build various tables needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level and private + * dictionaries. + * + * - read numbers, arrays & strings from any dictionary. + * + * See `t1load.c' to see how data is loaded from the font file. + * + */ + + +#include +#include +#include + +#include "t1parse.h" + +#include "t1errors.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t1parse + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** INPUT STREAM PARSER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + /* see Adobe Technical Note 5040.Download_Fonts.pdf */ + + static FT_Error + read_pfb_tag( FT_Stream stream, + FT_UShort *atag, + FT_ULong *asize ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + + + *atag = 0; + *asize = 0; + + if ( !FT_READ_USHORT( tag ) ) + { + if ( tag == 0x8001U || tag == 0x8002U ) + { + if ( !FT_READ_ULONG_LE( size ) ) + *asize = size; + } + + *atag = tag; + } + + return error; + } + + + static FT_Error + check_type1_format( FT_Stream stream, + const char* header_string, + size_t header_length ) + { + FT_Error error; + FT_UShort tag; + FT_ULong dummy; + + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &dummy ); + if ( error ) + goto Exit; + + /* We assume that the first segment in a PFB is always encoded as */ + /* text. This might be wrong (and the specification doesn't insist */ + /* on that), but we have never seen a counterexample. */ + if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) ) + goto Exit; + + if ( !FT_FRAME_ENTER( header_length ) ) + { + error = FT_Err_Ok; + + if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 ) + error = FT_THROW( Unknown_File_Format ); + + FT_FRAME_EXIT(); + } + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + + + psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = NULL; + parser->private_len = 0; + parser->private_dict = NULL; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; + + /* check the header format */ + error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); + if ( error ) + { + if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) + goto Exit; + + error = check_type1_format( stream, "%!FontType", 10 ); + if ( error ) + { + FT_TRACE2(( " not a Type 1 font\n" )); + goto Exit; + } + } + + /******************************************************************* + * + * Here a short summary of what is going on: + * + * When creating a new Type 1 parser, we try to locate and load + * the base dictionary if this is possible (i.e., for PFB + * files). Otherwise, we load the whole font into memory. + * + * When `loading' the base dictionary, we only setup pointers + * in the case of a memory-based stream. Otherwise, we + * allocate and load the base dictionary in it. + * + * parser->in_pfb is set if we are in a binary (`.pfb') font. + * parser->in_memory is set if we have a memory stream. + */ + + /* try to compute the size of the base dictionary; */ + /* look for a Postscript binary file tag, i.e., 0x8001 */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + + if ( tag != 0x8001U ) + { + /* assume that this is a PFA file for now; an error will */ + /* be produced later when more things are checked */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + size = stream->size; + } + else + parser->in_pfb = 1; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory -- this is clumsy, but so does the format */ + if ( FT_QALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + T1_Finalize_Parser( T1_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* always free the private dictionary */ + FT_FREE( parser->private_dict ); + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + parser->root.funcs.done( &parser->root ); + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->root.memory; + FT_Error error = FT_Err_Ok; + FT_ULong size; + + + if ( parser->in_pfb ) + { + /* in the case of the PFB format, the private dictionary can be */ + /* made of several segments. We thus first read the number of */ + /* segments to compute the total size of the private dictionary */ + /* then re-read them into memory. */ + FT_ULong start_pos = FT_STREAM_POS(); + FT_UShort tag; + + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Fail; + + if ( tag != 0x8002U ) + break; + + parser->private_len += size; + + if ( FT_STREAM_SKIP( size ) ) + goto Fail; + } + + /* Check that we have a private dictionary there */ + /* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( FT_STREAM_SEEK( start_pos ) || + FT_QALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error || tag != 0x8002U ) + { + error = FT_Err_Ok; + break; + } + + if ( FT_STREAM_READ( parser->private_dict + parser->private_len, + size ) ) + goto Fail; + + parser->private_len += size; + } + } + else + { + /* We have already `loaded' the whole PFA font file into memory; */ + /* if this is a memory resource, allocate a new block to hold */ + /* the private dict. Otherwise, simply overwrite into the base */ + /* dictionary block in the heap. */ + + /* First look for the `eexec' keyword. Ensure `eexec' is real -- */ + /* it could be in a comment or string (as e.g. in u003043t.gsf */ + /* from ghostscript). */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Pointer pos_lf; + FT_Bool test_cr; + + + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->base_dict + parser->base_len; + + cur = parser->root.cursor; + limit = parser->root.limit; + + while ( cur < limit ) + { + /* 9 = 5 letters for `eexec' + whitespace + 4 chars */ + if ( cur[0] == 'e' && cur + 9 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'x' && + cur[3] == 'e' && + cur[4] == 'c' ) + goto Found; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + break; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + FT_ERROR(( "T1_Get_Private_Dict: could not find `eexec' keyword\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + /* now determine where to write the _encrypted_ binary private */ + /* dictionary. We overwrite the base dictionary for disk-based */ + /* resources and allocate a new block otherwise */ + + Found: + parser->root.limit = parser->base_dict + parser->base_len; + + T1_Skip_PS_Token( parser ); + cur = parser->root.cursor; + limit = parser->root.limit; + + /* According to the Type 1 spec, the first cipher byte must not be */ + /* an ASCII whitespace character code (blank, tab, carriage return */ + /* or line feed). We have seen Type 1 fonts with two line feed */ + /* characters... So skip now all whitespace character codes. */ + /* */ + /* On the other hand, Adobe's Type 1 parser handles fonts just */ + /* fine that are violating this limitation, so we add a heuristic */ + /* test to stop at \r only if it is not used for EOL. */ + + pos_lf = ft_memchr( cur, '\n', (size_t)( limit - cur ) ); + test_cr = FT_BOOL( !pos_lf || + pos_lf > ft_memchr( cur, + '\r', + (size_t)( limit - cur ) ) ); + + while ( cur < limit && + ( *cur == ' ' || + *cur == '\t' || + (test_cr && *cur == '\r' ) || + *cur == '\n' ) ) + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " `eexec' not properly terminated\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + size = parser->base_len - (FT_ULong)( cur - parser->base_dict ); + + if ( parser->in_memory ) + { + /* note that we allocate one more byte to put a terminating `0' */ + if ( FT_QALLOC( parser->private_dict, size + 1 ) ) + goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = NULL; + parser->base_len = 0; + } + + /* now determine whether the private dictionary is encoded in binary */ + /* or hexadecimal ASCII format -- decode it accordingly */ + + /* we need to access the next 4 bytes (after the final whitespace */ + /* following the `eexec' keyword); if they all are hexadecimal */ + /* digits, then we have a case of ASCII storage */ + + if ( cur + 3 < limit && + ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && + ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) + { + /* ASCII hexadecimal encoding */ + FT_ULong len; + + + parser->root.cursor = cur; + (void)psaux->ps_parser_funcs->to_bytes( &parser->root, + parser->private_dict, + parser->private_len, + &len, + 0 ); + parser->private_len = len; + + /* put a safeguard */ + parser->private_dict[len] = '\0'; + } + else + /* binary encoding -- copy the private dict */ + FT_MEM_MOVE( parser->private_dict, cur, size ); + } + + /* we now decrypt the encoded binary private dictionary */ + psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); + + if ( parser->private_len < 4 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* replace the four random bytes at the beginning with whitespace */ + parser->private_dict[0] = ' '; + parser->private_dict[1] = ' '; + parser->private_dict[2] = ' '; + parser->private_dict[3] = ' '; + + parser->root.base = parser->private_dict; + parser->root.cursor = parser->private_dict; + parser->root.limit = parser->root.cursor + parser->private_len; + + Fail: + Exit: + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1parse.h b/Dependencies/freetype/freetype/src/type1/t1parse.h new file mode 100644 index 00000000..a0a2134d --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1parse.h @@ -0,0 +1,137 @@ +/**************************************************************************** + * + * t1parse.h + * + * Type 1 parser (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T1PARSE_H_ +#define T1PARSE_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @Struct: + * T1_ParserRec + * + * @Description: + * A PS_ParserRec is an object used to parse a Type 1 fonts very + * quickly. + * + * @Fields: + * root :: + * The root parser. + * + * stream :: + * The current input stream. + * + * base_dict :: + * A pointer to the top-level dictionary. + * + * base_len :: + * The length in bytes of the top dictionary. + * + * private_dict :: + * A pointer to the private dictionary. + * + * private_len :: + * The length in bytes of the private dictionary. + * + * in_pfb :: + * A boolean. Indicates that we are handling a PFB + * file. + * + * in_memory :: + * A boolean. Indicates a memory-based stream. + * + * single_block :: + * A boolean. Indicates that the private dictionary + * is stored in lieu of the base dictionary. + */ + typedef struct T1_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_ULong base_len; + + FT_Byte* private_dict; + FT_ULong private_len; + + FT_Bool in_pfb; + FT_Bool in_memory; + FT_Bool single_block; + + } T1_ParserRec, *T1_Parser; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) + +#define T1_ToCoordArray( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define T1_ToTokenArray( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) + +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + FT_LOCAL( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ); + + FT_LOCAL( void ) + T1_Finalize_Parser( T1_Parser parser ); + + +FT_END_HEADER + +#endif /* T1PARSE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/t1tokens.h b/Dependencies/freetype/freetype/src/type1/t1tokens.h new file mode 100644 index 00000000..5a3d2f1e --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/t1tokens.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * + * t1tokens.h + * + * Type 1 tokenizer (specification). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Notice", notice, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FullName", full_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FamilyName", family_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Weight", weight, + T1_FIELD_DICT_FONTDICT ) + + /* we use pointers to detect modifications made by synthetic fonts */ + T1_FIELD_NUM ( "ItalicAngle", italic_angle, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, + T1_FIELD_DICT_FONTDICT ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, + T1_FIELD_DICT_FONTDICT ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + + T1_FIELD_NUM ( "UniqueID", unique_id, + T1_FIELD_DICT_FONTDICT | T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "lenIV", lenIV, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "LanguageGroup", language_group, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "password", password, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueShift", blue_shift, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, + T1_FIELD_DICT_PRIVATE ) + + T1_FIELD_FIXED ( "ExpansionFactor", expansion_factor, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_BOOL ( "ForceBold", force_bold, + T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "PaintType", paint_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "FontType", font_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, T1_FIELD_DICT_FONTDICT ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, T1_FIELD_DICT_FONTDICT ) + + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FaceRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FACE + + T1_FIELD_NUM( "NDV", ndv_idx, T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM( "CDV", cdv_idx, T1_FIELD_DICT_PRIVATE ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_BlendRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BLEND + + T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, + T1_MAX_MM_DESIGNS, T1_FIELD_DICT_FONTDICT ) + + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type1/type1.c b/Dependencies/freetype/freetype/src/type1/type1.c new file mode 100644 index 00000000..d7ff53c7 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type1/type1.c @@ -0,0 +1,29 @@ +/**************************************************************************** + * + * type1.c + * + * FreeType Type 1 driver component (body only). + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "t1afm.c" +#include "t1driver.c" +#include "t1gload.c" +#include "t1load.c" +#include "t1objs.c" +#include "t1parse.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42drivr.c b/Dependencies/freetype/freetype/src/type42/t42drivr.c new file mode 100644 index 00000000..25f507f1 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42drivr.c @@ -0,0 +1,248 @@ +/**************************************************************************** + * + * t42drivr.c + * + * High-level Type 42 driver interface (body). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This driver implements Type42 fonts as described in the + * Technical Note #5012 from Adobe, with these limitations: + * + * 1) CID Fonts are not currently supported. + * 2) Incremental fonts making use of the GlyphDirectory keyword + * will be loaded, but the rendering will be using the TrueType + * tables. + * 3) As for Type1 fonts, CDevProc is not supported. + * 4) The Metrics dictionary is not supported. + * 5) AFM metrics are not supported. + * + * In other words, this driver supports Type42 fonts derived from + * TrueType fonts in a non-CID manner, as done by usual conversion + * programs. + * + */ + + +#include "t42drivr.h" +#include "t42objs.h" +#include "t42error.h" +#include + +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + /* + * + * GLYPH DICT SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t42_get_glyph_name( FT_Face face, /* T42_Face */ + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + T42_Face t42face = (T42_Face)face; + + + FT_STRCPYN( buffer, + t42face->type1.glyph_names[glyph_index], + buffer_max ); + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + t42_get_name_index( FT_Face face, /* T42_Face */ + const FT_String* glyph_name ) + { + T42_Face t42face = (T42_Face)face; + FT_Int i; + + + for ( i = 0; i < t42face->type1.num_glyphs; i++ ) + { + FT_String* gname = t42face->type1.glyph_names[i]; + + + if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)ft_strtol( + (const char *)t42face->type1.charstrings[i], + NULL, + 10 ); + } + + return 0; + } + + + static const FT_Service_GlyphDictRec t42_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t42_get_glyph_name, /* get_name */ + (FT_GlyphDict_NameIndexFunc)t42_get_name_index /* name_index */ + }; + + + /* + * + * POSTSCRIPT NAME SERVICE + * + */ + + FT_CALLBACK_DEF( const char* ) + t42_get_ps_font_name( FT_Face face ) /* T42_Face */ + { + T42_Face t42face = (T42_Face)face; + + + return (const char*)t42face->type1.font_name; + } + + + static const FT_Service_PsFontNameRec t42_service_ps_font_name = + { + (FT_PsName_GetFunc)t42_get_ps_font_name /* get_ps_font_name */ + }; + + + /* + * + * POSTSCRIPT INFO SERVICE + * + */ + + FT_CALLBACK_DEF( FT_Error ) + t42_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T42_Face)face)->type1.font_info; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Error ) + t42_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T42_Face)face)->type1.font_extra; + + return FT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_Int ) + t42_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + + return 1; + } + + + static const FT_Service_PsInfoRec t42_service_ps_info = + { + (PS_GetFontInfoFunc) t42_ps_get_font_info, /* ps_get_font_info */ + (PS_GetFontExtraFunc) t42_ps_get_font_extra, /* ps_get_font_extra */ + (PS_HasGlyphNamesFunc) t42_ps_has_glyph_names, /* ps_has_glyph_names */ + /* Type42 fonts don't have a Private dict */ + (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ + /* not implemented */ + (PS_GetFontValueFunc) NULL /* ps_get_font_value */ + }; + + + /* + * + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec t42_services[] = + { + { FT_SERVICE_ID_GLYPH_DICT, &t42_service_glyph_dict }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t42_service_ps_font_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t42_service_ps_info }, + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TYPE_42 }, + { NULL, NULL } + }; + + + FT_CALLBACK_DEF( FT_Module_Interface ) + T42_Get_Interface( FT_Module module, + const FT_String* t42_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( t42_services, t42_interface ); + } + + + const FT_Driver_ClassRec t42_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | +#ifdef TT_USE_BYTECODE_INTERPRETER + FT_MODULE_DRIVER_HAS_HINTER, +#else + 0, +#endif + + sizeof ( T42_DriverRec ), + + "type42", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + T42_Driver_Init, /* FT_Module_Constructor module_init */ + T42_Driver_Done, /* FT_Module_Destructor module_done */ + T42_Get_Interface, /* FT_Module_Requester get_interface */ + }, + + sizeof ( T42_FaceRec ), + sizeof ( T42_SizeRec ), + sizeof ( T42_GlyphSlotRec ), + + T42_Face_Init, /* FT_Face_InitFunc init_face */ + T42_Face_Done, /* FT_Face_DoneFunc done_face */ + T42_Size_Init, /* FT_Size_InitFunc init_size */ + T42_Size_Done, /* FT_Size_DoneFunc done_size */ + T42_GlyphSlot_Init, /* FT_Slot_InitFunc init_slot */ + T42_GlyphSlot_Done, /* FT_Slot_DoneFunc done_slot */ + + T42_GlyphSlot_Load, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + T42_Size_Request, /* FT_Size_RequestFunc request_size */ + T42_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42drivr.h b/Dependencies/freetype/freetype/src/type42/t42drivr.h new file mode 100644 index 00000000..5b3852b8 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42drivr.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * + * t42drivr.h + * + * High-level Type 42 driver interface (specification). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42DRIVR_H_ +#define T42DRIVR_H_ + + +#include + + +FT_BEGIN_HEADER + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class; + +FT_END_HEADER + + +#endif /* T42DRIVR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42error.h b/Dependencies/freetype/freetype/src/type42/t42error.h new file mode 100644 index 00000000..f52205e2 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42error.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * t42error.h + * + * Type 42 error codes (specification only). + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Type 42 error enumeration constants. + * + */ + +#ifndef T42ERROR_H_ +#define T42ERROR_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T42_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type42 + +#include + +#endif /* T42ERROR_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42objs.c b/Dependencies/freetype/freetype/src/type42/t42objs.c new file mode 100644 index 00000000..7010ba86 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42objs.c @@ -0,0 +1,698 @@ +/**************************************************************************** + * + * t42objs.c + * + * Type 42 objects manager (body). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t42objs.h" +#include "t42parse.h" +#include "t42error.h" +#include +#include +#include + + +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + static FT_Error + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t42_loader_init( &loader, face ); + + parser = &loader.parser; + + face->ttf_data = NULL; + face->ttf_size = 0; + + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + + error = t42_parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + + if ( type1->font_type != 42 ) + { + FT_ERROR(( "T42_Open_Face: cannot handle FontType %d\n", + type1->font_type )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* now, propagate the charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T42_Open_Face: no charstrings array in face\n" )); + error = FT_THROW( Invalid_File_Format ); + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = NULL; + loader.glyph_names.elements = NULL; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* as defined in the CharStrings array. */ + /* The index is then stored in type1.encoding.char_index, and */ + /* the name in type1.encoding.char_name */ + + min_char = 0; + max_char = 0; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + const FT_String* char_name = + (const FT_String*)loader.encoding_table.elements[charcode]; + + + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = ".notdef"; + + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + const FT_String* glyph_name = type1->glyph_names[idx]; + + + if ( ft_strcmp( char_name, glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( ".notdef", glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t42_loader_done( &loader ); + if ( error ) + { + FT_FREE( face->ttf_data ); + face->ttf_size = 0; + } + return error; + } + + + /***************** Driver Functions *************/ + + + FT_LOCAL_DEF( FT_Error ) + T42_Face_Init( FT_Stream stream, + FT_Face t42face, /* T42_Face */ + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T42_Face face = (T42_Face)t42face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + FT_Face root = (FT_Face)&face->root; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + + + face->ttf_face = NULL; + face->root.num_faces = 1; + + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T42_Face_Init: cannot access `psaux' module\n" )); + error = FT_THROW( Missing_Module ); + goto Exit; + } + + FT_TRACE2(( "Type 42 driver\n" )); + + /* open the tokenizer, this will also check the font format */ + error = T42_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( ( face_index & 0xFFFF ) > 0 ) + { + FT_ERROR(( "T42_Face_Init: invalid face index\n" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Now load the font program into the face object */ + + /* Init the face object fields */ + /* Now set up root face fields */ + + root->num_glyphs = type1->num_glyphs; + root->num_charmaps = 0; + root->face_index = 0; + + root->face_flags |= FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES; + + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + root->face_flags |= FT_FACE_FLAG_HINTER; +#endif + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + /* assume "Regular" style if we don't know better */ + root->style_name = (char *)"Regular"; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + + + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + root->style_name = full; + break; + } + } + } + } + } + else + { + /* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = NULL; + + /* Load the TTF font embedded in the T42 font */ + { + FT_Open_Args args; + + + args.flags = FT_OPEN_MEMORY | FT_OPEN_DRIVER; + args.driver = FT_Get_Module( FT_FACE_LIBRARY( face ), + "truetype" ); + args.memory_base = face->ttf_data; + args.memory_size = face->ttf_size; + + if ( num_params ) + { + args.flags |= FT_OPEN_PARAMS; + args.num_params = num_params; + args.params = params; + } + + error = FT_Open_Face( FT_FACE_LIBRARY( face ), + &args, 0, &face->ttf_face ); + } + + if ( error ) + goto Exit; + + FT_Done_Size( face->ttf_face->size ); + + /* Ignore info in FontInfo dictionary and use the info from the */ + /* loaded TTF font. The PostScript interpreter also ignores it. */ + root->bbox = face->ttf_face->bbox; + root->units_per_EM = face->ttf_face->units_per_EM; + + root->ascender = face->ttf_face->ascender; + root->descender = face->ttf_face->descender; + root->height = face->ttf_face->height; + + root->max_advance_width = face->ttf_face->max_advance_width; + root->max_advance_height = face->ttf_face->max_advance_height; + + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + + /* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) + root->face_flags |= FT_FACE_FLAG_VERTICAL; + + { + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); + } + } + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + T42_Face_Done( FT_Face t42face ) + { + T42_Face face = (T42_Face)t42face; + T1_Font type1; + PS_FontInfo info; + FT_Memory memory; + + + if ( !face ) + return; + + type1 = &face->type1; + info = &type1->font_info; + memory = face->root.memory; + + /* delete internal ttf face prior to freeing face->ttf_data */ + if ( face->ttf_face ) + FT_Done_Face( face->ttf_face ); + + /* release font info strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + + FT_FREE( face->ttf_data ); + +#if 0 + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FT_FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = NULL; + face->root.style_name = NULL; + } + + + /************************************************************************** + * + * @Function: + * T42_Driver_Init + * + * @Description: + * Initializes a given Type 42 driver object. + * + * @Input: + * driver :: + * A handle to the target driver object. + * + * @Return: + * FreeType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + T42_Driver_Init( FT_Module module ) /* T42_Driver */ + { + T42_Driver driver = (T42_Driver)module; + FT_Module ttmodule; + + + ttmodule = FT_Get_Module( module->library, "truetype" ); + if ( !ttmodule ) + { + FT_ERROR(( "T42_Driver_Init: cannot access `truetype' module\n" )); + return FT_THROW( Missing_Module ); + } + + driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T42_Driver_Done( FT_Module module ) + { + FT_UNUSED( module ); + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Init( FT_Size size ) /* T42_Size */ + { + T42_Size t42size = (T42_Size)size; + FT_Face face = size->face; + T42_Face t42face = (T42_Face)face; + FT_Size ttsize; + FT_Error error; + + + error = FT_New_Size( t42face->ttf_face, &ttsize ); + if ( !error ) + t42size->ttsize = ttsize; + + FT_Activate_Size( ttsize ); + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Request( FT_Size t42size, /* T42_Size */ + FT_Size_Request req ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Request_Size( face->ttf_face, req ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Select( FT_Size t42size, /* T42_Size */ + FT_ULong strike_index ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + + + FT_Activate_Size( size->ttsize ); + + error = FT_Select_Size( face->ttf_face, (FT_Int)strike_index ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + + return error; + + } + + + FT_LOCAL_DEF( void ) + T42_Size_Done( FT_Size t42size ) /* T42_Size */ + { + T42_Size size = (T42_Size)t42size; + FT_Face face = t42size->face; + T42_Face t42face = (T42_Face)face; + FT_ListNode node; + + + node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); + if ( node ) + { + FT_Done_Size( size->ttsize ); + size->ttsize = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Init( FT_GlyphSlot t42slot ) /* T42_GlyphSlot */ + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + FT_Face face = t42slot->face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot ttslot; + FT_Memory memory = face->memory; + FT_Error error = FT_Err_Ok; + + + if ( !face->glyph ) + { + /* First glyph slot for this face */ + slot->ttslot = t42face->ttf_face->glyph; + } + else + { + error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); + if ( !error ) + slot->ttslot = ttslot; + } + + /* share the loader so that the autohinter can see it */ + FT_GlyphLoader_Done( slot->ttslot->internal->loader ); + FT_FREE( slot->ttslot->internal ); + slot->ttslot->internal = t42slot->internal; + + return error; + } + + + FT_LOCAL_DEF( void ) + T42_GlyphSlot_Done( FT_GlyphSlot t42slot ) /* T42_GlyphSlot */ + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + + + /* do not destroy the inherited internal structure just yet */ + slot->ttslot->internal = NULL; + FT_Done_GlyphSlot( slot->ttslot ); + } + + + static void + t42_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); + + /* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + FT_ZERO( &slot->bitmap ); + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = NULL; + slot->control_data = NULL; + slot->control_len = 0; + slot->other = NULL; + slot->format = FT_GLYPH_FORMAT_NONE; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; + T42_Size t42size = (T42_Size)size; + T42_Face t42face = (T42_Face)size->face; + FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; + + + FT_TRACE1(( "T42_GlyphSlot_Load: glyph index %d\n", glyph_index )); + + /* map T42 glyph index to embedded TTF's glyph index */ + glyph_index = (FT_UInt)ft_strtol( + (const char *)t42face->type1.charstrings[glyph_index], + NULL, 10 ); + + t42_glyphslot_clear( t42slot->ttslot ); + error = ttclazz->load_glyph( t42slot->ttslot, + t42size->ttsize, + glyph_index, + load_flags | FT_LOAD_NO_BITMAP ); + + if ( !error ) + { + glyph->metrics = t42slot->ttslot->metrics; + + glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; + glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; + + glyph->format = t42slot->ttslot->format; + glyph->outline = t42slot->ttslot->outline; + + glyph->bitmap = t42slot->ttslot->bitmap; + glyph->bitmap_left = t42slot->ttslot->bitmap_left; + glyph->bitmap_top = t42slot->ttslot->bitmap_top; + + glyph->num_subglyphs = t42slot->ttslot->num_subglyphs; + glyph->subglyphs = t42slot->ttslot->subglyphs; + + glyph->control_data = t42slot->ttslot->control_data; + glyph->control_len = t42slot->ttslot->control_len; + } + + return error; + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42objs.h b/Dependencies/freetype/freetype/src/type42/t42objs.h new file mode 100644 index 00000000..3ca83bc5 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42objs.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * + * t42objs.h + * + * Type 42 objects manager (specification). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42OBJS_H_ +#define T42OBJS_H_ + +#include +#include +#include +#include "t42types.h" +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + /* Type42 size */ + typedef struct T42_SizeRec_ + { + FT_SizeRec root; + FT_Size ttsize; + + } T42_SizeRec, *T42_Size; + + + /* Type42 slot */ + typedef struct T42_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_GlyphSlot ttslot; + + } T42_GlyphSlotRec, *T42_GlyphSlot; + + + /* Type 42 driver */ + typedef struct T42_DriverRec_ + { + FT_DriverRec root; + FT_Driver_Class ttclazz; + + } T42_DriverRec, *T42_Driver; + + + /* */ + + + FT_LOCAL( FT_Error ) + T42_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + FT_LOCAL( void ) + T42_Face_Done( FT_Face face ); + + + FT_LOCAL( FT_Error ) + T42_Size_Init( FT_Size size ); + + + FT_LOCAL( FT_Error ) + T42_Size_Request( FT_Size size, + FT_Size_Request req ); + + + FT_LOCAL( FT_Error ) + T42_Size_Select( FT_Size size, + FT_ULong strike_index ); + + + FT_LOCAL( void ) + T42_Size_Done( FT_Size size ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Init( FT_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + + FT_LOCAL( void ) + T42_GlyphSlot_Done( FT_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_Driver_Init( FT_Module module ); + + FT_LOCAL( void ) + T42_Driver_Done( FT_Module module ); + + /* */ + +FT_END_HEADER + + +#endif /* T42OBJS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42parse.c b/Dependencies/freetype/freetype/src/type42/t42parse.c new file mode 100644 index 00000000..e53d3528 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42parse.c @@ -0,0 +1,1351 @@ +/**************************************************************************** + * + * t42parse.c + * + * Type 42 font parser (body). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include "t42parse.h" +#include "t42error.h" +#include +#include +#include + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT t42 + + + static void + t42_parse_font_matrix( FT_Face face, + void* loader_ ); + static void + t42_parse_encoding( FT_Face face, + void* loader_ ); + + static void + t42_parse_charstrings( FT_Face face, + void* loader_ ); + + static void + t42_parse_sfnts( FT_Face face, + void* loader_ ); + + + /* as Type42 fonts have no Private dict, */ + /* we set the last argument of T1_FIELD_XXX to 0 */ + static const + T1_FieldRec t42_keywords[] = + { + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontInfo +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + + T1_FIELD_STRING( "version", version, 0 ) + T1_FIELD_STRING( "Notice", notice, 0 ) + T1_FIELD_STRING( "FullName", full_name, 0 ) + T1_FIELD_STRING( "FamilyName", family_name, 0 ) + T1_FIELD_STRING( "Weight", weight, 0 ) + T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + + T1_FIELD_NUM ( "FSType", fs_type, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + + T1_FIELD_KEY ( "FontName", font_name, 0 ) + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) + +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + + T1_FIELD_BBOX( "FontBBox", xMin, 0 ) + + T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) + T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) + T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) + + T1_FIELD_ZERO + }; + + +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) + +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) + +#define T1_ToInt( p ) \ + (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToBytes( p, b, m, n, d ) \ + (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) + +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) + +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + + + /********************* Parsing Functions ******************/ + + FT_LOCAL_DEF( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error = FT_Err_Ok; + FT_Long size; + + + psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory ); + + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = NULL; + parser->in_memory = 0; + + /******************************************************************** + * + * Here a short summary of what is going on: + * + * When creating a new Type 42 parser, we try to locate and load + * the base dictionary, loading the whole font into memory. + * + * When `loading' the base dictionary, we only set up pointers + * in the case of a memory-based stream. Otherwise, we allocate + * and load the base dictionary in it. + * + * parser->in_memory is set if we have a memory stream. + */ + + if ( FT_STREAM_SEEK( 0L ) || + FT_FRAME_ENTER( 17 ) ) + goto Exit; + + if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) + { + FT_TRACE2(( " not a Type42 font\n" )); + error = FT_THROW( Unknown_File_Format ); + } + + FT_FRAME_EXIT(); + + if ( error || FT_STREAM_SEEK( 0 ) ) + goto Exit; + + size = (FT_Long)stream->size; + + /* now, try to load `size' bytes of the `base' dictionary we */ + /* found previously */ + + /* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; + + /* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { + /* read segment in memory */ + if ( FT_QALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + + parser->base_len = size; + } + + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + + return error; + } + + + FT_LOCAL_DEF( void ) + t42_parser_done( T42_Parser parser ) + { + FT_Memory memory = parser->root.memory; + + + /* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + + if ( parser->root.funcs.done ) + parser->root.funcs.done( &parser->root ); + } + + + static int + t42_is_space( FT_Byte c ) + { + return ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' || c == '\f' || + c == '\0' ); + } + + + static void + t42_parse_font_matrix( FT_Face face, /* T42_Face */ + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Matrix* matrix = &t42face->type1.font_matrix; + FT_Vector* offset = &t42face->type1.font_offset; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + + + result = T1_ToFixedArray( parser, 6, temp, 0 ); + + if ( result < 6 ) + { + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + temp_scale = FT_ABS( temp[3] ); + + if ( temp_scale == 0 ) + { + FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* atypical case */ + if ( temp_scale != 0x10000L ) + { + temp[0] = FT_DivFix( temp[0], temp_scale ); + temp[1] = FT_DivFix( temp[1], temp_scale ); + temp[2] = FT_DivFix( temp[2], temp_scale ); + temp[4] = FT_DivFix( temp[4], temp_scale ); + temp[5] = FT_DivFix( temp[5], temp_scale ); + temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; + } + + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + + if ( !FT_Matrix_Check( matrix ) ) + { + FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + + + static void + t42_parse_encoding( FT_Face face, + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + + PSAux_Service psaux = (PSAux_Service)t42face->psaux; + + + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + /* if we have a number or `[', the encoding is an array, */ + /* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &t42face->type1.encoding; + FT_Int count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; + + + /* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + + /* only composite fonts (which we don't support) */ + /* can have larger values */ + if ( count > 256 ) + { + FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" )); + parser->root.error = FT_THROW( Invalid_File_Format ); + return; + } + + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; + + /* PostScript happily allows overwriting of encoding arrays */ + if ( encode->char_index ) + { + FT_FREE( encode->char_index ); + FT_FREE( encode->char_name ); + T1_Release_Table( char_table ); + } + + /* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_QNEW_ARRAY( encode->char_index, count ) || + FT_QNEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } + + /* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + (void)T1_Add_Table( char_table, n, ".notdef", 8 ); + + /* Now we need to read records of the form */ + /* */ + /* ... charcode /charname ... */ + /* */ + /* for each entry in our table. */ + /* */ + /* We simply look for a number followed by an immediate */ + /* name. Note that this ignores correctly the sequence */ + /* that is often seen in type42 fonts: */ + /* */ + /* 0 1 255 { 1 index exch /.notdef put } for dup */ + /* */ + /* used to clean the encoding array before anything else. */ + /* */ + /* Alternatively, if the array is directly given as */ + /* */ + /* /Encoding [ ... ] */ + /* */ + /* we only read immediates. */ + + n = 0; + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + + /* we stop when we encounter `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + t42_is_space( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } + + /* check whether we have found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + + + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + + /* protect against invalid charcode */ + if ( cur == parser->root.cursor ) + { + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + + cur = parser->root.cursor; + + if ( cur + 2 < limit && *cur == '/' && n < count ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + return; + if ( parser->root.error ) + return; + + len = (FT_UInt)( parser->root.cursor - cur ); + + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + + n++; + } + else if ( only_immediates ) + { + /* Since the current position is not updated for */ + /* immediates-only mode we would get an infinite loop if */ + /* we don't do anything here. */ + /* */ + /* This encoding array is not valid according to the */ + /* type42 specification (it might be an encoding for a CID */ + /* type42 font, however), so we conclude that this font is */ + /* NOT a type42 font. */ + parser->root.error = FT_THROW( Unknown_File_Format ); + return; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + + T1_Skip_Spaces( parser ); + } + + t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } + + /* Otherwise, we should have either `StandardEncoding', */ + /* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + + else + parser->root.error = FT_ERR( Ignore ); + } + } + + + typedef enum T42_Load_Status_ + { + BEFORE_START, + BEFORE_TABLE_DIR, + OTHER_TABLES + + } T42_Load_Status; + + + static void + t42_parse_sfnts( FT_Face face, + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Error error; + FT_Int num_tables = 0; + FT_Long ttf_count; + FT_Long ttf_reserved; + + FT_ULong n, string_size, old_string_size, real_size; + FT_Byte* string_buf = NULL; + FT_Bool allocated = 0; + + T42_Load_Status status; + + /** There should only be one sfnts array, but free any previous. */ + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; + + /* The format is */ + /* */ + /* /sfnts [ ... ] def */ + /* */ + /* or */ + /* */ + /* /sfnts [ */ + /* RD */ + /* RD */ + /* ... */ + /* ] def */ + /* */ + /* with exactly one space after the `RD' token. */ + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) + { + FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + T1_Skip_Spaces( parser ); + status = BEFORE_START; + string_size = 0; + old_string_size = 0; + ttf_count = 0; + ttf_reserved = 12; + if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) ) + goto Fail; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( "t42_parse_sfnts:\n" )); + + while ( parser->root.cursor < limit ) + { + FT_ULong size; + + + cur = parser->root.cursor; + + if ( *cur == ']' ) + { + parser->root.cursor++; + t42face->ttf_size = ttf_count; + goto Exit; + } + + else if ( *cur == '<' ) + { + if ( string_buf && !allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + /* don't include delimiters */ + string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( FT_QREALLOC( string_buf, old_string_size, string_size ) ) + goto Fail; + + allocated = 1; + + parser->root.cursor = cur; + (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); + old_string_size = string_size; + string_size = real_size; + } + + else if ( ft_isdigit( *cur ) ) + { + FT_Long tmp; + + + if ( allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + tmp = T1_ToInt( parser ); + if ( tmp < 0 ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + else + string_size = (FT_ULong)tmp; + + T1_Skip_PS_Token( parser ); /* `RD' */ + if ( parser->root.error ) + return; + + string_buf = parser->root.cursor + 1; /* one space after `RD' */ + + if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size ) + { + FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + else + parser->root.cursor += string_size + 1; + } + + if ( !string_buf ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* A string can have a trailing zero (odd) byte for padding. */ + /* Ignore it. */ + if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) + string_size--; + + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + FT_TRACE2(( " PS string size %5lu bytes, offset 0x%08lx (%lu)\n", + string_size, ttf_count, ttf_count )); + + /* The whole TTF is now loaded into `string_buf'. We are */ + /* checking its contents while copying it to `ttf_data'. */ + + size = (FT_ULong)( limit - parser->root.cursor ); + + for ( n = 0; n < string_size; n++ ) + { + switch ( status ) + { + case BEFORE_START: + /* load offset table, 12 bytes */ + if ( ttf_count < 12 ) + { + t42face->ttf_data[ttf_count++] = string_buf[n]; + continue; + } + else + { + FT_Long ttf_reserved_prev = ttf_reserved; + + + num_tables = 16 * t42face->ttf_data[4] + t42face->ttf_data[5]; + status = BEFORE_TABLE_DIR; + ttf_reserved = 12 + 16 * num_tables; + + FT_TRACE2(( " SFNT directory contains %d tables\n", + num_tables )); + + if ( (FT_Long)size < ttf_reserved ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) + goto Fail; + } + FALL_THROUGH; + + case BEFORE_TABLE_DIR: + /* the offset table is read; read the table directory */ + if ( ttf_count < ttf_reserved ) + { + t42face->ttf_data[ttf_count++] = string_buf[n]; + continue; + } + else + { + int i; + FT_ULong len; + FT_Long ttf_reserved_prev = ttf_reserved; + + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " table length\n" )); + FT_TRACE2(( " ------------------------------\n" )); + + for ( i = 0; i < num_tables; i++ ) + { + FT_Byte* p = t42face->ttf_data + 12 + 16 * i + 12; + + + len = FT_PEEK_ULONG( p ); + FT_TRACE2(( " %4i 0x%08lx (%lu)\n", i, len, len )); + + if ( len > size || + ttf_reserved > (FT_Long)( size - len ) ) + { + FT_ERROR(( "t42_parse_sfnts:" + " invalid data in sfnts array\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* Pad to a 4-byte boundary length */ + ttf_reserved += (FT_Long)( ( len + 3 ) & ~3U ); + } + ttf_reserved += 1; + + status = OTHER_TABLES; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " allocating %ld bytes\n", ttf_reserved )); + FT_TRACE2(( "\n" )); + + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) + goto Fail; + } + FALL_THROUGH; + + case OTHER_TABLES: + /* all other tables are just copied */ + if ( ttf_count >= ttf_reserved ) + { + FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + t42face->ttf_data[ttf_count++] = string_buf[n]; + } + } + + T1_Skip_Spaces( parser ); + } + + /* if control reaches this point, the format was not valid */ + error = FT_THROW( Invalid_File_Format ); + + Fail: + parser->root.error = error; + + Exit: + if ( parser->root.error ) + { + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; + } + if ( allocated ) + FT_FREE( string_buf ); + } + + + static void + t42_parse_charstrings( FT_Face face, /* T42_Face */ + void* loader_ ) + { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)t42face->psaux; + + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Int n; + FT_Int notdef_index = 0; + FT_Byte notdef_found = 0; + + + T1_Skip_Spaces( parser ); + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( ft_isdigit( *parser->root.cursor ) ) + { + loader->num_glyphs = T1_ToInt( parser ); + if ( parser->root.error ) + return; + if ( loader->num_glyphs < 0 ) + { + FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we certainly need more than 4 bytes per glyph */ + if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) + { + FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" + " (from %d to %zu)\n", + loader->num_glyphs, + ( limit - parser->root.cursor ) >> 2 )); + loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; + } + + } + else if ( *parser->root.cursor == '<' ) + { + /* We have `<< ... >>'. Count the number of `/' in the dictionary */ + /* to get its size. */ + FT_Int count = 0; + + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + + while ( parser->root.cursor < limit ) + { + if ( *parser->root.cursor == '/' ) + count++; + else if ( *parser->root.cursor == '>' ) + { + loader->num_glyphs = count; + parser->root.cursor = cur; /* rewind */ + break; + } + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + } + } + else + { + FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* initialize tables */ + + /* contrary to Type1, we disallow multiple CharStrings arrays */ + if ( swap_table->init ) + { + FT_ERROR(( "t42_parse_charstrings:" + " only one CharStrings array allowed\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + error = psaux->ps_table_funcs->init( code_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( name_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + /* Initialize table for swapping index notdef_index and */ + /* index 0 names and codes (if necessary). */ + + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + + n = 0; + + for (;;) + { + /* We support two formats. */ + /* */ + /* `/glyphname' + index [+ `def'] */ + /* `(glyphname)' [+ `cvn'] + index [+ `def'] */ + /* */ + /* The latter format gets created by the */ + /* LilyPond typesetting program. */ + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* We stop when we find an `end' keyword or '>' */ + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' && + t42_is_space( cur[3] ) ) + break; + if ( *cur == '>' ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + if ( parser->root.error ) + return; + + if ( *cur == '/' || *cur == '(' ) + { + FT_UInt len; + FT_Bool have_literal = FT_BOOL( *cur == '(' ); + + + if ( cur + ( have_literal ? 3 : 2 ) >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + cur++; /* skip `/' */ + len = (FT_UInt)( parser->root.cursor - cur ); + if ( have_literal ) + len--; + + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + /* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)( name_table->elements[n] ) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + + T1_Skip_Spaces( parser ); + + if ( have_literal ) + T1_Skip_PS_Token( parser ); + + cur = parser->root.cursor; + + (void)T1_ToInt( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + len = (FT_UInt)( parser->root.cursor - cur ); + + error = T1_Add_Table( code_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + code_table->elements[n][len] = '\0'; + + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + + loader->num_glyphs = n; + + if ( !notdef_found ) + { + FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* if /.notdef does not occupy index 0, do our magic. */ + if ( ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) + { + /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ + /* name and code entries to swap_table. Then place notdef_index */ + /* name and code entries into swap_table. Then swap name and code */ + /* entries at indices notdef_index and 0 using values stored in */ + /* swap_table. */ + + /* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + + /* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + /* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + + } + + return; + + Fail: + parser->root.error = error; + } + + + static FT_Error + t42_load_keyword( T42_Face face, + T42_Loader loader, + T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects = 0; + + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now the keyword is either a simple field or a table of fields; */ + /* we are now going to take care of it */ + + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + break; + + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + break; + + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + break; + + default: + dummy_object = &face->type1; + } + + objects = &dummy_object; + + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T42_Parser parser = &loader->parser; + FT_Byte* limit; + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = FT_Err_Ok; + + limit = parser->root.limit; + + T1_Skip_Spaces( parser ); + + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + + + cur = parser->root.cursor; + + /* look for `FontDirectory' which causes problems for some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; + + + /* skip the `FontDirectory' keyword */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = cur2 = parser->root.cursor; + + /* look up the `known' keyword */ + while ( cur < limit ) + { + if ( *cur == 'k' && cur + 5 < limit && + ft_strncmp( (char*)cur, "known", 5 ) == 0 ) + break; + + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + + if ( cur < limit ) + { + T1_TokenRec token; + + + /* skip the `known' keyword and the token following it */ + T1_Skip_PS_Token( parser ); + T1_ToToken( parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; + } + parser->root.cursor = cur2; + } + + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_UInt len; + + + cur++; + + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + + len = (FT_UInt)( parser->root.cursor - cur ); + + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + T1_Field keyword = (T1_Field)t42_keywords; + + + /* now compare the immediate name to the keyword table */ + while ( keyword->len ) + { + FT_Byte* name = (FT_Byte*)keyword->ident; + + + if ( !name ) + continue; + + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) + { + /* we found it -- run the parsing callback! */ + parser->root.error = t42_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + + keyword++; + } + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + } + + T1_Skip_Spaces( parser ); + } + + Exit: + return parser->root.error; + } + + + FT_LOCAL_DEF( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ) + { + FT_UNUSED( face ); + + FT_ZERO( loader ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + } + + + FT_LOCAL_DEF( void ) + t42_loader_done( T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + + /* finalize parser */ + t42_parser_done( parser ); + } + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42parse.h b/Dependencies/freetype/freetype/src/type42/t42parse.h new file mode 100644 index 00000000..e9778616 --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42parse.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * t42parse.h + * + * Type 42 font parser (specification). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42PARSE_H_ +#define T42PARSE_H_ + + +#include "t42objs.h" +#include + + +FT_BEGIN_HEADER + + typedef struct T42_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_Long base_len; + + FT_Bool in_memory; + + } T42_ParserRec, *T42_Parser; + + + typedef struct T42_Loader_ + { + T42_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */ + + } T42_LoaderRec, *T42_Loader; + + + FT_LOCAL( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + t42_parser_done( T42_Parser parser ); + + + FT_LOCAL( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ); + + + FT_LOCAL( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ); + + FT_LOCAL( void ) + t42_loader_done( T42_Loader loader ); + + + /* */ + +FT_END_HEADER + + +#endif /* T42PARSE_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/t42types.h b/Dependencies/freetype/freetype/src/type42/t42types.h new file mode 100644 index 00000000..550cc07c --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/t42types.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * + * t42types.h + * + * Type 42 font data types (specification only). + * + * Copyright (C) 2002-2024 by + * Roberto Alameda. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef T42TYPES_H_ +#define T42TYPES_H_ + + +#include +#include +#include +#include + + +FT_BEGIN_HEADER + + + typedef struct T42_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; +#if 0 + const void* afm_data; +#endif + FT_Byte* ttf_data; + FT_Long ttf_size; + FT_Face ttf_face; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_UnicodesRec unicode_map; + + } T42_FaceRec, *T42_Face; + + +FT_END_HEADER + +#endif /* T42TYPES_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/type42/type42.c b/Dependencies/freetype/freetype/src/type42/type42.c new file mode 100644 index 00000000..a9444f0f --- /dev/null +++ b/Dependencies/freetype/freetype/src/type42/type42.c @@ -0,0 +1,26 @@ +/**************************************************************************** + * + * type42.c + * + * FreeType Type 42 driver component. + * + * Copyright (C) 2002-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include "t42drivr.c" +#include "t42objs.c" +#include "t42parse.c" + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/winfonts/fnterrs.h b/Dependencies/freetype/freetype/src/winfonts/fnterrs.h new file mode 100644 index 00000000..7ca65923 --- /dev/null +++ b/Dependencies/freetype/freetype/src/winfonts/fnterrs.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * fnterrs.h + * + * Win FNT/FON error codes (specification only). + * + * Copyright (C) 2001-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * This file is used to define the Windows FNT/FON error enumeration + * constants. + * + */ + +#ifndef FNTERRS_H_ +#define FNTERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX FNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_Winfonts + +#include + +#endif /* FNTERRS_H_ */ + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/winfonts/winfnt.c b/Dependencies/freetype/freetype/src/winfonts/winfnt.c new file mode 100644 index 00000000..74a06416 --- /dev/null +++ b/Dependencies/freetype/freetype/src/winfonts/winfnt.c @@ -0,0 +1,1219 @@ +/**************************************************************************** + * + * winfnt.c + * + * FreeType font driver for Windows FNT/FON files + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright 2003 Huw D M Davies for Codeweavers + * Copyright 2007 Dmitry Timoshkov for Codeweavers + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include +#include +#include +#include +#include + +#include "winfnt.h" +#include "fnterrs.h" +#include +#include + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT winfnt + + + static const FT_Frame_Field winmz_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinMZ_HeaderRec + + FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 29 * 2 ), + FT_FRAME_ULONG_LE ( lfanew ), + FT_FRAME_END + }; + + static const FT_Frame_Field winne_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinNE_HeaderRec + + FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE ( resource_tab_offset ), + FT_FRAME_USHORT_LE ( rname_tab_offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_HeaderRec + + FT_FRAME_START( 248 ), + FT_FRAME_ULONG_LE ( magic ), /* PE00 */ + FT_FRAME_USHORT_LE ( machine ), /* 0x014C - i386 */ + FT_FRAME_USHORT_LE ( number_of_sections ), + FT_FRAME_SKIP_BYTES( 12 ), + FT_FRAME_USHORT_LE ( size_of_optional_header ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_USHORT_LE ( magic32 ), /* 0x10B */ + FT_FRAME_SKIP_BYTES( 110 ), + FT_FRAME_ULONG_LE ( rsrc_virtual_address ), + FT_FRAME_ULONG_LE ( rsrc_size ), + FT_FRAME_SKIP_BYTES( 104 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe32_section_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_SectionRec + + FT_FRAME_START( 40 ), + FT_FRAME_BYTES ( name, 8 ), + FT_FRAME_SKIP_BYTES( 4 ), + FT_FRAME_ULONG_LE ( virtual_address ), + FT_FRAME_ULONG_LE ( size_of_raw_data ), + FT_FRAME_ULONG_LE ( pointer_to_raw_data ), + FT_FRAME_SKIP_BYTES( 16 ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE ( characteristics ), + FT_FRAME_ULONG_LE ( time_date_stamp ), + FT_FRAME_USHORT_LE( major_version ), + FT_FRAME_USHORT_LE( minor_version ), + FT_FRAME_USHORT_LE( number_of_named_entries ), + FT_FRAME_USHORT_LE( number_of_id_entries ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirEntryRec + + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( name ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + + static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDataEntryRec + + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( offset_to_data ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( code_page ), + FT_FRAME_ULONG_LE( reserved ), + FT_FRAME_END + }; + + static const FT_Frame_Field winfnt_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_WinFNT_HeaderRec + + FT_FRAME_START( 148 ), + FT_FRAME_USHORT_LE( version ), + FT_FRAME_ULONG_LE ( file_size ), + FT_FRAME_BYTES ( copyright, 60 ), + FT_FRAME_USHORT_LE( file_type ), + FT_FRAME_USHORT_LE( nominal_point_size ), + FT_FRAME_USHORT_LE( vertical_resolution ), + FT_FRAME_USHORT_LE( horizontal_resolution ), + FT_FRAME_USHORT_LE( ascent ), + FT_FRAME_USHORT_LE( internal_leading ), + FT_FRAME_USHORT_LE( external_leading ), + FT_FRAME_BYTE ( italic ), + FT_FRAME_BYTE ( underline ), + FT_FRAME_BYTE ( strike_out ), + FT_FRAME_USHORT_LE( weight ), + FT_FRAME_BYTE ( charset ), + FT_FRAME_USHORT_LE( pixel_width ), + FT_FRAME_USHORT_LE( pixel_height ), + FT_FRAME_BYTE ( pitch_and_family ), + FT_FRAME_USHORT_LE( avg_width ), + FT_FRAME_USHORT_LE( max_width ), + FT_FRAME_BYTE ( first_char ), + FT_FRAME_BYTE ( last_char ), + FT_FRAME_BYTE ( default_char ), + FT_FRAME_BYTE ( break_char ), + FT_FRAME_USHORT_LE( bytes_per_row ), + FT_FRAME_ULONG_LE ( device_offset ), + FT_FRAME_ULONG_LE ( face_name_offset ), + FT_FRAME_ULONG_LE ( bits_pointer ), + FT_FRAME_ULONG_LE ( bits_offset ), + FT_FRAME_BYTE ( reserved ), + FT_FRAME_ULONG_LE ( flags ), + FT_FRAME_USHORT_LE( A_space ), + FT_FRAME_USHORT_LE( B_space ), + FT_FRAME_USHORT_LE( C_space ), + FT_FRAME_ULONG_LE ( color_table_offset ), + FT_FRAME_BYTES ( reserved1, 16 ), + FT_FRAME_END + }; + + + static void + fnt_font_done( FNT_Face face ) + { + FT_Memory memory = FT_FACE( face )->memory; + FT_Stream stream = FT_FACE( face )->stream; + FNT_Font font = face->font; + + + if ( !font ) + return; + + if ( font->fnt_frame ) + FT_FRAME_RELEASE( font->fnt_frame ); + FT_FREE( font->family_name ); + + FT_FREE( font ); + face->font = NULL; + } + + + static FT_Error + fnt_font_load( FNT_Font font, + FT_Stream stream ) + { + FT_Error error; + FT_WinFNT_Header header = &font->header; + FT_Bool new_format; + FT_UInt size; + + + /* first of all, read the FNT header */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + new_format = FT_BOOL( font->header.version == 0x300 ); + size = new_format ? 148 : 118; + + if ( header->file_size < size ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* Version 2 doesn't have these fields */ + if ( header->version == 0x200 ) + { + header->flags = 0; + header->A_space = 0; + header->B_space = 0; + header->C_space = 0; + + header->color_table_offset = 0; + } + + if ( header->file_type & 1 ) + { + FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + /* this is a FNT file/table; extract its frame */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) + goto Exit; + + Exit: + return error; + } + + + static FT_Error + fnt_face_get_dll_font( FNT_Face face, + FT_Int face_instance_index ) + { + FT_Error error; + FT_Stream stream = FT_FACE( face )->stream; + FT_Memory memory = FT_FACE( face )->memory; + WinMZ_HeaderRec mz_header; + FT_Long face_index; + + + face->font = NULL; + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* does it begin with an MZ header? */ + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) + { + error = FT_ERR( Unknown_File_Format ); + goto Exit; + } + + error = FT_ERR( Unknown_File_Format ); + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { + /* yes, now look for an NE header in the file */ + WinNE_HeaderRec ne_header; + + + FT_TRACE2(( "MZ signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) + goto Exit; + + error = FT_ERR( Unknown_File_Format ); + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { + /* good, now look into the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + + ne_header.resource_tab_offset; + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + + + FT_TRACE2(( "NE signature found\n" )); + + if ( FT_STREAM_SEEK( res_offset ) || + FT_FRAME_ENTER( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + + size_shift = FT_GET_USHORT_LE(); + + /* Microsoft's specification of the executable-file header format */ + /* for `New Executable' (NE) doesn't give a limit for the */ + /* alignment shift count; however, in 1985, the year of the */ + /* specification release, only 32bit values were supported, thus */ + /* anything larger than 16 doesn't make sense in general, given */ + /* that file offsets are 16bit values, shifted by the alignment */ + /* shift count */ + if ( size_shift > 16 ) + { + FT_TRACE2(( "invalid alignment shift count for resource data\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit1; + } + + + for (;;) + { + FT_UShort type_id, count; + + + type_id = FT_GET_USHORT_LE(); + if ( !type_id ) + break; + + count = FT_GET_USHORT_LE(); + + FT_TRACE2(( type_id == 0x8007U ? "RT_FONTDIR count %hu\n" : + type_id == 0x8008U ? "RT_FONT count %hu\n" : "", + count )); + + if ( type_id == 0x8008U ) + { + font_count = count; + font_offset = FT_STREAM_POS() + 4 - + (FT_ULong)( stream->limit - stream->cursor ); + break; + } + + stream->cursor += 4 + count * 12; + } + + FT_FRAME_EXIT(); + + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "this file doesn't contain any FNT resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* loading `winfnt_header_fields' needs at least 118 bytes; */ + /* use this as a rough measure to check the expected font size */ + if ( font_count * 118UL > stream->size ) + { + FT_TRACE2(( "invalid number of faces\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + face->root.num_faces = font_count; + + if ( face_instance_index < 0 ) + goto Exit; + + if ( face_index >= font_count ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_NEW( face->font ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font_offset + (FT_ULong)face_index * 12 ) || + FT_FRAME_ENTER( 12 ) ) + goto Fail; + + face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + + stream->cursor += 8; + + FT_FRAME_EXIT(); + + error = fnt_font_load( face->font, stream ); + } + else if ( ne_header.magic == WINFNT_PE_MAGIC ) + { + WinPE32_HeaderRec pe32_header; + WinPE32_SectionRec pe32_section; + WinPE_RsrcDirRec root_dir, name_dir, lang_dir; + WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; + WinPE_RsrcDataEntryRec data_entry; + + FT_ULong root_dir_offset, name_dir_offset, lang_dir_offset; + FT_UShort i, j, k; + + + FT_TRACE2(( "PE signature found\n" )); + + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) + goto Exit; + + FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " + "size_of_optional_header %02x\n", + pe32_header.magic, pe32_header.machine, + pe32_header.number_of_sections, + pe32_header.size_of_optional_header )); + FT_TRACE2(( "magic32 %02x, rsrc_virtual_address %04lx, " + "rsrc_size %04lx\n", + pe32_header.magic32, pe32_header.rsrc_virtual_address, + pe32_header.rsrc_size )); + + if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || + pe32_header.machine != 0x014C /* i386 */ || + pe32_header.size_of_optional_header != 0xE0 /* FIXME */ || + pe32_header.magic32 != 0x10B ) + { + FT_TRACE2(( "this file has an invalid PE header\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + face->root.num_faces = 0; + + for ( i = 0; i < pe32_header.number_of_sections; i++ ) + { + if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, + &pe32_section ) ) + goto Exit; + + FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", + pe32_section.name, pe32_section.virtual_address, + pe32_section.size_of_raw_data, + pe32_section.pointer_to_raw_data )); + + if ( pe32_header.rsrc_virtual_address == + pe32_section.virtual_address ) + goto Found_rsrc_section; + } + + FT_TRACE2(( "this file doesn't contain any resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + + Found_rsrc_section: + FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) + goto Exit; + + root_dir_offset = pe32_section.pointer_to_raw_data; + + for ( i = 0; i < root_dir.number_of_named_entries + + root_dir.number_of_id_entries; i++ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry1 ) ) + goto Exit; + + if ( !( dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dir_entry1.offset &= ~0x80000000UL; + + name_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry1.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry1.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) + goto Exit; + + for ( j = 0; j < name_dir.number_of_named_entries + + name_dir.number_of_id_entries; j++ ) + { + if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry2 ) ) + goto Exit; + + if ( !( dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + dir_entry2.offset &= ~0x80000000UL; + + lang_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry2.offset; + + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry2.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) + goto Exit; + + for ( k = 0; k < lang_dir.number_of_named_entries + + lang_dir.number_of_id_entries; k++ ) + { + if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry3 ) ) + goto Exit; + + if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( dir_entry1.name == 8 /* RT_FONT */ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, + &data_entry ) ) + goto Exit; + + FT_TRACE2(( "found font #%lu, offset %04lx, " + "size %04lx, cp %lu\n", + dir_entry2.name, + pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address, + data_entry.size, data_entry.code_page )); + + if ( face_index == face->root.num_faces ) + { + if ( FT_NEW( face->font ) ) + goto Exit; + + face->font->offset = pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address; + face->font->fnt_size = data_entry.size; + + error = fnt_font_load( face->font, stream ); + if ( error ) + { + FT_TRACE2(( "font #%lu load error 0x%x\n", + dir_entry2.name, error )); + goto Fail; + } + else + FT_TRACE2(( "font #%lu successfully loaded\n", + dir_entry2.name )); + } + + face->root.num_faces++; + } + } + } + } + } + + if ( !face->root.num_faces ) + { + FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( face_index >= face->root.num_faces ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + Fail: + if ( error ) + fnt_font_done( face ); + + Exit: + return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; + } + + + typedef struct FNT_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt32 first; + FT_UInt32 count; + + } FNT_CMapRec, *FNT_CMap; + + + static FT_Error + fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */ + FT_Pointer pointer ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); + FNT_Font font = face->font; + + FT_UNUSED( pointer ); + + + fntcmap->first = (FT_UInt32)font->header.first_char; + fntcmap->count = (FT_UInt32)( font->header.last_char - + fntcmap->first + 1 ); + + return 0; + } + + + static FT_UInt + fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */ + FT_UInt32 char_code ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; + + + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) + /* we artificially increase the glyph index; */ + /* FNT_Load_Glyph reverts to the right one */ + gindex = (FT_UInt)( char_code + 1 ); + return gindex; + } + + + static FT_UInt + fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */ + FT_UInt32 *pchar_code ) + { + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + + + if ( char_code <= fntcmap->first ) + { + result = fntcmap->first; + gindex = 1; + } + else + { + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) + { + result = fntcmap->first + char_code; + gindex = (FT_UInt)( char_code + 1 ); + } + } + + *pchar_code = result; + return gindex; + } + + + static const FT_CMap_ClassRec fnt_cmap_class_rec = + { + sizeof ( FNT_CMapRec ), + + (FT_CMap_InitFunc) fnt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)fnt_cmap_char_index, + (FT_CMap_CharNextFunc) fnt_cmap_char_next, + + NULL, NULL, NULL, NULL, NULL + }; + + static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; + + + static void + FNT_Face_Done( FT_Face fntface ) /* FNT_Face */ + { + FNT_Face face = (FNT_Face)fntface; + FT_Memory memory; + + + if ( !face ) + return; + + memory = FT_FACE_MEMORY( face ); + + fnt_font_done( face ); + + FT_FREE( fntface->available_sizes ); + fntface->num_fixed_sizes = 0; + } + + + static FT_Error + FNT_Face_Init( FT_Stream stream, + FT_Face fntface, /* FNT_Face */ + FT_Int face_instance_index, + FT_Int num_params, + FT_Parameter* params ) + { + FNT_Face face = (FNT_Face)fntface; + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Int face_index; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + + + FT_TRACE2(( "Windows FNT driver\n" )); + + face_index = FT_ABS( face_instance_index ) & 0xFFFF; + + /* try to load font from a DLL */ + error = fnt_face_get_dll_font( face, face_instance_index ); + if ( !error && face_instance_index < 0 ) + goto Exit; + + if ( FT_ERR_EQ( error, Unknown_File_Format ) ) + { + /* this didn't work; try to load a single FNT font */ + FNT_Font font; + + if ( FT_NEW( face->font ) ) + goto Exit; + + fntface->num_faces = 1; + + font = face->font; + font->offset = 0; + font->fnt_size = stream->size; + + error = fnt_font_load( font, stream ); + + if ( !error ) + { + if ( face_instance_index < 0 ) + goto Exit; + + if ( face_index > 0 ) + error = FT_THROW( Invalid_Argument ); + } + } + + if ( error ) + goto Fail; + + /* sanity check */ + if ( !face->font->header.pixel_height ) + { + FT_TRACE2(( "invalid pixel height\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* we now need to fill the root FT_Face fields */ + /* with relevant information */ + { + FT_Face root = FT_FACE( face ); + FNT_Font font = face->font; + FT_ULong family_size; + + + root->face_index = face_index; + + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + + if ( font->header.avg_width == font->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + if ( font->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( font->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + /* set up the `fixed_sizes' array */ + if ( FT_QNEW( root->available_sizes ) ) + goto Fail; + + root->num_fixed_sizes = 1; + + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_UShort x_res, y_res; + + + bsize->width = (FT_Short)font->header.avg_width; + bsize->height = (FT_Short)( font->header.pixel_height + + font->header.external_leading ); + bsize->size = font->header.nominal_point_size << 6; + + x_res = font->header.horizontal_resolution; + if ( !x_res ) + x_res = 72; + + y_res = font->header.vertical_resolution; + if ( !y_res ) + y_res = 72; + + bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); + bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); + + /* + * this reads: + * + * the nominal height is larger than the bbox's height + * + * => nominal_point_size contains incorrect value; + * use pixel_height as the nominal height + */ + if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) + { + FT_TRACE2(( "use pixel_height as the nominal height\n" )); + + bsize->y_ppem = font->header.pixel_height << 6; + bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); + } + + bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); + bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); + } + + { + FT_CharMapRec charmap; + + + charmap.encoding = FT_ENCODING_NONE; + /* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + charmap.face = root; + + if ( font->header.charset == FT_WinFNT_ID_MAC ) + { + charmap.encoding = FT_ENCODING_APPLE_ROMAN; + charmap.platform_id = TT_PLATFORM_MACINTOSH; +/* charmap.encoding_id = TT_MAC_ID_ROMAN; */ + } + + error = FT_CMap_New( fnt_cmap_class, + NULL, + &charmap, + NULL ); + if ( error ) + goto Fail; + } + + /* set up remaining flags */ + + if ( font->header.last_char < font->header.first_char ) + { + FT_TRACE2(( "invalid number of glyphs\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + + /* reserve one slot for the .notdef glyph at index 0 */ + root->num_glyphs = font->header.last_char - + font->header.first_char + 1 + 1; + + if ( font->header.face_name_offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid family name offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } + family_size = font->header.file_size - font->header.face_name_offset; + /* Some broken fonts don't delimit the face name with a final */ + /* null byte -- the frame is erroneously one byte too small. */ + /* We thus allocate one more byte, setting it explicitly to */ + /* zero. */ + if ( FT_QALLOC( font->family_name, family_size + 1 ) ) + goto Fail; + + FT_MEM_COPY( font->family_name, + font->fnt_frame + font->header.face_name_offset, + family_size ); + + font->family_name[family_size] = '\0'; + + /* shrink it to the actual length */ + if ( FT_QREALLOC( font->family_name, + family_size + 1, + ft_strlen( font->family_name ) + 1 ) ) + goto Fail; + + root->family_name = font->family_name; + root->style_name = (char *)"Regular"; + + if ( root->style_flags & FT_STYLE_FLAG_BOLD ) + { + if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Bold Italic"; + else + root->style_name = (char *)"Bold"; + } + else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Italic"; + } + goto Exit; + + Fail: + FNT_Face_Done( fntface ); + + Exit: + return error; + } + + + static FT_Error + FNT_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + + FT_UNUSED( strike_index ); + + + FT_Select_Metrics( size->face, 0 ); + + size->metrics.ascender = header->ascent * 64; + size->metrics.descender = -( header->pixel_height - + header->ascent ) * 64; + size->metrics.max_advance = header->max_width * 64; + + return FT_Err_Ok; + } + + + static FT_Error + FNT_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FT_ERR( Invalid_Pixel_Size ); + FT_Long height; + + + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FT_Err_Ok; + break; + + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == header->pixel_height ) + error = FT_Err_Ok; + break; + + default: + error = FT_THROW( Unimplemented_Feature ); + break; + } + + if ( error ) + return error; + else + return FNT_Size_Select( size, 0 ); + } + + + static FT_Error + FNT_Load_Glyph( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FNT_Face face = (FNT_Face)size->face; + FNT_Font font; + FT_Error error = FT_Err_Ok; + FT_Byte* p; + FT_UInt len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + + + if ( !face ) + { + error = FT_THROW( Invalid_Face_Handle ); + goto Exit; + } + + font = face->font; + + if ( !font || + glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_TRACE1(( "FNT_Load_Glyph: glyph index %d\n", glyph_index )); + + if ( glyph_index > 0 ) + glyph_index--; /* revert to real index */ + else + glyph_index = font->header.default_char; /* the `.notdef' glyph */ + + new_format = FT_BOOL( font->header.version == 0x300 ); + len = new_format ? 6 : 4; + + /* get glyph width and offset */ + offset = ( new_format ? 148 : 118 ) + len * glyph_index; + + if ( offset >= font->header.file_size - 2 - ( new_format ? 4 : 2 ) ) + { + FT_TRACE2(( "invalid FNT offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + p = font->fnt_frame + offset; + + bitmap->width = FT_NEXT_USHORT_LE( p ); + + /* jump to glyph entry */ + if ( new_format ) + offset = FT_NEXT_ULONG_LE( p ); + else + offset = FT_NEXT_USHORT_LE( p ); + + if ( offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid FNT offset\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = FT_GLYPH_FORMAT_BITMAP; + + /* now set up metrics */ + slot->metrics.width = (FT_Pos)( bitmap->width << 6 ); + slot->metrics.height = (FT_Pos)( bitmap->rows << 6 ); + slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 ); + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + + ft_synthesize_vertical_metrics( &slot->metrics, + (FT_Pos)( bitmap->rows << 6 ) ); + + if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) + goto Exit; + + /* jump to glyph data */ + p = font->fnt_frame + /* font->header.bits_offset */ + offset; + + /* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_UInt pitch = ( bitmap->width + 7 ) >> 3; + FT_Byte* column; + FT_Byte* write; + + + bitmap->pitch = (int)pitch; + if ( !pitch || + offset + pitch * bitmap->rows > font->header.file_size ) + { + FT_TRACE2(( "invalid bitmap width\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* note: since glyphs are stored in columns and not in rows we */ + /* can't use ft_glyphslot_set_bitmap */ + if ( FT_QALLOC_MULT( bitmap->buffer, bitmap->rows, pitch ) ) + goto Exit; + + column = (FT_Byte*)bitmap->buffer; + + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + + + for ( write = column; p < limit; p++, write += bitmap->pitch ) + *write = *p; + } + + slot->internal->flags = FT_GLYPH_OWN_BITMAP; + } + + Exit: + return error; + } + + + static FT_Error + winfnt_get_header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ) + { + FNT_Font font = ((FNT_Face)face)->font; + + + *aheader = font->header; + + return 0; + } + + + static const FT_Service_WinFntRec winfnt_service_rec = + { + winfnt_get_header /* get_header */ + }; + + /* + * SERVICE LIST + * + */ + + static const FT_ServiceDescRec winfnt_services[] = + { + { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_WINFNT }, + { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, + { NULL, NULL } + }; + + + static FT_Module_Interface + winfnt_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( winfnt_services, service_id ); + } + + + + + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec winfnt_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + + "winfonts", + 0x10000L, + 0x20000L, + + NULL, /* module-specific interface */ + + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + winfnt_get_service /* FT_Module_Requester get_interface */ + }, + + sizeof ( FNT_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + + FNT_Face_Init, /* FT_Face_InitFunc init_face */ + FNT_Face_Done, /* FT_Face_DoneFunc done_face */ + NULL, /* FT_Size_InitFunc init_size */ + NULL, /* FT_Size_DoneFunc done_size */ + NULL, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ + + FNT_Load_Glyph, /* FT_Slot_LoadFunc load_glyph */ + + NULL, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + NULL, /* FT_Face_GetAdvancesFunc get_advances */ + + FNT_Size_Request, /* FT_Size_RequestFunc request_size */ + FNT_Size_Select /* FT_Size_SelectFunc select_size */ + }; + + +/* END */ diff --git a/Dependencies/freetype/freetype/src/winfonts/winfnt.h b/Dependencies/freetype/freetype/src/winfonts/winfnt.h new file mode 100644 index 00000000..78137496 --- /dev/null +++ b/Dependencies/freetype/freetype/src/winfonts/winfnt.h @@ -0,0 +1,164 @@ +/**************************************************************************** + * + * winfnt.h + * + * FreeType font driver for Windows FNT/FON files + * + * Copyright (C) 1996-2024 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright 2007 Dmitry Timoshkov for Codeweavers + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef WINFNT_H_ +#define WINFNT_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + + typedef struct WinMZ_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort lfanew; + + } WinMZ_HeaderRec; + + + typedef struct WinNE_HeaderRec_ + { + FT_UShort magic; + /* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + + } WinNE_HeaderRec; + + + typedef struct WinPE32_HeaderRec_ + { + FT_ULong magic; + FT_UShort machine; + FT_UShort number_of_sections; + /* skipped content */ + FT_UShort size_of_optional_header; + /* skipped content */ + FT_UShort magic32; + /* skipped content */ + FT_ULong rsrc_virtual_address; + FT_ULong rsrc_size; + /* skipped content */ + + } WinPE32_HeaderRec; + + + typedef struct WinPE32_SectionRec_ + { + FT_Byte name[8]; + /* skipped content */ + FT_ULong virtual_address; + FT_ULong size_of_raw_data; + FT_ULong pointer_to_raw_data; + /* skipped content */ + + } WinPE32_SectionRec; + + + typedef struct WinPE_RsrcDirRec_ + { + FT_ULong characteristics; + FT_ULong time_date_stamp; + FT_UShort major_version; + FT_UShort minor_version; + FT_UShort number_of_named_entries; + FT_UShort number_of_id_entries; + + } WinPE_RsrcDirRec; + + + typedef struct WinPE_RsrcDirEntryRec_ + { + FT_ULong name; + FT_ULong offset; + + } WinPE_RsrcDirEntryRec; + + + typedef struct WinPE_RsrcDataEntryRec_ + { + FT_ULong offset_to_data; + FT_ULong size; + FT_ULong code_page; + FT_ULong reserved; + + } WinPE_RsrcDataEntryRec; + + + typedef struct WinNameInfoRec_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + + } WinNameInfoRec; + + + typedef struct WinResourceInfoRec_ + { + FT_UShort type_id; + FT_UShort count; + + } WinResourceInfoRec; + + +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E +#define WINFNT_PE_MAGIC 0x4550 + + + typedef struct FNT_FontRec_ + { + FT_ULong offset; + + FT_WinFNT_HeaderRec header; + + FT_Byte* fnt_frame; + FT_ULong fnt_size; + FT_String* family_name; + + } FNT_FontRec, *FNT_Font; + + + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + FNT_Font font; + + } FNT_FaceRec, *FNT_Face; + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) winfnt_driver_class; + + +FT_END_HEADER + + +#endif /* WINFNT_H_ */ + + +/* END */ diff --git a/Dependencies/msdf-atlas-gen/.gitattributes b/Dependencies/msdf-atlas-gen/.gitattributes new file mode 100644 index 00000000..176a458f --- /dev/null +++ b/Dependencies/msdf-atlas-gen/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/Dependencies/msdf-atlas-gen/.gitignore b/Dependencies/msdf-atlas-gen/.gitignore new file mode 100644 index 00000000..3a559fc4 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/.gitignore @@ -0,0 +1,26 @@ +/build/ +/Debug/ +/Release/ +/Debug Library/ +/Release Library/ +/x86/ +/x64/ +.vs/ +.vscode/ +.DS_Store +*.exe +*.zip +*.user +*.sdf +*.pdb +*.ipdb +*.iobj +*.suo +*.VC.opendb +*.VC.db +/bin/*.lib +/bin/msdf-atlas-gen +output.png +CMakeUserPresets.json +out/ +/cmake-gen.bat diff --git a/Dependencies/msdf-atlas-gen/.gitmodules b/Dependencies/msdf-atlas-gen/.gitmodules new file mode 100644 index 00000000..64238d0d --- /dev/null +++ b/Dependencies/msdf-atlas-gen/.gitmodules @@ -0,0 +1,6 @@ +[submodule "msdfgen"] + path = msdfgen + url = https://github.com/Chlumsky/msdfgen +[submodule "artery-font-format"] + path = artery-font-format + url = https://github.com/Chlumsky/artery-font-format diff --git a/Dependencies/msdf-atlas-gen/CHANGELOG.md b/Dependencies/msdf-atlas-gen/CHANGELOG.md new file mode 100644 index 00000000..9670d814 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/CHANGELOG.md @@ -0,0 +1,55 @@ + +## Version 1.3 (2024-06-01) + +- Updated to MSDFgen 1.12 +- Switched to vcpkg as the primary dependency management system +- Removed Visual Studio solution and Makefile - now has to be generated by CMake +- CMake configuration overhaul, added installation configuration +- Switched to libpng as the primary PNG file encoder +- Added uniform grid mode (`-uniformgrid`) where atlas is laid out in a rectangular grid +- Added options to add extra padding around glyphs (`-empadding`, `-pxpadding` and similar) +- Added the possibility to specify asymmetrical distance range (`-aemrange`, `-apxrange`) +- Added `-pxalign` option which governs glyph alignment with the pixel grid +- Added `-allglyphs` option as alternative to explicit charset / glyphset +- Added `-chars` and `-glyphs` options to specify charset / glyphset directly on command line +- Added `-varfont` option to configure variables of variable fonts +- Added `-version` option to print program version +- Arguments with double dash (e.g. `--font`) now also accepted +- Minor fix to positioning for `-type hardmask` +- Errors are now reported to `stderr` +- TinyXML 2 no longer required as a dependency + +### Version 1.2.2 (2021-09-06) + +- CMake support +- Conan package manager support + +### Version 1.2.1 (2021-07-09) + +- Updated to MSDFgen 1.9.1 + +## Version 1.2 (2021-05-29) + +- Updated to MSDFgen 1.9. +- Multiple fonts or font sizes can now be compiled into a single atlas. +- Added `-yorigin` option to choose if Y-coordinates increase from bottom to top or from top to bottom. +- Added `-coloringstrategy` option to select MSDF edge coloring heuristic. +- Shadron preview now properly loads floating-point image outputs in full range mode. + +## Version 1.1 (2020-10-18) + +- Updated to MSDFgen 1.8. +- Glyph geometry is now preprocessed by Skia to resolve irregularities which were previously unsupported and caused artifacts. + - The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively. + - The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`. +- Glyphs can now also be loaded by glyph index rather than Unicode values. In the standalone version, a set of glyphs can be passed by `-glyphset` in place of `-charset`. +- Glyphs not present in the font should now be correctly skipped instead of producing a placeholder symbol. +- Added `-threads` argument to set the number of concurrent threads used during distance field generation. + +### Version 1.0.1 (2020-03-09) + +- Updated to MSDFgen 1.7.1. + +## Version 1.0 (2020-03-08) + +- Initial release. diff --git a/Dependencies/msdf-atlas-gen/CMakeLists.txt b/Dependencies/msdf-atlas-gen/CMakeLists.txt new file mode 100644 index 00000000..d2b1f6b6 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/CMakeLists.txt @@ -0,0 +1,207 @@ + +cmake_minimum_required(VERSION 3.15) +include(cmake/version.cmake) + +option(MSDF_ATLAS_BUILD_STANDALONE "Build the msdf-atlas-gen standalone executable" ON) +option(MSDF_ATLAS_USE_VCPKG "Use vcpkg package manager to link project dependencies" ON) +option(MSDF_ATLAS_USE_SKIA "Build with the Skia library" ON) +option(MSDF_ATLAS_NO_ARTERY_FONT "Disable Artery Font export and do not require its submodule" OFF) +option(MSDF_ATLAS_MSDFGEN_EXTERNAL "Do not build the msdfgen submodule but find it as an external package" OFF) +option(MSDF_ATLAS_INSTALL "Generate installation target" OFF) +option(MSDF_ATLAS_DYNAMIC_RUNTIME "Link dynamic runtime library instead of static" OFF) +option(BUILD_SHARED_LIBS "Generate dynamic library files instead of static" OFF) + +if(NOT MSDF_ATLAS_MSDFGEN_EXTERNAL) + set(MSDFGEN_DISABLE_SVG ON CACHE BOOL "Disable unused SVG functionality to minimize dependencies") + set(MSDFGEN_CORE_ONLY OFF CACHE INTERNAL "Only build the core msdfgen library with no dependencies (disabled for msdf-atlas-gen)" FORCE) + set(MSDFGEN_BUILD_STANDALONE OFF CACHE BOOL "Build the msdfgen standalone executable") + set(MSDFGEN_USE_VCPKG ${MSDF_ATLAS_USE_VCPKG} CACHE INTERNAL "Use vcpkg package manager to link msdfgen project dependencies" FORCE) + set(MSDFGEN_USE_OPENMP OFF CACHE INTERNAL "Build with OpenMP support for multithreaded code (disabled for msdf-atlas-gen)" FORCE) + set(MSDFGEN_USE_CPP11 ON CACHE INTERNAL "Build with C++11 enabled (always enabled for msdf-atlas-gen)" FORCE) + set(MSDFGEN_USE_SKIA ${MSDF_ATLAS_USE_SKIA} CACHE INTERNAL "Build msdfgen with the Skia library" FORCE) + set(MSDFGEN_INSTALL ${MSDF_ATLAS_INSTALL} CACHE INTERNAL "Generate installation target for msdfgen" FORCE) + set(MSDFGEN_DYNAMIC_RUNTIME ${MSDF_ATLAS_DYNAMIC_RUNTIME} CACHE INTERNAL "Link dynamic runtime library instead of static for msdfgen" FORCE) +endif() + +get_property(MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) + message(STATUS "CMAKE_BUILD_TYPE not set, defaulting to Release") + set(CMAKE_BUILD_TYPE Release) +endif() + +if(MSDF_ATLAS_DYNAMIC_RUNTIME) + set(MSDF_ATLAS_MSVC_RUNTIME "MultiThreaded$<$:Debug>DLL") +else() + set(MSDF_ATLAS_MSVC_RUNTIME "MultiThreaded$<$:Debug>") +endif() + +if(BUILD_SHARED_LIBS) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +if(MSDF_ATLAS_USE_VCPKG) + # Make sure that vcpkg toolchain file is set + if(NOT CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{VCPKG_ROOT}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") + else() + message(SEND_ERROR "Vcpkg toolchain not configured. Either set VCPKG_ROOT environment variable or pass -DCMAKE_TOOLCHAIN_FILE=VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake to cmake") + endif() + endif() + # Default to statically linked vcpkg triplet on Windows + if(WIN32 AND NOT VCPKG_TARGET_TRIPLET AND NOT MSDF_ATLAS_DYNAMIC_RUNTIME) + if(CMAKE_GENERATOR_PLATFORM MATCHES "64$" AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") + set(VCPKG_TARGET_TRIPLET "x64-windows-static") + elseif(CMAKE_GENERATOR_PLATFORM MATCHES "32$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x86") + set(VCPKG_TARGET_TRIPLET "x86-windows-static") + else() + if(CMAKE_GENERATOR_PLATFORM) + message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -DVCPKG_TARGET_TRIPLET=x64-windows-static or similar") + else() + message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -A to explicitly select platform (Win32 or x64)") + endif() + endif() + endif() + # Select project features + if(NOT MSDF_ATLAS_VCPKG_FEATURES_SET) + set(VCPKG_MANIFEST_NO_DEFAULT_FEATURES ON) + if(MSDF_ATLAS_USE_SKIA) + list(APPEND VCPKG_MANIFEST_FEATURES "geometry-preprocessing") + endif() + endif() + set(MSDFGEN_VCPKG_FEATURES_SET ON) +endif() + +# Version is specified in vcpkg.json +project(msdf-atlas-gen VERSION ${MSDF_ATLAS_VERSION} LANGUAGES CXX) + +if(MSDF_ATLAS_MSDFGEN_EXTERNAL) + if(NOT TARGET msdfgen::msdfgen) + find_package(msdfgen REQUIRED) + endif() +else() + add_subdirectory(msdfgen) +endif() +find_package(Threads REQUIRED) +if(NOT MSDFGEN_DISABLE_PNG AND NOT TARGET PNG::PNG) + find_package(PNG REQUIRED) +endif() + +file(GLOB_RECURSE MSDF_ATLAS_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "msdf-atlas-gen/*.h" "msdf-atlas-gen/*.hpp") +file(GLOB_RECURSE MSDF_ATLAS_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "msdf-atlas-gen/*.cpp") + +# msdf-atlas-gen library +add_library(msdf-atlas-gen ${MSDF_ATLAS_HEADERS} ${MSDF_ATLAS_SOURCES}) +add_library(msdf-atlas-gen::msdf-atlas-gen ALIAS msdf-atlas-gen) +set_target_properties(msdf-atlas-gen PROPERTIES PUBLIC_HEADER "${MSDF_ATLAS_HEADERS}") +set_property(TARGET msdf-atlas-gen PROPERTY MSVC_RUNTIME_LIBRARY "${MSDF_ATLAS_MSVC_RUNTIME}") +target_compile_definitions(msdf-atlas-gen PUBLIC + MSDF_ATLAS_VERSION=${MSDF_ATLAS_VERSION} + MSDF_ATLAS_VERSION_MAJOR=${MSDF_ATLAS_VERSION_MAJOR} + MSDF_ATLAS_VERSION_MINOR=${MSDF_ATLAS_VERSION_MINOR} + MSDF_ATLAS_VERSION_REVISION=${MSDF_ATLAS_VERSION_REVISION} + MSDF_ATLAS_COPYRIGHT_YEAR=${MSDF_ATLAS_COPYRIGHT_YEAR} +) +target_include_directories(msdf-atlas-gen INTERFACE + $ + $ +) +if(MSDF_ATLAS_NO_ARTERY_FONT) + target_compile_definitions(msdf-atlas-gen PUBLIC MSDF_ATLAS_NO_ARTERY_FONT) +else() + target_include_directories(msdf-atlas-gen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/artery-font-format) +endif() +set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdf-atlas-gen) + +target_compile_features(msdf-atlas-gen PUBLIC cxx_std_11) +target_link_libraries(msdf-atlas-gen PRIVATE Threads::Threads) +if(NOT MSDFGEN_DISABLE_PNG) + target_link_libraries(msdf-atlas-gen PRIVATE PNG::PNG) +endif() +target_link_libraries(msdf-atlas-gen PUBLIC msdfgen::msdfgen) + +if(BUILD_SHARED_LIBS AND WIN32) + target_compile_definitions(msdf-atlas-gen PRIVATE "MSDF_ATLAS_PUBLIC=__declspec(dllexport)") + target_compile_definitions(msdf-atlas-gen INTERFACE "MSDF_ATLAS_PUBLIC=__declspec(dllimport)") +else() + target_compile_definitions(msdf-atlas-gen PUBLIC MSDF_ATLAS_PUBLIC=) +endif() + +# msdf-atlas-gen standalone executable +if(MSDF_ATLAS_BUILD_STANDALONE) + set(MSDF_ATLAS_STANDALONE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/msdf-atlas-gen/main.cpp") + if(MSVC) + set(MSDF_ATLAS_STANDALONE_SOURCES ${MSDF_ATLAS_STANDALONE_SOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/msdf-atlas-gen.rc") + endif() + add_executable(msdf-atlas-gen-standalone ${MSDF_ATLAS_STANDALONE_SOURCES}) + target_compile_definitions(msdf-atlas-gen-standalone PUBLIC MSDF_ATLAS_STANDALONE) + target_compile_definitions(msdf-atlas-gen-standalone PRIVATE MSDF_ATLAS_VERSION_UNDERLINE=${MSDF_ATLAS_VERSION_UNDERLINE}) + set_property(TARGET msdf-atlas-gen-standalone PROPERTY MSVC_RUNTIME_LIBRARY "${MSDF_ATLAS_MSVC_RUNTIME}") + set_target_properties(msdf-atlas-gen-standalone PROPERTIES + OUTPUT_NAME msdf-atlas-gen + ARCHIVE_OUTPUT_NAME msdf-atlas-gen-standalone + # Avoid deleting msdf-atlas-gen.lib during clean + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + ) + target_link_libraries(msdf-atlas-gen-standalone PRIVATE msdf-atlas-gen::msdf-atlas-gen) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdf-atlas-gen-standalone) +endif() + +# Installation +if(MSDF_ATLAS_INSTALL) + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + set(MSDF_ATLAS_CONFIG_PATH "lib/cmake/msdf-atlas-gen") + + # install tree package config + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/msdf-atlas-gen-config-version.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion + ) + + configure_package_config_file( + cmake/msdf-atlas-gen-config.cmake.in + ${MSDF_ATLAS_CONFIG_PATH}/msdf-atlas-gen-config.cmake + INSTALL_DESTINATION ${MSDF_ATLAS_CONFIG_PATH} + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + + # build tree package config + configure_file( + cmake/msdf-atlas-gen-config.cmake.in + msdf-atlas-gen-config.cmake + @ONLY + ) + + install(TARGETS msdf-atlas-gen EXPORT msdf-atlas-gen-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/msdf-atlas-gen + ) + if(MSVC AND BUILD_SHARED_LIBS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) + endif() + + export(EXPORT msdf-atlas-gen-targets NAMESPACE msdf-atlas-gen:: FILE "${CMAKE_CURRENT_BINARY_DIR}/msdf-atlas-gen-targets.cmake") + install(EXPORT msdf-atlas-gen-targets FILE msdf-atlas-gen-targets.cmake NAMESPACE msdf-atlas-gen:: DESTINATION ${MSDF_ATLAS_CONFIG_PATH}) + + if(MSDF_ATLAS_BUILD_STANDALONE) + install(TARGETS msdf-atlas-gen-standalone EXPORT msdf-atlas-gen-binary-targets DESTINATION ${CMAKE_INSTALL_BINDIR}) + if(MSVC) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) + endif() + export(EXPORT msdf-atlas-gen-binary-targets NAMESPACE msdf-atlas-gen-standalone:: FILE "${CMAKE_CURRENT_BINARY_DIR}/msdf-atlas-gen-binary-targets.cmake") + install(EXPORT msdf-atlas-gen-binary-targets FILE msdf-atlas-gen-binary-targets.cmake NAMESPACE msdf-atlas-gen-standalone:: DESTINATION ${MSDF_ATLAS_CONFIG_PATH}) + endif() + + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${MSDF_ATLAS_CONFIG_PATH}/msdf-atlas-gen-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/msdf-atlas-gen-config-version.cmake" + DESTINATION ${MSDF_ATLAS_CONFIG_PATH} + ) +endif() diff --git a/Dependencies/msdf-atlas-gen/CMakePresets.json b/Dependencies/msdf-atlas-gen/CMakePresets.json new file mode 100644 index 00000000..2db4e798 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/CMakePresets.json @@ -0,0 +1,155 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "include": [ + "cmake/CMakePresets.json" + ], + "configurePresets": [ + { + "name": "win64", + "displayName": "Windows x64 default config (static, vcpkg, Skia)", + "inherits": [ "win64-base", "vcpkg", "skia" ] + }, { + "name": "win32", + "displayName": "Windows x86 default config (static, vcpkg, Skia)", + "inherits": [ "win32-base", "vcpkg", "skia" ] + }, { + "name": "win64-dynamic", + "displayName": "Windows x64 dynamic config (vcpkg, Skia)", + "inherits": [ "win64-base", "vcpkg", "skia", "dynamic-runtime", "dynamic-lib" ], + "binaryDir": "${sourceDir}/build/win64-dynamic" + }, { + "name": "win32-dynamic", + "displayName": "Windows x86 dynamic config (vcpkg, Skia)", + "inherits": [ "win32-base", "vcpkg", "skia", "dynamic-runtime", "dynamic-lib" ], + "binaryDir": "${sourceDir}/build/win32-dynamic" + }, { + "name": "win64-no-skia", + "displayName": "Windows x64 config without Skia (static, vcpkg)", + "inherits": [ "win64-base", "vcpkg", "no-skia" ] + }, { + "name": "win32-no-skia", + "displayName": "Windows x86 config without Skia (static, vcpkg)", + "inherits": [ "win32-base", "vcpkg", "no-skia" ] + }, + + { + "name": "osx-vcpkg-rel", + "displayName": "Mac OS release config with vcpkg and Skia (static)", + "inherits": [ "osx-rel-base", "vcpkg", "skia" ] + }, { + "name": "osx-vcpkg-dbg", + "displayName": "Mac OS debug config with vcpkg and Skia (static)", + "inherits": [ "osx-dbg-base", "vcpkg", "skia" ] + }, { + "name": "osx-no-skia-rel", + "displayName": "Mac OS release config with system libraries and no Skia (static, install)", + "inherits": [ "osx-rel-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "osx-no-skia-dbg", + "displayName": "Mac OS debug config with system libraries and no Skia (static, install)", + "inherits": [ "osx-dbg-base", "no-vcpkg", "no-skia", "install" ] + }, + + { + "name": "linux-vcpkg-rel", + "displayName": "Linux release config with vcpkg and Skia (static)", + "inherits": [ "linux-rel-base", "vcpkg", "skia" ] + }, { + "name": "linux-vcpkg-dbg", + "displayName": "Linux debug config with vcpkg and Skia (static)", + "inherits": [ "linux-dbg-base", "vcpkg", "skia" ] + }, { + "name": "linux-no-skia-rel", + "displayName": "Linux release config with system libraries and no Skia (static, install)", + "inherits": [ "linux-rel-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "linux-no-skia-dbg", + "displayName": "Linux debug config with system libraries and no Skia (static, install)", + "inherits": [ "linux-dbg-base", "no-vcpkg", "no-skia", "install" ] + } + ], + "buildPresets": [ + { + "name": "win64-rel", + "configurePreset": "win64", + "configuration": "Release" + }, { + "name": "win64-dbg", + "configurePreset": "win64", + "configuration": "Debug" + }, { + "name": "win32-rel", + "configurePreset": "win32", + "configuration": "Release" + }, { + "name": "win32-dbg", + "configurePreset": "win32", + "configuration": "Debug" + }, { + "name": "win64-dynamic-rel", + "configurePreset": "win64-dynamic", + "configuration": "Release" + }, { + "name": "win64-dynamic-dbg", + "configurePreset": "win64-dynamic", + "configuration": "Debug" + }, { + "name": "win32-dynamic-rel", + "configurePreset": "win32-dynamic", + "configuration": "Release" + }, { + "name": "win32-dynamic-dbg", + "configurePreset": "win32-dynamic", + "configuration": "Debug" + }, { + "name": "win64-no-skia-rel", + "configurePreset": "win64-no-skia", + "configuration": "Release" + }, { + "name": "win64-no-skia-dbg", + "configurePreset": "win64-no-skia", + "configuration": "Debug" + }, { + "name": "win32-no-skia-rel", + "configurePreset": "win32-no-skia", + "configuration": "Release" + }, { + "name": "win32-no-skia-dbg", + "configurePreset": "win32-no-skia", + "configuration": "Debug" + }, + + { + "name": "osx-vcpkg-rel", + "configurePreset": "osx-vcpkg-rel" + }, { + "name": "osx-vcpkg-dbg", + "configurePreset": "osx-vcpkg-dbg" + }, { + "name": "osx-no-skia-rel", + "configurePreset": "osx-no-skia-rel" + }, { + "name": "osx-no-skia-dbg", + "configurePreset": "osx-no-skia-dbg" + }, + + { + "name": "linux-vcpkg-rel", + "configurePreset": "linux-vcpkg-rel" + }, { + "name": "linux-vcpkg-dbg", + "configurePreset": "linux-vcpkg-dbg" + }, { + "name": "linux-no-skia-rel", + "configurePreset": "linux-no-skia-rel" + }, { + "name": "linux-no-skia-dbg", + "configurePreset": "linux-no-skia-dbg" + } + ] +} diff --git a/Dependencies/msdf-atlas-gen/LICENSE.txt b/Dependencies/msdf-atlas-gen/LICENSE.txt new file mode 100644 index 00000000..d97dd494 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 - 2024 Viktor Chlumsky + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Dependencies/msdf-atlas-gen/README.md b/Dependencies/msdf-atlas-gen/README.md new file mode 100644 index 00000000..a494eb02 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/README.md @@ -0,0 +1,277 @@ + +# Multi-channel signed distance field atlas generator + +This is a utility for generating compact font atlases using [MSDFgen](https://github.com/Chlumsky/msdfgen). + +The atlas generator loads a subset of glyphs from a TTF or OTF font file, generates a distance field for each of them, and tightly packs them into an atlas bitmap (example below). The finished atlas and/or its layout metadata can be exported as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, a plain image file, a CSV sheet or a structured JSON file. + +![Atlas example](https://github.com/Chlumsky/msdf-atlas-gen/assets/18639794/ee8bfc77-7d36-4cbb-82df-aa8a02424b4a) + +A font atlas is typically stored in texture memory and used to draw text in real-time rendering contexts such as video games. + +- See what's new in the [changelog](CHANGELOG.md). + +## Atlas types + +The atlas generator can generate the following six types of atlases. + +| |Hard mask|Soft mask|SDF|PSDF|MSDF|MTSDF| +|-|-|-|-|-|-|-| +| |![Hard mask](https://user-images.githubusercontent.com/18639794/76163903-9eec9380-614a-11ea-92cb-d49485bbad31.png)|![Soft mask](https://user-images.githubusercontent.com/18639794/76163904-a1e78400-614a-11ea-912a-b220fed081cb.png)|![SDF](https://user-images.githubusercontent.com/18639794/76163905-a4e27480-614a-11ea-93eb-c80819a44e6e.png)|![PSDF](https://user-images.githubusercontent.com/18639794/76163907-a6ac3800-614a-11ea-8d97-dafc1db6711d.png)|![MSDF](https://user-images.githubusercontent.com/18639794/76163909-a9a72880-614a-11ea-9726-e825ee0dde94.png)|![MTSDF](https://user-images.githubusercontent.com/18639794/76163910-ac098280-614a-11ea-8b6b-811d864cd584.png)| +|Channels:|1 (1-bit)|1|1|1|3|4| +|Anti-aliasing:|-|Yes|Yes|Yes|Yes|Yes| +|Scalability:|-|-|Yes|Yes|Yes|Yes| +|Sharp corners:|-|-|-|-|Yes|Yes| +|Soft effects:|-|-|Yes|-|-|Yes| +|Hard effects:|-|-|-|Yes|Yes|Yes| + +Notes: +- *Sharp corners* refers to preservation of corner sharpness when upscaled. +- *Soft effects* refers to the support of effects that use true distance, such as glows, rounded outlines, or simplified shadows. +- *Hard effects* refers to the support of effects that use perpendicular distance, such as mitered outlines or thickness adjustment. + +## Getting started + +This project can be used either as a library or as a standalone console program. +Examples of how to use it as a library are available at the [bottom of the page](#library-usage-examples). +To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases). +To build the project from source, you may use the included [CMake script](CMakeLists.txt). +In its default configuration, it requires [vcpkg](https://vcpkg.io/) as the provider for third-party library dependencies. +If you set the environment variable `VCPKG_ROOT` to the vcpkg directory, the CMake configuration will take care of fetching all required packages from vcpkg. + +## Command line arguments + +Use the following command line arguments for the standalone version of the atlas generator. + +### Input + +- `-font ` (required) – sets the input font file. + - Alternatively, use `-varfont ` to configure a variable font. +- `-charset ` – sets the character set. See [the syntax specification](#character-set-specification-syntax) of `charset.txt`. +- `-glyphset ` – sets the set of input glyphs using their indices within the font file. See [the syntax specification](#glyph-set-specification). +- `-chars` / `-glyphs ` sets the above character / glyph set in-line. See [the syntax specification](#character-set-specification-syntax). +- `-allglyphs` – sets the set of input glyphs to all glyphs present within the font file. +- `-fontscale ` – applies a scaling transformation to the font's glyphs. Mainly to be used to generate multiple sizes in a single atlas, otherwise use [`-size`](#glyph-configuration). +- `-fontname ` – sets a name for the font that will be stored in certain output files as metadata. +- `-and` – separates multiple inputs to be combined into a single atlas. + +If no character set or glyph set is provided, and `-allglyphs` is not used, the ASCII charset will be used. + +### Bitmap atlas type + +`-type ` – see [Atlas types](#atlas-types) + +`` can be one of: + +- `hardmask` – a non-anti-aliased binary image +- `softmask` – an anti-aliased image +- `sdf` – a true signed distance field (SDF) +- `psdf` – a signed perpendicular distance field (PSDF) +- `msdf` (default) – a multi-channel signed distance field (MSDF) +- `mtsdf` – a combination of MSDF and true SDF in the alpha channel + +### Atlas image format + +`-format ` + +`` can be one of: + +- `png` – a compressed PNG image +- `bmp` – an uncompressed BMP image +- `tiff` – an uncompressed floating-point TIFF image +- `text` – a sequence of pixel values in plain text +- `textfloat` – a sequence of floating-point pixel values in plain text +- `bin` – a sequence of pixel values encoded as raw bytes of data +- `binfloat` – a sequence of pixel values encoded as raw 32-bit floating-point values + +### Atlas dimensions + +`-dimensions ` – sets fixed atlas dimensions + +Alternativelly, the minimum possible dimensions may be selected automatically if a dimensions constraint is set instead: + +- `-pots` – a power-of-two square +- `-potr` – a power-of-two square or rectangle (typically 2:1 aspect ratio) +- `-square` – any square dimensions +- `-square2` – square with even side length +- `-square4` (default) – square with side length divisible by four + +### Uniform grid atlas + +By default, glyphs in the atlas have different dimensions and are bin-packed in an irregular fashion to maximize use of space. +With the `-uniformgrid` switch, you can instead force all glyphs to have identical dimensions and be laid out in a grid. +In that case, these additional options are available to customize the layout: + +- `-uniformcols ` – sets the number of columns +- `-uniformcell ` – sets the dimensions of the grid's cells +- `-uniformcellconstraint ` – sets constraint for cell dimensions (see explanation of options above) +- `-uniformorigin ` – sets whether the glyph's origin point should be fixed at the same position in each cell + +### Outputs + +Any non-empty subset of the following may be specified: + +- `-imageout ` – saves the atlas bitmap as a plain image file. Format matches `-format` +- `-json ` – writes the atlas's layout data as well as other metrics into a structured JSON file +- `-csv ` – writes the glyph layout data into a simple CSV file +- `-arfont ` – saves the atlas and its layout data as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file +- `-shadronpreview ` – generates a [Shadron script](https://www.arteryengine.com/shadron/) that uses the generated atlas to draw a sample text as a preview + +### Glyph configuration + +- `-size ` – sets the size of the glyphs in the atlas in pixels per em +- `-minsize ` – sets the minimum size. The largest possible size that fits the same atlas dimensions will be used +- `-emrange ` – sets the distance field range in em's +- `-pxrange ` (default = 2) – sets the distance field range in output pixels +- `-aemrange` / `-apxrange ` – sets the distance field range asymmetrically by specifying the minimum and maximum representable signed distances (outside distances are negative!) +- `-pxalign ` (default = vertical) – enables or disables alignment of glyph's origin point with the pixel grid +- `-empadding` / `-pxpadding ` – sets additional padding within each glyph's box (in em's / pixels) +- `-outerempadding` / `-outerpxpadding ` – sets additional padding around each glyph's box +- `-aempadding` / `-apxpadding` / `-aouterempadding` / `-aouterpxpadding ` – sets additional padding (see above) asymmetrically with a separate width value for each side + +### Distance field generator settings + +- `-angle ` – sets the minimum angle between adjacent edges to be considered a corner. Append D for degrees (`msdf` / `mtsdf` only) +- `-coloringstrategy ` – selects the edge coloring heuristic (`msdf` / `mtsdf` only) +- `-errorcorrection ` – selects the error correction algorithm. Use `help` as mode for more information (`msdf` / `mtsdf` only) +- `-miterlimit ` – sets the miter limit that limits the extension of each glyph's bounding box due to very sharp corners (`psdf` / `msdf` / `mtsdf` only) +- `-overlap` – switches to distance field generator with support for overlapping contours +- `-nopreprocess` – disables path preprocessing which resolves self-intersections and overlapping contours +- `-scanline` – performs an additional scanline pass to fix the signs of the distances +- `-seed ` – sets the initial seed for the edge coloring heuristic +- `-threads ` – sets the number of threads for the parallel computation (0 = auto) + +Use `-help` for an exhaustive list of options. + +## Character set specification syntax + +The character set file is a text file with UTF-8 or ASCII encoding. +The characters can be denoted in the following ways: + +- Single character: `'A'` (UTF-8 encoded), `65` (decimal Unicode), `0x41` (hexadecimal Unicode) +- Range of characters: `['A', 'Z']`, `[65, 90]`, `[0x41, 0x5a]` +- String of characters: `"ABCDEFGHIJKLMNOPQRSTUVWXYZ"` (UTF-8 encoded) + +The entries should be separated by commas or whitespace. +In between quotation marks, backslash is used as the escape character (e.g. `'\''`, `'\\'`, `"!\"#"`). +The order in which characters appear is not taken into consideration. + +Additionally, the include directive can be used to include other charset files and combine character sets in a hierarchical way. +It must be written on a separate line: + +`@include "base-charset.txt"` + +### Glyph set specification + +The syntax of the glyph set specification is mostly the same as that of a character set, but only numeric values (decimal and hexadecimal) are allowed. + +## Library usage examples + +Here are commented snippets of code that demonstrate how the project can be used as a library. + +### Generating whole atlas at once + +```c++ +#include + +using namespace msdf_atlas; + +bool generateAtlas(const char *fontFilename) { + bool success = false; + // Initialize instance of FreeType library + if (msdfgen::FreetypeHandle *ft = msdfgen::initializeFreetype()) { + // Load font file + if (msdfgen::FontHandle *font = msdfgen::loadFont(ft, fontFilename)) { + // Storage for glyph geometry and their coordinates in the atlas + std::vector glyphs; + // FontGeometry is a helper class that loads a set of glyphs from a single font. + // It can also be used to get additional font metrics, kerning information, etc. + FontGeometry fontGeometry(&glyphs); + // Load a set of character glyphs: + // The second argument can be ignored unless you mix different font sizes in one atlas. + // In the last argument, you can specify a charset other than ASCII. + // To load specific glyph indices, use loadGlyphs instead. + fontGeometry.loadCharset(font, 1.0, Charset::ASCII); + // Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies. + const double maxCornerAngle = 3.0; + for (GlyphGeometry &glyph : glyphs) + glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0); + // TightAtlasPacker class computes the layout of the atlas. + TightAtlasPacker packer; + // Set atlas parameters: + // setDimensions or setDimensionsConstraint to find the best value + packer.setDimensionsConstraint(TightAtlasPacker::DimensionsConstraint::SQUARE); + // setScale for a fixed size or setMinimumScale to use the largest that fits + packer.setMinimumScale(24.0); + // setPixelRange or setUnitRange + packer.setPixelRange(2.0); + packer.setMiterLimit(1.0); + // Compute atlas layout - pack glyphs + packer.pack(glyphs.data(), glyphs.size()); + // Get final atlas dimensions + int width = 0, height = 0; + packer.getDimensions(width, height); + // The ImmediateAtlasGenerator class facilitates the generation of the atlas bitmap. + ImmediateAtlasGenerator< + float, // pixel type of buffer for individual glyphs depends on generator function + 3, // number of atlas color channels + &msdfGenerator, // function to generate bitmaps for individual glyphs + BitmapAtlasStorage // class that stores the atlas bitmap + // For example, a custom atlas storage class that stores it in VRAM can be used. + > generator(width, height); + // GeneratorAttributes can be modified to change the generator's default settings. + GeneratorAttributes attributes; + generator.setAttributes(attributes); + generator.setThreadCount(4); + // Generate atlas bitmap + generator.generate(glyphs.data(), glyphs.size()); + // The atlas bitmap can now be retrieved via atlasStorage as a BitmapConstRef. + // The glyphs array (or fontGeometry) contains positioning data for typesetting text. + success = myProject::submitAtlasBitmapAndLayout(generator.atlasStorage(), glyphs); + // Cleanup + msdfgen::destroyFont(font); + } + msdfgen::deinitializeFreetype(ft); + } + return success; +} +``` + +### Dynamic atlas + +The `DynamicAtlas` class allows you to add glyphs to the atlas "on-the-fly" as they are needed. In this example, the `ImmediateAtlasGenerator` is used as the underlying atlas generator, which however isn't ideal for this purpose because it may launch new threads every time. In practice, you would typically define your own atlas generator class that properly handles your specific performance and synchronization requirements. + +Acquiring the `GlyphGeometry` objects can be adapted from the previous example. + +```c++ +#include + +using namespace msdf_atlas; + +using MyDynamicAtlas = DynamicAtlas>>; + +const double pixelRange = 2.0; +const double glyphScale = 32.0; +const double miterLimit = 1.0; +const double maxCornerAngle = 3.0; + +MyDynamicAtlas atlas; + +void addGlyphsToAtlas(GlyphGeometry *glyphs, int count) { + for (int i = 0; i < count; ++i) { + // Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies. + glyphs[i].edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0); + // Finalize glyph box size based on the parameters + glyphs[i].wrapBox(glyphScale, pixelRange/glyphScale, miterLimit); + } + // Add glyphs to atlas - invokes the underlying atlas generator + // Adding multiple glyphs at once may improve packing efficiency. + MyDynamicAtlas::ChangeFlags change = atlas.add(glyphs, count); + if (change&MyDynamicAtlas::RESIZED) { + // Atlas has been enlarged - can be handled here or directly in custom generator class + } + // Glyph positioning data is now stored in glyphs. +} +``` + +The atlas storage (and its bitmap) can be accessed as `dynamicAtlas.atlasGenerator().atlasStorage()`. diff --git a/Dependencies/msdf-atlas-gen/cmake/CMakePresets.json b/Dependencies/msdf-atlas-gen/cmake/CMakePresets.json new file mode 100644 index 00000000..a3eec351 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/cmake/CMakePresets.json @@ -0,0 +1,154 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "configurePresets": [ + { + "name": "release-only", + "displayName": "Release only configuration", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, { + "name": "debug-only", + "displayName": "Debug only configuration", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, { + "name": "win64-base", + "displayName": "Windows 64-bit base configuration", + "hidden": true, + "architecture": "x64", + "binaryDir": "${sourceDir}/build/win64", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { + "name": "win32-base", + "displayName": "Windows 32-bit base configuration", + "hidden": true, + "architecture": "Win32", + "binaryDir": "${sourceDir}/build/win32", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { + "name": "osx-base", + "displayName": "Mac OS base configuration", + "hidden": true, + "binaryDir": "${sourceDir}/build/osx", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, { + "name": "osx-rel-base", + "displayName": "Mac OS base release configuration", + "inherits": [ "osx-base", "release-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/osx-rel" + }, { + "name": "osx-dbg-base", + "displayName": "Mac OS base debug configuration", + "inherits": [ "osx-base", "debug-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/osx-dbg" + }, { + "name": "linux-base", + "displayName": "Linux base configuration", + "hidden": true, + "binaryDir": "${sourceDir}/build/linux", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, { + "name": "linux-rel-base", + "displayName": "Linux base release configuration", + "inherits": [ "linux-base", "release-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/linux-rel" + }, { + "name": "linux-dbg-base", + "displayName": "Linux base debug configuration", + "inherits": [ "linux-base", "debug-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/linux-dbg" + }, { + "name": "vcpkg", + "displayName": "Configuration with vcpkg as dependency management system", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_USE_VCPKG": "ON" + } + }, { + "name": "no-vcpkg", + "displayName": "Configuration with dependencies not managed by vcpkg", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_USE_VCPKG": "OFF" + } + }, { + "name": "skia", + "displayName": "Configuration with Skia geometry preprocessing", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_USE_SKIA": "ON" + } + }, { + "name": "no-skia", + "displayName": "Configuration without Skia geometry preprocessing", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_USE_SKIA": "OFF" + } + }, { + "name": "install", + "displayName": "Configuration with installation targets", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_INSTALL": "ON" + } + }, { + "name": "static-runtime", + "displayName": "Configuration that links against the static runtime", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_DYNAMIC_RUNTIME": "OFF" + } + }, { + "name": "dynamic-runtime", + "displayName": "Configuration that links against the dynamic runtime", + "hidden": true, + "cacheVariables": { + "MSDF_ATLAS_DYNAMIC_RUNTIME": "ON" + } + }, { + "name": "static-lib", + "displayName": "Configuration that builds and links msdfgen statically", + "hidden": true, + "cacheVariables": { + "BUILD_SHARED_LIBS": "OFF" + } + }, { + "name": "dynamic-lib", + "displayName": "Configuration that builds and links msdfgen dynamically", + "hidden": true, + "cacheVariables": { + "BUILD_SHARED_LIBS": "ON" + } + } + ] +} diff --git a/Dependencies/msdf-atlas-gen/cmake/msdf-atlas-gen-config.cmake.in b/Dependencies/msdf-atlas-gen/cmake/msdf-atlas-gen-config.cmake.in new file mode 100644 index 00000000..b5b2317f --- /dev/null +++ b/Dependencies/msdf-atlas-gen/cmake/msdf-atlas-gen-config.cmake.in @@ -0,0 +1,21 @@ + +include(CMakeFindDependencyMacro) + +set(MSDF_ATLAS_STANDALONE_AVAILABLE @MSDF_ATLAS_BUILD_STANDALONE@) +set(MSDF_ATLAS_NO_PNG @MSDFGEN_DISABLE_PNG@) + +if(NOT MSDF_ATLAS_NO_PNG) + find_dependency(PNG REQUIRED) +endif() +find_dependency(msdfgen REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/msdf-atlas-gen-targets.cmake") + +if(MSDF_ATLAS_STANDALONE_AVAILABLE) + include("${CMAKE_CURRENT_LIST_DIR}/msdf-atlas-gen-binary-targets.cmake") + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + set_target_properties(msdf-atlas-gen-standalone::msdf-atlas-gen-standalone PROPERTIES IMPORTED_GLOBAL TRUE) + endif() + add_executable(msdf-atlas-gen::msdf-atlas-gen-run ALIAS msdf-atlas-gen-standalone::msdf-atlas-gen-standalone) + set(MSDF_ATLAS_GEN_EXECUTABLE "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/msdf-atlas-gen@CMAKE_EXECUTABLE_SUFFIX@") +endif() diff --git a/Dependencies/msdf-atlas-gen/cmake/version.cmake b/Dependencies/msdf-atlas-gen/cmake/version.cmake new file mode 100644 index 00000000..291f6321 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/cmake/version.cmake @@ -0,0 +1,19 @@ + +# This script reads version from vcpkg.json and sets it to ${MSDF_ATLAS_VERSION} etc. + +cmake_minimum_required(VERSION 3.15) + +file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/../vcpkg.json" MSDF_ATLAS_VCPKG_JSON) + +string(REGEX MATCH "\"version\"[ \t\n\r]*:[ \t\n\r]*\"[^\"]*\"" MSDF_ATLAS_TMP_VERSION_PAIR ${MSDF_ATLAS_VCPKG_JSON}) +string(REGEX REPLACE "\"version\"[ \t\n\r]*:[ \t\n\r]*\"([^\"]*)\"" "\\1" MSDF_ATLAS_VERSION ${MSDF_ATLAS_TMP_VERSION_PAIR}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\1" MSDF_ATLAS_VERSION_MAJOR ${MSDF_ATLAS_VERSION}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\2" MSDF_ATLAS_VERSION_MINOR ${MSDF_ATLAS_VERSION}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\3" MSDF_ATLAS_VERSION_REVISION ${MSDF_ATLAS_VERSION}) +string(LENGTH ${MSDF_ATLAS_VERSION} MSDF_ATLAS_VERSION_LENGTH) +string(REPEAT "-" ${MSDF_ATLAS_VERSION_LENGTH} MSDF_ATLAS_VERSION_UNDERLINE) +string(TIMESTAMP MSDF_ATLAS_COPYRIGHT_YEAR "%Y") + +unset(MSDF_ATLAS_TMP_VERSION_PAIR) +unset(MSDF_ATLAS_VERSION_LENGTH) +unset(MSDF_ATLAS_VCPKG_JSON) diff --git a/Dependencies/msdf-atlas-gen/icon.ico b/Dependencies/msdf-atlas-gen/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..09e1a936e1b5df1fa2d35af3986f7b345047d42c GIT binary patch literal 32038 zcmeHQ32arx`v0KqWm9Po{IiJM2clTEg0hsNEmSC2wgMH(A}!^ywCt9(3rkt#JwSv2 z8U*7K0Tqp+ghas?L~)6tEP2X{q9SocjT^=Ue*f<`hf{BF?>TqrEo$r}U(dO7X1;B{ zGxN>Nccvn>Bv#_%MUz*i#)|ako!9!kOY@)Byu`#yzuSu3*+e8Y)%xA8ugJw-BJK1i zQFs+s3?26<1sVQHbGHBp{e)`rMSY${2R8yz)vgwNrRsA$N3crTV$Kqs=px zVPYL0S+Kw5e(dRb2rsrgg8j0;QvLn=1uq_Hi9Lt9V*mb@_H!ErawQi(%gnkEWB9Gw2RVPq7YBioZa~5*ujDe@loNr{!sbi*=rU+QPARZSeZtq??gpu`C7#v84xL@nRK9dGFROczyElj=X~dasVeb zo=}}_#DN2v_fDm{0r_YB`7$40$ydm@ekwAiUXQQ7(!BYh*KZ}Qj19HDZ~+AVXw@q8 z`s5)sH5JmQj{$S9dCd0%{aLl7dX=TMA_LZCKjT$MRj~V+rKa!FjG7ck1O9DT-M{^L zsBU`x_yf|PF=Ga1Z`}&ca`VY{y`b00lbhor4w$;c5p&`_e17gAN=gcS>jtEMgWO>HxrKF?p=s)9 z+|+&~4$EO2l!Lx?UGEPb6dXP*xM^g2G##Cah0E%ie)5JJ%4KJL|5T2Xv|f={FkZ%E zj?BSwS#Ef0D{afmXyt(SZQELX^77?^IdcT##|vJ0ML?eX>NwJ$B2x^#Ov%IoS%ASZ z7(cc82_-{IAVY_`LP^O`{Pa^R3?3|4ut1QRY4I~M45<1ofac&$r}9Mk|mJh zVpm|9tTjupXmKY@oM>r@ZJ@;b!IeJCe<@$$(U?au^@gcfa7Ph349kQJ8|DffGKXP7 z(H)pN^#(lpXbismvJzdJkD&B7%0_(V`3%G3hhstf0`!gVi*x5MBJ=!th#xTT+{N?g z+c#eAE*`^&$E#oD(e{s=ezGK+Hkd1OQ7DBNEu(Qf?>Khns~?%4UjcUS&d2fNdD`Zp zZ7-NR*V27*a^&>c2FK+%_R3!5Ngig%3{WSu3%(4Wn7VktKMH~Rqg1-4zXkFd+}-6nn78Q*!n`}D_)i+{&sm-V^oZG}{hPjk!f z+2>K-GAT2C;azf<=^I~`m&?n%{Ib=@-F27M=arRN{IDUpUIP> zN57#o#6`J?O|r?@AZ_tEc@8J#Bu<_bJolVsbF{rpn*E9>!;jEm6ZHIk5 zeYL;!n0KCbclNB7xv%=@_mWfALxl>&!>9+T zT{|#@PMbXXr%?HhRylwAf6L!$HYWW?B<6C0O_%EwTr$m3C|{@0wbPnZqk(GFK(zXh z>c-=wg6gIlE&P8A{@b)^1G)bCN>EGlyk2j#bZKxAXCPXJhsxt`Q2qDOwQQ!*3brp{ zUssqXK$9k6`85IMB@QOywDH?l(qh(qhxm^cG!X%FKi( zV;FkGCgTJ7z|433^b&}cYaZ7CKlnh_V6e!~Xq8OsE~ z9}@qp$N4>V-CKHNl1xI86d_x(F+c_w{@F$W@Q0MgwE-d-FhG!j`L$@Z~@Yb=D828`* zLc#>rdF$jc-D7QnapM~6np$Jzlgz3vq4ELA1b>rF>y zmrN{7S%`v^0;Hv+qeV&zBtl@_wDc4d6r^C`!W3O6?1Jgj>zQ}r&O04-A2$CgEWVTP z@PfR6G)Y52VgZV#6=V3cX-H70tsr3n>##0y6ctZX84{6}CV1fmrS+XF?-B8Tzua%u z+PX`3jFWL#-ntA^muy1MfBzft%e4<$wk#}Q9oC(?X$h8>wN@JvbnkAh(cOQ4^!ZPf zRAWO+WC@1U8-n?5=Hp-KYmq*799oSX3kefgCw<&l{A+Ex?)A6PceoywEV15Ojjai2 z$Fze>5SIPh^*9b3seJ?~ZBsBMaSF;3%aE0rg^r0m;LXTDoPq=amSNeBJrcFAOhj2( zqV}DM+K0B)zO=R(i*0%?*NFHx{zNTcfM)=*J=rMs6l0QS5_)@jz!DUJQZ01APc0Pe>@Y5u4XQ*NF5_y>S2bl$@&MPjGCb!nvQ} zq(6KAf@74wzi{f5wb$WP*Dqgx2275$wX}I=`x9ejYz2RU@Aqr+nvu;e>whJWuf4`t znTr0x*s+%GUHk=qz5+7uPcP8##?sj6nf^q7>5rK*^LKwj)SpmR`buAadb*x%@mN|a z<^ICVnS%cPfA<#}Hx9{mh}$VuqN@cfqD)SuA3IPO6)7VCmszytC? zr8*BhAh>YBipk>MKlk8razy+BKMZqXhHl1e|%NqpE~$fzQsP-XZaJ#J7wVh z2j!p*aX;#kuFU=uGs!piL&!Vt=`ZZtr?|ciOZUX6Cul>o zCE65Y=@?UJ<6tZyW9n!tv>DnC{e>PqEPr9^R(D!99-ph;22ABN^{MN91%E>40-O_Y zZoqz&ahYs`YvdYSbB$#mjKgHVNgtoSK7IZ$`~`nr0x}_w&dE48 z;~b6iOY+aYiG2)zu)pWrigPT^wK(T`{dK|n@4M^CpXR0CdI^~P<#heMOqLlw2g*Rh zGv~&fBXh1y* zI|{*0oXSMaerz77f7_qvddoi{1qDdB1ibJ1PhFF}%B zICwiA-oAF|UfjhYy?Zh5 z&>@He@EOZgk$2X2O3}c5IdIhQA7Ct2rCbi(yV;LZyVT^@Xds{lv_saUhU<6zn5FB8 z)Lf&Z2Y>zAzZs{Ms<2eSj?#JQR(jYB2UdStX)`kuQVYmN| zZ99OUp=U5$gj@^^PyVLoGyDiNzp8m4no-GX-ux4?AYc+ zGi>?o7=Zg?H=}Or1W1Pt6(FWv2Tb$KHtTHs&dovZRnF&kb0jitwg)jC+Ew6zJk?ET zjr%rR@uA#PbKoOv`H6?;n0zXqqLXw&o7Vj*#M9i^s=tXB{Y8Gk8}fz|-74q5@rK}+ zUj&RDy|I6*3Ouyw*BYHV2|oSQIwQqFcJdG`1?2M{xyQ6G*Wdd{A7nHdkE_NNp!I-! zjFgdJ{MQrmgej9Ki2-pa;fV9~oFdcqPds78gN+<1Xq`U*R~3vy#`s1Wi*219KnCu) z$CXY*@^_IgMz-Cu+sI0p^XtyV-F1sFK_(cTP&ZufUoER6meWZ`t5;j{Ge&~4PM9FL zyQnVm=hg*v!5F#SyR9-^x;O1E&A=M7#klnNRXc|8Y64%IdjjJ?*zZ$<~tIEhCX&pj`bPS#rB;ovvHf;X5tgL zr^D}i89S0BNwD`DxaX!+q5|9}C1LJQBqdofCH#Jvdq<3Sxa~Hnglk z-4@cq$p4bOgq!7N6C=ae2JXx8+$+Y(aK9SY0o$+J4!Q2SsKEB^icpa<9*%oWJU5H` zevFymH~cr>EO_Z9Oa2xus!x9EhG!el1{j~hHfCG_-vP#-G4`8%-_Zj{=`JA7w3;c- zDiHy35ZBS82f#j%@ga;yqwOlb3U2Lp>6uJM;rzdHf zCu!R!sSPBlEp$_xXsEVfov9EP7gTo27A(2Sua&V~wi{#SyPg)8hTP;_lxCM=R`x7p zW{<(m+1Y5KAW;J1BF@Y)+4|0BtNhv82PA7>5NG-XGP8YqNU}#oeiOr@uN?b&_WA7l z3%eF#>6|i*TeJwbDR>oXD@YZAIEafliF;|;96dXttBEV*SimuX^0Oac+k^mBZhzAF zNIn9`diuj0`{@I$ZnPQ;i|)t3EnCoj%^FEp3OxBX%IfF<4%Y)jdOkvS95JtqfE6{Lzl9Kt2<>i{iHiIj=O{mY{_YxEF*121=BCcYhSUw1kgEQ0YC77arXo&34;76F zSeH2Zq^GLPsTv=js&VnD>hC72zgr)i3y=wpi+{oST!F34ER zFl1-hU@2sL=1d!H0$y!@n6aXac^xIAOy9VJ7Kc}s!(;oIeQGf#qsf$hjre<(}8xeWn!?9d8YiSwG< zZx8J6^1LPzZ{9pC*`wP2)H}~rVxuxX+tD9ZUy1LDM?68>$>XusIOx+j`MZqwCQ+W_ z6lU8;U4F)gQvMaP0*rNKj5N=@BJiGh_V>~pD}wRM`8^Tx8(hZ2GCr2)WD$7JycH{~ zGK@D3hA+T#&2mj);f$47;}5?p@0z&}=RlkbaZbd!5p9BNL(~z!p-{@Mz;7v7nCltz zX*kE>T!(WW&V6VT@4jpKyRotExEyG?3hz+ImFEZLK_egIvpEOmT$poW&W#!O$-d!5 zdC`=)R<3o#b?vp5>@U7(&1pHe#b{Y{b9!ZbIr_NALbdQw1KYD z)t@JH?P|3v&mQHw&oxc1W%0WVu65Gi<#~xjuxgcaJGk+9>6uGX?4k?f8 z!nAK+f0*mT75rh@Y|8MQ4jV7e*LYl;|uGihdI z<9X2j{xHv>q(5w*Px6pFR8Hrihb;N22l~4_m(qWIm*+tfd9!AJUinq4cvhY@I`H?0 z`Az9i84B(r@&5|YAFd;HP^XUN@ACf&aNlO=Q0q)w-}PPF-+lJkD$7ot2TSGcq6Ndg z=XoxC2Ug0;fc`MQ!Lz^5<5*$$>HOY~-{J-GcUP{o+MegPM8cC_oobaoMq==z{D}AD zJx71o{@)Zl_k-thP+|O^6i)u`d+!N;{811S^XHeJy51(+j16#I(A6JqsiLDL-27dx z^AXv$ZBdcE+U=k6v!CNTz_U@D{9%4Wi$cm@XuhR&@^^XW36Zg1^t0nge^;yh+dO_K z9~ytSqjYrkhu`{1&w_r-?A-?PcRO~p{M`>fjGFA1rTwV`_J6bi`hNUolzpAQKfLqa zoqG23y_Ni3_K7@;f_^WNu>Z658ilK(a7|I6#d#3rxBX$BKTW^L*B>5x>sb9}_SOpi zF8v&yPt7@i?eB8lqZ~&IT!oJ!9dnM^ukvdJe|V`Z{XJeHzLV}@#OwO570iU;gWKoioBMyP$g2>~!2c1z%1xX8b>(Nf+5Ry1NzGbd z`y9yR$p#YiO0a)-&uMRbAnt2Y_9*$g{`M2h1pLca>9>7m2G>VAH|T}9J{lL)KQP4g z?}N_08kqGB%1>W7%C=8@!BSLd)|T4%q0tXG<~@eGw`$y^gY0&G-F~;~x%6KA@Ixci zuKm}SUzM%CtNO#5ZZuYHx&&?Az*m-GVjb442Dq&4PyQ1U5;R7q3^5841XzY;S*IFg zC(dB0y6FB{@Ycxhu7N*GJ5?7S?$TFJpHp43M1nV%{58*OG*F{~zljDcZ_D}b_m&q`~ereFgmnJWHj3rrBD@%qX3k_gEa3#wTsvC4k6QF;+m+z3G zc2`=vwU7c17BY9q8FJ>#;SA}&|2nY~b9QMX>)XO+w&XXo6@6X$mbSKA8}n7N?|7Wu z+nr7ME$Cm-4(MCZN^i|upLfTXW*gZYnPdCfzG9UV-yYFBWps@6z{@6k`p5R(5-%;y zBQH1fdYb#KU0K^Yc5P*=S<`yfvI@Or-Wyi8cl5ORduiwN)OnBV%ZBIoMC)SftO_o> z7!N^dW)u8hfsSzK;Po&3t>JYEKZQqy{vY`5M&#dP@Vm!1=;iT$euzbj0z1}VB_<8= z`!H^Vc}9MQZ*puK*tg7i0nUMCZ5VY8-%23e1MfP|3)cOE$33XoVU8A2?V;5`|Al8{ zo!$n$*R)k1x!4ors?1%3y+7Lb%-u%roSvYwE74;#@I3Y9VNArBE}s0%s^u?kcNFtJ z?jE)Joq<`gr1RtF_+IsUN78Qd6z8HFJKf|X#V;TxE$y^J)+ow>iS6&e#BSKhH}E@T z!_>-$EP8dIMNeJl$Y-blIYYZHJld5-J8++EF-CD8KfhKM%Bt8pn9?WzPPaW-AJS3h zqo@q+sBkmBR2fxGYw*U|2VYIsK7Y@Vxb^i?HB|L&v5{S&={&-!zskuD$vMv$slKng zBX5oK-&wmt?w=r|I=e(O*uCUimZ-AG9_eV-F^}r?r_JbuHdG5)Tq9@I$abo%+EI@^ zQSLFB>{zn3{dn`1*8GV3^J7Mq712tam2@H!#@Sdzj&#Y*J!C3Wfi`#wP2t+0vNXXo zKN9<;?U1OE^(#9vIVd|4*#Z@-^hY>d1np>F5O3#nR}VD%Ppr zD~{7zi`mLls1lauef^UBh>^JPXjk!7=(ee%^7W&=Vh`87&&uz^?U_X9gbKC$ntGFu zX*yGw;cTma$F5w$smJ9{Gx9nEY1O<&6Z^v4udz|j>y1vztPW@8D=f_0kdB9wM_wwf zTwFzUPH7TtA(LRiioKz1bPr!gcy^Zq{N>*&pPOv!fJ1Bv_Bl``HX85FA(R=(^BeA6S&j+k1UMFHv zX7=oTDddp2Ufi>)tSi>KMK<0LLT;b1x@=VyQGL+O!C}+NV?Cn%bdX*7oEGef);ykd zbUSPL{1zD>5y-cB+{Fpirv69Xg z@Sg;oizKPhH150qhtO_(O6>FY{(nqQ?+cNG`#t%**2T-kHg1RH$vn$D%qBFKU?}{u e*+o_Bjn8Xm++~zeL-h!@rk18}8qc2n_5BY$v{J4B literal 0 HcmV?d00001 diff --git a/Dependencies/msdf-atlas-gen/resource.h b/Dependencies/msdf-atlas-gen/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..2b808651339802d4095c15904834ffbeb1ed5252 GIT binary patch literal 1336 zcmbu9TT22_6ouDw(0>^4#fU7UKVUl9kXmR;_A+?MFs#7IGNQj;efu2D3!@luaL#4+ zUT5vK_W1p^s~u(3*PR9$>WMi}L)WS+QcY!^w+a<2tEu*Qmto#6XO^)ZEe)s2?IoRY zV*wTwo(n0rB;%jS>)y`wVf_yox?3=7s9Xp4?devJv-Cr zknzE&!68PS5GElzTh&xVl@LWf8MEks`iJUitY;S)BSsC`DDdptMa z$DF?~_c^mp=n*w>oe{X+81XK*a6=O;AKleEIgjl7L>@St5zmCRN6&%Y`^`=BJ))Y3 z>LPfV$9WL{GV(ei$B^e5)ZjODmHYngP|wKiU!4XM-Y48LK%p_Ssqn`9tgaqd_lQjv z@I3D!@g6V0{VUgtO~>Bcv9G2@1s8Zya=97Q9Duz(r%r5vXsf$IS6P3zaqyIr3hOkz z?EA30V{$^>xPCO8202Z7vdG%Ln*s<;)~i~YUdLM_n;`rneq l+dFRmIaco`)&Z!0!}dy=7n^ZSpLq{uaNis==e+vM`yXfGydVGo literal 0 HcmV?d00001 diff --git a/Dependencies/msdf-atlas-gen/vcpkg.json b/Dependencies/msdf-atlas-gen/vcpkg.json new file mode 100644 index 00000000..fdb7a678 --- /dev/null +++ b/Dependencies/msdf-atlas-gen/vcpkg.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/master/docs/vcpkg.schema.json", + "name": "msdf-atlas-gen", + "version": "1.3.0", + "description": "Multi-channel signed distance field atlas generator", + "homepage": "https://github.com/Chlumsky/msdf-atlas-gen", + "license": "MIT", + "dependencies": [ + "freetype", + "libpng" + ], + "default-features": [ + "geometry-preprocessing" + ], + "features": { + "geometry-preprocessing": { + "description": "Preprocessing of non-compliant vector geometry via the Skia library", + "dependencies": [ { + "name": "skia", + "default-features": false + } ] + } + } +} diff --git a/Dependencies/msdfgen/msdfgen.lua b/Dependencies/msdfgen/msdfgen.lua new file mode 100644 index 00000000..b860be6a --- /dev/null +++ b/Dependencies/msdfgen/msdfgen.lua @@ -0,0 +1,98 @@ +local dep = Solution.Util.CreateDepTable("msdfgen", { "freetype" }) + +Solution.Util.CreateStaticLib(dep.Name, Solution.Projects.Current.BinDir, dep.Dependencies, function() + Solution.Util.SetLanguage("C++") + Solution.Util.SetCppDialect(20) + + local rootDir = dep.Path .. "/msdfgen" + local coreDir = rootDir .. "/core" + local extDir = rootDir .. "/ext" + + local defines = { "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", "_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS" } + local links = {} + local files = + { + rootDir .. "/msdfgen.h", + rootDir .. "/msdfgen-ext.h", + + coreDir .. "/arithmetics.h", + coreDir .. "/base.h", + coreDir .. "/Bitmap.h", + coreDir .. "/Bitmap.hpp", + coreDir .. "/bitmap-interpolation.hpp", + coreDir .. "/BitmapRef.hpp", + coreDir .. "/Contour.cpp", + coreDir .. "/contour-combiners.cpp", + coreDir .. "/contour-combiners.h", + coreDir .. "/DistanceMapping.cpp", + coreDir .. "/DistanceMapping.h", + coreDir .. "/EdgeColor.h", + coreDir .. "/edge-coloring.cpp", + coreDir .. "/edge-coloring.h", + coreDir .. "/EdgeHolder.cpp", + coreDir .. "/EdgeHolder.h", + coreDir .. "/edge-segments.cpp", + coreDir .. "/edge-segments.h", + coreDir .. "/edge-selectors.cpp", + coreDir .. "/edge-selectors.h", + coreDir .. "/equation-solver.cpp", + coreDir .. "/equation-solver.h", + coreDir .. "/export-svg.cpp", + coreDir .. "/export-svg.h", + coreDir .. "/generator-config.h", + coreDir .. "/MSDFErrorCorrection.h", + coreDir .. "/msdf-error-correction.h", + coreDir .. "/MSDFErrorCorrection.cpp", + coreDir .. "/msdf-error-correction.cpp", + coreDir .. "/msdfgen.cpp", + coreDir .. "/pixel-conversion.hpp", + coreDir .. "/Projection.cpp", + coreDir .. "/Projection.h", + coreDir .. "/Range.hpp", + coreDir .. "/rasterization.cpp", + coreDir .. "/rasterization.h", + coreDir .. "/render-sdf.cpp", + coreDir .. "/render-sdf.h", + coreDir .. "/save-bmp.h", + coreDir .. "/save-fl32.cpp", + coreDir .. "/save-fl32.h", + coreDir .. "/save-rgba.cpp", + coreDir .. "/save-rgba.h", + coreDir .. "/save-tiff.cpp", + coreDir .. "/save-tiff.h", + coreDir .. "/Scanline.cpp", + coreDir .. "/Scanline.h", + coreDir .. "/sdf-error-estimation.cpp", + coreDir .. "/sdf-error-estimation.h", + coreDir .. "/SDFTransformation.h", + coreDir .. "/Shape.cpp", + coreDir .. "/Shape.h", + coreDir .. "/shape-description.cpp", + coreDir .. "/shape-description.h", + coreDir .. "/ShapeDistanceFinder.h", + coreDir .. "/ShapeDistanceFinder.hpp", + coreDir .. "/SignedDistance.hpp", + coreDir .. "/Vector2.hp", + + extDir .. "/import-font.cpp", + extDir .. "/import-font.h", + extDir .. "/import-svg.cpp", + extDir .. "/import-svg.h", + extDir .. "/resolve-shape-geometry.cpp", + extDir .. "/resolve-shape-geometry.h", + extDir .. "/save-png.cpp", + extDir .. "/save-png.h", + } + + Solution.Util.SetDefines(defines) + Solution.Util.SetLinks(links) + Solution.Util.SetFiles(files) + Solution.Util.SetIncludes(dep.Path) +end) + +Solution.Util.CreateDep(dep.NameLow, dep.Dependencies, function() + local msdfgenDir = dep.Path .. "/msdfgen" + + Solution.Util.SetIncludes({ dep.Path, msdfgenDir }) + Solution.Util.SetLinks({ dep.Name }) +end) \ No newline at end of file diff --git a/Dependencies/msdfgen/msdfgen/.gitattributes b/Dependencies/msdfgen/msdfgen/.gitattributes new file mode 100644 index 00000000..176a458f --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/Dependencies/msdfgen/msdfgen/.gitignore b/Dependencies/msdfgen/msdfgen/.gitignore new file mode 100644 index 00000000..007846a3 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/.gitignore @@ -0,0 +1,32 @@ +/build/ +/Debug/ +/Release/ +/Release OpenMP/ +/Debug Library/ +/Release Library/ +/Release Library OpenMP/ +/x86/ +/x64/ +.vs/ +.vscode/ +.DS_Store +*.exe +*.zip +*.user +*.sdf +*.pdb +*.ipdb +*.iobj +*.suo +*.VC.opendb +*.VC.db +/bin/*.lib +/bin/msdfgen +output.png +render.png +CMakeUserPresets.json +out/ +/all-in-one/ +/build_xcode/ +/cmake-gen.bat +/line-ending-check.bat diff --git a/Dependencies/msdfgen/msdfgen/CHANGELOG.md b/Dependencies/msdfgen/msdfgen/CHANGELOG.md new file mode 100644 index 00000000..1fbc76d3 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/CHANGELOG.md @@ -0,0 +1,134 @@ + +## Version 1.12 (2024-05-18) + +- Added the possibility to specify asymmetrical distance range (`-arange`, `-apxrange`) +- Added the ability to export the shape into an SVG file (`-exportsvg`) +- Edge coloring no longer colors smooth contours white, which has been found suboptimal +- Fixed incorrect scaling of font glyph coordinates. To preserve backwards compatibility, the user has to enable the fix with an explicit additional argument: + - `-emnormalize` in standalone, `FONT_SCALING_EM_NORMALIZED` in API for coordinates in ems + - `-noemnormalize` in standalone, `FONT_SCALING_NONE` in API for raw integer coordinates + - The default (backwards-compatible) behavior will change in a future version; a warning will be displayed if neither option is set +- Added two new developer-friendly export image formats: RGBA and FL32 +- `-size` parameter renamed to `-dimensions` for clarity (old one will be kept for compatibility) +- `generate*SDF` functions now combine projection and range into a single argument (`SDFTransformation`) +- Conversion of floating point color values to 8-bit integers adjusted to match graphics hardware +- Improved edge deconvergence procedure and made sure that calling `Shape::normalize` a second time has no effect +- Fixed certain edge cases where Skia geometry preprocessing wouldn't make the geometry fully compliant +- The term "perpendicular distance" now used instead of "pseudo-distance" (PSDF instead of PseudoSDF in API) +- Fixed a bug in `savePng` where `fclose` could be called on null pointer +- Minor code improvements + +## Version 1.11 (2023-11-11) + +- Reworked SVG parser, which now supports multiple paths and other shapes - requires Skia +- Major performance improvements due to inlining certain low-level classes +- A limited version of the standalone executable can now be built without any dependencies +- Fixed `listFontVariationAxes` which previously reported incorrectly scaled values +- Fixed potential crash when generating SDF from an empty `Shape` +- Fixed a small bug in the error correction routine +- Errors now reported to `stderr` rather than `stdout` +- All command line arguments can now also be passed with two dashes instead of one +- Added `-version` argument to print the program's version +- `Shape` can now be loaded from a pointer to FreeType's `FT_Outline` +- Added hidden CMake options to selectively disable PNG, SVG, or variable font support +- Added CMake presets +- Other minor bug fixes + +## Version 1.10 (2023-01-15) + +- Switched to vcpkg as the primary dependency management system +- Switched to libpng as the primary PNG file encoder +- Parameters of variable fonts can be specified +- Fixed a bug that prevented glyph 0 to be specified in a glyphset + +### Version 1.9.2 (2021-12-01) + +- Improved detection of numerical errors in cubic equation solver +- Added -windingpreprocess option +- Fixed edge coloring not restored if lost during preprocessing + +### Version 1.9.1 (2021-07-09) + +- Fixed an edge case bug in the new MSDF error correction algorithm + +## Version 1.9 (2021-05-28) + +- Error correction of multi-channel distance fields has been completely reworked +- Added new edge coloring strategy that optimizes colors based on distances between edges +- Added some minor functions for the library API +- Minor code refactor and optimizations + +## Version 1.8 (2020-10-17) + +- Integrated the Skia library into the project, which is used to preprocess the shape geometry and eliminate any self-intersections and other irregularities previously unsupported by the software + - The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively. + - The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA` +- Significantly improved performance of the core algorithm by reusing results from previously computed pixels +- Introduced an additional error correction routine which eliminates MSDF artifacts by analytically predicting results of bilinear interpolation +- Added the possibility to load font glyphs by their index rather than a Unicode value (use the prefix `g` before the character code in `-font` argument) +- Added `-distanceshift` argument that can be used to adjust the center of the distance range in the output distance field +- Fixed several errors in the evaluation of curve distances +- Fixed an issue with paths containing convergent corners (those whose inner angle is zero) +- The algorithm for pseudo-distance computation slightly changed, fixing certain rare edge cases and improving consistency +- Added the ability to supply own `FT_Face` handle to the msdfgen library +- Minor refactor of the core algorithm + +### Version 1.7.1 (2020-03-09) + +- Fixed an edge case bug in scanline rasterization + +## Version 1.7 (2020-03-07) + +- Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel +- Distance fields can now be stored as uncompressed TIFF image files with floating point precision +- Bitmap class refactor - template argument split into data type and number of channels, bitmap reference classes introduced +- Added a secondary "ink trap" edge coloring heuristic, can be selected using `-coloringstrategy inktrap` +- Added computation of estimated rendering error for a given SDF +- Added computation of bounding box that includes sharp mitered corners +- The API for bounds computation of the `Shape` class changed for clarity +- Fixed several edge case bugs + +## Version 1.6 (2019-04-08) + +- Core algorithm rewritten to split up advanced edge selection logic into modular template arguments. +- Pseudo-distance evaluation reworked to eliminate discontinuities at the midpoint between edges. +- MSDF error correction reworked to also fix distances away from edges and consider diagonal pairs. Code simplified. +- Added scanline rasterization support for `Shape`. +- Added a scanline pass in the standalone version, which corrects the signs in the distance field according to the selected fill rule (`-fillrule`). Can be disabled using `-noscanline`. +- Fixed autoframe scaling, which previously caused the output to have unnecessary empty border. +- `-guessorder` switch no longer enabled by default, as the functionality is now provided by the scanline pass. +- Updated FreeType and other libraries, changed to static linkage +- Added 64-bit and static library builds to the Visual Studio solution + +## Version 1.5 (2017-07-23) + +- Fixed rounding error in cubic curve splitting. +- SVG parser fixes and support for additional path commands. +- Added CMake build script. + +## Version 1.4 (2017-02-09) + +- Reworked contour combining logic to support overlapping contours. Original algorithm preserved in functions with `_legacy` suffix, which are invoked by the new `-legacy` switch. +- Fixed a severe bug in cubic curve distance computation, where a control point lies at the endpoint. +- Standalone version now automatically detects if the input has the wrong orientation and adjusts the distance field accordingly. Can be disabled by `-keeporder` or `-reverseorder` switch. +- SVG parser fixes and improvements. + +## Version 1.3 (2016-12-07) + +- Fixed `-reverseorder` switch. +- Fixed glyph loading to use the proper method of acquiring outlines from FreeType. + +## Version 1.2 (2016-07-20) + +- Added option to specify that shape vertices are listed in reverse order (`-reverseorder`). +- Added option to set a seed for the edge coloring heuristic (-seed \), which can be used to adjust the output. +- Fixed parsing of glyph contours that start with a curve control point. + +## Version 1.1 (2016-05-08) + +- Switched to MIT license due to popular demand. +- Fixed SDF rendering anti-aliasing when the output is smaller than the distance field. + +## Version 1.0 (2016-04-28) + +- Project published. diff --git a/Dependencies/msdfgen/msdfgen/CMakeLists.txt b/Dependencies/msdfgen/msdfgen/CMakeLists.txt new file mode 100644 index 00000000..44e8fe0b --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/CMakeLists.txt @@ -0,0 +1,328 @@ + +cmake_minimum_required(VERSION 3.15) +include(cmake/version.cmake) + +option(MSDFGEN_CORE_ONLY "Only build the core library with no dependencies" OFF) +option(MSDFGEN_BUILD_STANDALONE "Build the msdfgen standalone executable" ON) +option(MSDFGEN_USE_VCPKG "Use vcpkg package manager to link project dependencies" ON) +option(MSDFGEN_USE_OPENMP "Build with OpenMP support for multithreaded code" OFF) +option(MSDFGEN_USE_CPP11 "Build with C++11 enabled" ON) +option(MSDFGEN_USE_SKIA "Build with the Skia library" ON) +option(MSDFGEN_INSTALL "Generate installation target" OFF) +option(MSDFGEN_DYNAMIC_RUNTIME "Link dynamic runtime library instead of static" OFF) +option(BUILD_SHARED_LIBS "Generate dynamic library files instead of static" OFF) + +if(MSDFGEN_CORE_ONLY AND MSDFGEN_USE_VCPKG) + message(STATUS "Option MSDFGEN_USE_VCPKG ignored due to MSDFGEN_CORE_ONLY - core has no dependencies") + set(MSDFGEN_USE_VCPKG OFF) +endif() + +get_property(MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) + message(STATUS "CMAKE_BUILD_TYPE not set, defaulting to Release") + set(CMAKE_BUILD_TYPE Release) +endif() + +if(MSDFGEN_USE_VCPKG) + # Make sure that vcpkg toolchain file is set + if(NOT CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{VCPKG_ROOT}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") + else() + message(SEND_ERROR "Vcpkg toolchain not configured. Either set VCPKG_ROOT environment variable or pass -DCMAKE_TOOLCHAIN_FILE=VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake to cmake") + endif() + endif() + # Default to statically linked vcpkg triplet on Windows + if(WIN32 AND NOT VCPKG_TARGET_TRIPLET AND NOT MSDFGEN_DYNAMIC_RUNTIME) + if(CMAKE_GENERATOR_PLATFORM MATCHES "64$" AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") + set(VCPKG_TARGET_TRIPLET "x64-windows-static") + elseif(CMAKE_GENERATOR_PLATFORM MATCHES "32$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x86") + set(VCPKG_TARGET_TRIPLET "x86-windows-static") + else() + if(CMAKE_GENERATOR_PLATFORM) + message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -DVCPKG_TARGET_TRIPLET=x64-windows-static or similar") + else() + message(WARNING "Vcpkg triplet not explicitly specified and could not be deduced. Recommend using -A to explicitly select platform (Win32 or x64)") + endif() + endif() + endif() + # Select project features + if(NOT MSDFGEN_VCPKG_FEATURES_SET) + set(VCPKG_MANIFEST_NO_DEFAULT_FEATURES ON) + if(NOT MSDFGEN_CORE_ONLY) + list(APPEND VCPKG_MANIFEST_FEATURES "extensions") + endif() + if(MSDFGEN_BUILD_STANDALONE) + list(APPEND VCPKG_MANIFEST_FEATURES "standalone") + endif() + if(MSDFGEN_USE_SKIA) + list(APPEND VCPKG_MANIFEST_FEATURES "geometry-preprocessing") + endif() + if(MSDFGEN_USE_OPENMP) + list(APPEND VCPKG_MANIFEST_FEATURES "openmp") + endif() + endif() +endif() + +# Version is specified in vcpkg.json +project(msdfgen VERSION ${MSDFGEN_VERSION} LANGUAGES CXX) + +if(MSDFGEN_DYNAMIC_RUNTIME) + set(MSDFGEN_MSVC_RUNTIME "MultiThreaded$<$:Debug>DLL") +else() + set(MSDFGEN_MSVC_RUNTIME "MultiThreaded$<$:Debug>") +endif() + +if(BUILD_SHARED_LIBS) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +if(MAX_WARNING_LEVEL) + if (MSVC) + add_compile_options(/W4) + else() + add_compile_options(-Wall -Wextra -Wpedantic) + endif() +endif() + +file(GLOB_RECURSE MSDFGEN_CORE_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "core/*.h" "core/*.hpp") +file(GLOB_RECURSE MSDFGEN_CORE_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "core/*.cpp") +file(GLOB_RECURSE MSDFGEN_EXT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/*.h" "ext/*.hpp") +file(GLOB_RECURSE MSDFGEN_EXT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "ext/*.cpp" "lib/*.cpp") + +# Core library +add_library(msdfgen-core "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" ${MSDFGEN_CORE_HEADERS} ${MSDFGEN_CORE_SOURCES}) +add_library(msdfgen::msdfgen-core ALIAS msdfgen-core) +set_target_properties(msdfgen-core PROPERTIES PUBLIC_HEADER "${MSDFGEN_CORE_HEADERS}") +set_property(TARGET msdfgen-core PROPERTY MSVC_RUNTIME_LIBRARY "${MSDFGEN_MSVC_RUNTIME}") +target_compile_definitions(msdfgen-core PUBLIC + MSDFGEN_VERSION=${MSDFGEN_VERSION} + MSDFGEN_VERSION_MAJOR=${MSDFGEN_VERSION_MAJOR} + MSDFGEN_VERSION_MINOR=${MSDFGEN_VERSION_MINOR} + MSDFGEN_VERSION_REVISION=${MSDFGEN_VERSION_REVISION} + MSDFGEN_COPYRIGHT_YEAR=${MSDFGEN_COPYRIGHT_YEAR} +) +target_include_directories(msdfgen-core INTERFACE + $ + $ +) +set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdfgen-core) + +if(MSDFGEN_USE_CPP11) + target_compile_features(msdfgen-core PUBLIC cxx_std_11) + target_compile_definitions(msdfgen-core PUBLIC MSDFGEN_USE_CPP11) +endif() + +if(MSDFGEN_USE_OPENMP) + # Note: Clang doesn't support OpenMP by default... + find_package(OpenMP REQUIRED COMPONENTS CXX) + target_compile_definitions(msdfgen-core PUBLIC MSDFGEN_USE_OPENMP) + target_link_libraries(msdfgen-core PUBLIC OpenMP::OpenMP_CXX) +endif() + +if(BUILD_SHARED_LIBS AND WIN32) + target_compile_definitions(msdfgen-core PRIVATE "MSDFGEN_PUBLIC=__declspec(dllexport)") + target_compile_definitions(msdfgen-core INTERFACE "MSDFGEN_PUBLIC=__declspec(dllimport)") +else() + target_compile_definitions(msdfgen-core PUBLIC MSDFGEN_PUBLIC=) +endif() + +# Extensions library +if(NOT MSDFGEN_CORE_ONLY) + if(NOT TARGET Freetype::Freetype) + find_package(Freetype REQUIRED) + endif() + if(NOT MSDFGEN_DISABLE_SVG AND NOT TARGET tinyxml2::tinyxml2) + find_package(tinyxml2 REQUIRED) + endif() + if(NOT MSDFGEN_DISABLE_PNG AND NOT TARGET PNG::PNG) + find_package(PNG REQUIRED) + endif() + + add_library(msdfgen-ext "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen-ext.h" ${MSDFGEN_EXT_HEADERS} ${MSDFGEN_EXT_SOURCES}) + add_library(msdfgen::msdfgen-ext ALIAS msdfgen-ext) + set_target_properties(msdfgen-ext PROPERTIES PUBLIC_HEADER "${MSDFGEN_EXT_HEADERS}") + set_property(TARGET msdfgen-ext PROPERTY MSVC_RUNTIME_LIBRARY "${MSDFGEN_MSVC_RUNTIME}") + target_compile_definitions(msdfgen-ext INTERFACE MSDFGEN_EXTENSIONS) + if(NOT MSDFGEN_DISABLE_SVG) + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_USE_TINYXML2) + target_link_libraries(msdfgen-ext PRIVATE tinyxml2::tinyxml2) + else() + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_DISABLE_SVG) + endif() + if(NOT MSDFGEN_DISABLE_PNG) + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_USE_LIBPNG) + target_link_libraries(msdfgen-ext PRIVATE PNG::PNG) + else() + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_DISABLE_PNG) + endif() + if(MSDFGEN_DISABLE_VARIABLE_FONTS) + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_DISABLE_VARIABLE_FONTS) + endif() + target_link_libraries(msdfgen-ext PRIVATE Freetype::Freetype msdfgen::msdfgen-core) + target_include_directories(msdfgen-ext + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdfgen-ext) + + if(MSDFGEN_USE_SKIA) + set(MSDFGEN_SKIA_LIB skia) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) + if(NOT TARGET skia) + if(MSDFGEN_USE_VCPKG) + find_package(unofficial-skia REQUIRED) + set(MSDFGEN_SKIA_LIB unofficial::skia::skia) + else() + find_package(skia REQUIRED) + endif() + endif() + target_compile_features(msdfgen-ext PUBLIC cxx_std_17) + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_USE_SKIA) + target_link_libraries(msdfgen-ext PRIVATE Threads::Threads ${MSDFGEN_SKIA_LIB}) + endif() + + if(BUILD_SHARED_LIBS AND WIN32) + target_compile_definitions(msdfgen-ext PRIVATE "MSDFGEN_EXT_PUBLIC=__declspec(dllexport)") + target_compile_definitions(msdfgen-ext INTERFACE "MSDFGEN_EXT_PUBLIC=__declspec(dllimport)") + else() + target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_EXT_PUBLIC=) + endif() + + add_library(msdfgen-full INTERFACE) + add_library(msdfgen::msdfgen ALIAS msdfgen-full) + target_link_libraries(msdfgen-full INTERFACE msdfgen::msdfgen-core msdfgen::msdfgen-ext) +else() + add_library(msdfgen::msdfgen ALIAS msdfgen-core) +endif() + +# Standalone executable +if(MSDFGEN_BUILD_STANDALONE) + set(MSDFGEN_STANDALONE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") + if(MSVC) + set(MSDFGEN_STANDALONE_SOURCES ${MSDFGEN_STANDALONE_SOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.rc") + endif() + add_executable(msdfgen ${MSDFGEN_STANDALONE_SOURCES}) + target_compile_definitions(msdfgen PUBLIC MSDFGEN_STANDALONE) + target_compile_definitions(msdfgen PRIVATE MSDFGEN_VERSION_UNDERLINE=${MSDFGEN_VERSION_UNDERLINE}) + set_property(TARGET msdfgen PROPERTY MSVC_RUNTIME_LIBRARY "${MSDFGEN_MSVC_RUNTIME}") + target_link_libraries(msdfgen PRIVATE msdfgen::msdfgen) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT msdfgen) +endif() + +# Hide ZERO_CHECK and ALL_BUILD targets +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER meta) + +# Installation +if(MSDFGEN_INSTALL) + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + set(MSDFGEN_CONFIG_PATH "lib/cmake/msdfgen") + + # Generate msdfgen-config.h + if(BUILD_SHARED_LIBS AND WIN32) + set(MSDFGEN_PUBLIC_MACRO_VALUE " __declspec(dllimport)") + else() + set(MSDFGEN_PUBLIC_MACRO_VALUE "") + endif() + set(MSDFGEN_ADDITIONAL_DEFINES "") + if(MSDFGEN_USE_CPP11) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_USE_CPP11") + endif() + if(MSDFGEN_USE_OPENMP) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_USE_OPENMP") + endif() + if(NOT MSDFGEN_CORE_ONLY) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_EXTENSIONS") + if(MSDFGEN_USE_SKIA) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_USE_SKIA") + endif() + if(NOT MSDFGEN_DISABLE_SVG) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_USE_TINYXML2") + else() + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_DISABLE_SVG") + endif() + if(NOT MSDFGEN_DISABLE_PNG) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_USE_LIBPNG") + else() + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_DISABLE_PNG") + endif() + if(MSDFGEN_DISABLE_VARIABLE_FONTS) + set(MSDFGEN_ADDITIONAL_DEFINES "${MSDFGEN_ADDITIONAL_DEFINES}\n#define MSDFGEN_DISABLE_VARIABLE_FONTS") + endif() + endif() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/msdfgen-config.h.in" msdfgen-config.h) + + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/msdfgenConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion + ) + + configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/msdfgenConfig.cmake.in" + ${MSDFGEN_CONFIG_PATH}/msdfgenConfig.cmake + INSTALL_DESTINATION ${MSDFGEN_CONFIG_PATH} + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/msdfgenConfig.cmake.in" + msdfgenConfig.cmake + @ONLY + ) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/msdfgen-config.h" DESTINATION include/msdfgen) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/msdfgen-config.h" DESTINATION include/msdfgen/msdfgen) + install(TARGETS msdfgen-core EXPORT msdfgenTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/msdfgen/core + ) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen.h" DESTINATION include/msdfgen) + if(MSVC AND BUILD_SHARED_LIBS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) + endif() + + if(NOT MSDFGEN_CORE_ONLY) + install(TARGETS msdfgen-ext EXPORT msdfgenTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/msdfgen/ext + ) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/msdfgen-ext.h" DESTINATION include/msdfgen) + if(MSVC AND BUILD_SHARED_LIBS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) + endif() + install(TARGETS msdfgen-full EXPORT msdfgenTargets) + endif() + + export(EXPORT msdfgenTargets NAMESPACE msdfgen:: FILE "${CMAKE_CURRENT_BINARY_DIR}/msdfgenTargets.cmake") + install(EXPORT msdfgenTargets FILE msdfgenTargets.cmake NAMESPACE msdfgen:: DESTINATION ${MSDFGEN_CONFIG_PATH}) + + if(MSDFGEN_BUILD_STANDALONE) + install(TARGETS msdfgen EXPORT msdfgenBinaryTargets DESTINATION ${CMAKE_INSTALL_BINDIR}) + if(MSVC) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) + endif() + export(EXPORT msdfgenBinaryTargets NAMESPACE msdfgen-standalone:: FILE "${CMAKE_CURRENT_BINARY_DIR}/msdfgenBinaryTargets.cmake") + install(EXPORT msdfgenBinaryTargets FILE msdfgenBinaryTargets.cmake NAMESPACE msdfgen-standalone:: DESTINATION ${MSDFGEN_CONFIG_PATH}) + endif() + + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${MSDFGEN_CONFIG_PATH}/msdfgenConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/msdfgenConfigVersion.cmake" + DESTINATION ${MSDFGEN_CONFIG_PATH} + ) +endif() diff --git a/Dependencies/msdfgen/msdfgen/CMakePresets.json b/Dependencies/msdfgen/msdfgen/CMakePresets.json new file mode 100644 index 00000000..f6f24241 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/CMakePresets.json @@ -0,0 +1,239 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "include": [ + "cmake/CMakePresets.json" + ], + "configurePresets": [ + { + "name": "win64", + "displayName": "Windows x64 default config (static, vcpkg, Skia)", + "inherits": [ "win64-base", "vcpkg", "skia" ] + }, { + "name": "win32", + "displayName": "Windows x86 default config (static, vcpkg, Skia)", + "inherits": [ "win32-base", "vcpkg", "skia" ] + }, { + "name": "win64-omp", + "displayName": "Windows x64 config with OpenMP (static, vcpkg, Skia)", + "inherits": [ "win64-base", "openmp", "vcpkg", "skia" ], + "binaryDir": "${sourceDir}/build/win64-omp" + }, { + "name": "win32-omp", + "displayName": "Windows x86 config with OpenMP (static, vcpkg, Skia)", + "inherits": [ "win32-base", "openmp", "vcpkg", "skia" ], + "binaryDir": "${sourceDir}/build/win32-omp" + }, { + "name": "win64-dynamic", + "displayName": "Windows x64 dynamic config (vcpkg, Skia)", + "inherits": [ "win64-base", "vcpkg", "skia", "dynamic-runtime", "dynamic-lib" ], + "binaryDir": "${sourceDir}/build/win64-dynamic" + }, { + "name": "win32-dynamic", + "displayName": "Windows x86 dynamic config (vcpkg, Skia)", + "inherits": [ "win32-base", "vcpkg", "skia", "dynamic-runtime", "dynamic-lib" ], + "binaryDir": "${sourceDir}/build/win32-dynamic" + }, { + "name": "win64-no-skia", + "displayName": "Windows x64 config without Skia (static, vcpkg)", + "inherits": [ "win64-base", "vcpkg", "no-skia" ] + }, { + "name": "win32-no-skia", + "displayName": "Windows x86 config without Skia (static, vcpkg)", + "inherits": [ "win32-base", "vcpkg", "no-skia" ] + }, { + "name": "win64-core", + "displayName": "Windows x64 core-only config (static)", + "inherits": [ "win64-base", "core-only" ], + "binaryDir": "${sourceDir}/build/win64-core" + }, { + "name": "win32-core", + "displayName": "Windows x86 core-only config (static)", + "inherits": [ "win32-base", "core-only" ], + "binaryDir": "${sourceDir}/build/win32-core" + }, + + { + "name": "osx-vcpkg-rel", + "displayName": "Mac OS release config with vcpkg and Skia (static)", + "inherits": [ "osx-rel-base", "vcpkg", "skia" ] + }, { + "name": "osx-vcpkg-dbg", + "displayName": "Mac OS debug config with vcpkg and Skia (static)", + "inherits": [ "osx-dbg-base", "vcpkg", "skia" ] + }, { + "name": "osx-no-skia-rel", + "displayName": "Mac OS release config with system libraries and no Skia (static, install)", + "inherits": [ "osx-rel-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "osx-no-skia-dbg", + "displayName": "Mac OS debug config with system libraries and no Skia (static, install)", + "inherits": [ "osx-dbg-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "osx-core-rel", + "displayName": "Mac OS release core-only config (static, install)", + "inherits": [ "osx-rel-base", "core-only", "install" ], + "binaryDir": "${sourceDir}/build/osx-core-rel" + }, { + "name": "osx-core-dbg", + "displayName": "Mac OS debug core-only config (static, install)", + "inherits": [ "osx-dbg-base", "core-only", "install" ], + "binaryDir": "${sourceDir}/build/osx-core-dbg" + }, + + { + "name": "linux-vcpkg-rel", + "displayName": "Linux release config with vcpkg and Skia (static)", + "inherits": [ "linux-rel-base", "vcpkg", "skia" ] + }, { + "name": "linux-vcpkg-dbg", + "displayName": "Linux debug config with vcpkg and Skia (static)", + "inherits": [ "linux-dbg-base", "vcpkg", "skia" ] + }, { + "name": "linux-no-skia-rel", + "displayName": "Linux release config with system libraries and no Skia (static, install)", + "inherits": [ "linux-rel-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "linux-no-skia-dbg", + "displayName": "Linux debug config with system libraries and no Skia (static, install)", + "inherits": [ "linux-dbg-base", "no-vcpkg", "no-skia", "install" ] + }, { + "name": "linux-core-rel", + "displayName": "Linux release core-only config (static, install)", + "inherits": [ "linux-rel-base", "core-only", "install" ], + "binaryDir": "${sourceDir}/build/linux-core-rel" + }, { + "name": "linux-core-dbg", + "displayName": "Linux debug core-only config (static, install)", + "inherits": [ "linux-dbg-base", "core-only", "install" ], + "binaryDir": "${sourceDir}/build/linux-core-dbg" + } + ], + "buildPresets": [ + { + "name": "win64-rel", + "configurePreset": "win64", + "configuration": "Release" + }, { + "name": "win64-dbg", + "configurePreset": "win64", + "configuration": "Debug" + }, { + "name": "win32-rel", + "configurePreset": "win32", + "configuration": "Release" + }, { + "name": "win32-dbg", + "configurePreset": "win32", + "configuration": "Debug" + }, { + "name": "win64-omp-rel", + "configurePreset": "win64-omp", + "configuration": "Release" + }, { + "name": "win64-omp-dbg", + "configurePreset": "win64-omp", + "configuration": "Debug" + }, { + "name": "win32-omp-rel", + "configurePreset": "win32-omp", + "configuration": "Release" + }, { + "name": "win32-omp-dbg", + "configurePreset": "win32-omp", + "configuration": "Debug" + }, { + "name": "win64-dynamic-rel", + "configurePreset": "win64-dynamic", + "configuration": "Release" + }, { + "name": "win64-dynamic-dbg", + "configurePreset": "win64-dynamic", + "configuration": "Debug" + }, { + "name": "win32-dynamic-rel", + "configurePreset": "win32-dynamic", + "configuration": "Release" + }, { + "name": "win32-dynamic-dbg", + "configurePreset": "win32-dynamic", + "configuration": "Debug" + }, { + "name": "win64-no-skia-rel", + "configurePreset": "win64-no-skia", + "configuration": "Release" + }, { + "name": "win64-no-skia-dbg", + "configurePreset": "win64-no-skia", + "configuration": "Debug" + }, { + "name": "win32-no-skia-rel", + "configurePreset": "win32-no-skia", + "configuration": "Release" + }, { + "name": "win32-no-skia-dbg", + "configurePreset": "win32-no-skia", + "configuration": "Debug" + }, { + "name": "win64-core-rel", + "configurePreset": "win64-core", + "configuration": "Release" + }, { + "name": "win64-core-dbg", + "configurePreset": "win64-core", + "configuration": "Debug" + }, { + "name": "win32-core-rel", + "configurePreset": "win32-core", + "configuration": "Release" + }, { + "name": "win32-core-dbg", + "configurePreset": "win32-core", + "configuration": "Debug" + }, + + { + "name": "osx-vcpkg-rel", + "configurePreset": "osx-vcpkg-rel" + }, { + "name": "osx-vcpkg-dbg", + "configurePreset": "osx-vcpkg-dbg" + }, { + "name": "osx-no-skia-rel", + "configurePreset": "osx-no-skia-rel" + }, { + "name": "osx-no-skia-dbg", + "configurePreset": "osx-no-skia-dbg" + }, { + "name": "osx-core-rel", + "configurePreset": "osx-core-rel" + }, { + "name": "osx-core-dbg", + "configurePreset": "osx-core-dbg" + }, + + { + "name": "linux-vcpkg-rel", + "configurePreset": "linux-vcpkg-rel" + }, { + "name": "linux-vcpkg-dbg", + "configurePreset": "linux-vcpkg-dbg" + }, { + "name": "linux-no-skia-rel", + "configurePreset": "linux-no-skia-rel" + }, { + "name": "linux-no-skia-dbg", + "configurePreset": "linux-no-skia-dbg" + }, { + "name": "linux-core-rel", + "configurePreset": "linux-core-rel" + }, { + "name": "linux-core-dbg", + "configurePreset": "linux-core-dbg" + } + ] +} diff --git a/Dependencies/msdfgen/msdfgen/LICENSE.txt b/Dependencies/msdfgen/msdfgen/LICENSE.txt new file mode 100644 index 00000000..d5b31742 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014 - 2024 Viktor Chlumsky + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Dependencies/msdfgen/msdfgen/README.md b/Dependencies/msdfgen/msdfgen/README.md new file mode 100644 index 00000000..8e8cede9 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/README.md @@ -0,0 +1,215 @@ +# Multi-channel signed distance field generator + +This is a utility for generating signed distance fields from vector shapes and font glyphs, +which serve as a texture representation that can be used in real-time graphics to efficiently reproduce said shapes. +Although it can also be used to generate conventional signed distance fields best known from +[this Valve paper](https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf) +and perpendicular distance fields, its primary purpose is to generate multi-channel distance fields, +using a method I have developed. Unlike monochrome distance fields, they have the ability +to reproduce sharp corners almost perfectly by utilizing all three color channels. + +The following comparison demonstrates the improvement in image quality. + +![demo-msdf16](https://user-images.githubusercontent.com/18639794/106391899-e37ebe80-63ef-11eb-988b-4764004bb196.png) +![demo-sdf16](https://user-images.githubusercontent.com/18639794/106391905-e679af00-63ef-11eb-96c3-993176330911.png) +![demo-sdf32](https://user-images.githubusercontent.com/18639794/106391906-e7aadc00-63ef-11eb-8f84-d402d0dd9174.png) + +- To learn more about this method, you can read my [Master's thesis](https://github.com/Chlumsky/msdfgen/files/3050967/thesis.pdf). +- Check out my [MSDF-Atlas-Gen](https://github.com/Chlumsky/msdf-atlas-gen) if you want to generate entire font atlases for text rendering. +- See what's new in the [changelog](CHANGELOG.md). + +## Getting started + +The project can be used either as a library or as a console program. It is divided into two parts, **[core](core)** +and **[extensions](ext)**. The core module has no dependencies and only uses bare C++. It contains all +key data structures and algorithms, which can be accessed through the [msdfgen.h](msdfgen.h) header. +Extensions contain utilities for loading fonts and SVG files, as well as saving PNG images. +Those are exposed by the [msdfgen-ext.h](msdfgen-ext.h) header. This module uses +[FreeType](https://freetype.org/), +[TinyXML2](https://www.grinninglizard.com/tinyxml2/), +[libpng](http://www.libpng.org/pub/png/libpng.html), +and (optionally) [Skia](https://skia.org/). + +Additionally, there is the [main.cpp](main.cpp), which wraps the functionality into +a comprehensive standalone console program. To start using the program immediately, +there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdfgen/releases). +To use the project as a library, you may install it via the [vcpkg](https://vcpkg.io) package manager as +``` +vcpkg install msdfgen +``` +Or, to build the project from source, you may use the included [CMake script](CMakeLists.txt). +In its default configuration, it requires [vcpkg](https://vcpkg.io) as the provider for third-party library dependencies. +If you set the environment variable `VCPKG_ROOT` to the vcpkg directory, +the CMake configuration will take care of fetching all required packages from vcpkg. + +## Console commands + +The standalone program is executed as +``` +msdfgen.exe +``` +where only the input specification is required. + +Mode can be one of: + - **sdf** – generates a conventional monochrome (true) signed distance field. + - **psdf** – generates a monochrome signed perpendicular distance field. + - **msdf** (default) – generates a multi-channel signed distance field using my new method. + - **mtsdf** – generates a combined multi-channel and true signed distance field in the alpha channel. + +The input can be specified as one of: + - **-font \ \** – to load a glyph from a font file. + Character code can be expressed as either a decimal (63) or hexadecimal (0x3F) Unicode value, or an ASCII character + in single quotes ('?'). + - **-svg \** – to load an SVG file. Note that only the last vector path in the file will be used. + - **-shapedesc \**, -defineshape \, -stdin – to load a text description of the shape + from either a file, the next argument, or the standard input, respectively. Its syntax is documented further down. + +The complete list of available options can be printed with **-help**. +Some of the important ones are: + - **-o \** – specifies the output file name. The desired format will be deduced from the extension + (png, bmp, tiff, rgba, fl32, txt, bin). Otherwise, use -format. + - **-dimensions \ \** – specifies the dimensions of the output distance field (in pixels). + - **-range \**, **-pxrange \** – specifies the width of the range around the shape + between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly. + - **-scale \** – sets the scale used to convert shape units to distance field pixels. + - **-translate \ \** – sets the translation of the shape in shape units. Otherwise the origin (0, 0) + lies in the bottom left corner. + - **-autoframe** – automatically frames the shape to fit the distance field. If the output must be precisely aligned, + you should manually position it using -translate and -scale instead. + - **-angle \** – specifies the maximum angle to be considered a corner. + Can be expressed in radians (3.0) or degrees with D at the end (171.9D). + - **-testrender \ \ \** - tests the generated distance field by using it to render an image + of the original shape into a PNG file with the specified dimensions. Alternatively, -testrendermulti renders + an image without combining the color channels, and may give you an insight in how the multi-channel distance field works. + - **-exportshape \** - saves the text description of the shape with edge coloring to the specified file. + This can be later edited and used as input through -shapedesc. + - **-printmetrics** – prints some useful information about the shape's layout. + +For example, +``` +msdfgen.exe msdf -font C:\Windows\Fonts\arialbd.ttf 'M' -o msdf.png -dimensions 32 32 -pxrange 4 -autoframe -testrender render.png 1024 1024 +``` + +will take the glyph capital M from the Arial Bold typeface, generate a 32×32 multi-channel distance field +with a 4 pixels wide distance range, store it into msdf.png, and create a test render of the glyph as render.png. + +**Note:** Do not use `-autoframe` to generate character maps! It is intended as a quick preview only. + +## Library API + +If you choose to use this utility inside your own program, there are a few simple steps you need to perform +in order to generate a distance field. Please note that all classes and functions are in the `msdfgen` namespace. + + - Acquire a `Shape` object. You can either load it via `loadGlyph` or `loadSvgShape`, or construct it manually. + It consists of closed contours, which in turn consist of edges. An edge is represented by a `LinearEdge`, `QuadraticEdge`, + or `CubicEdge`. You can construct them from two endpoints and 0 to 2 Bézier control points. + - Normalize the shape using its `normalize` method and assign colors to edges if you need a multi-channel SDF. + This can be performed automatically using the `edgeColoringSimple` (or other) heuristic, or manually by setting each edge's + `color` member. Keep in mind that at least two color channels must be turned on in each edge. + - Call `generateSDF`, `generatePSDF`, `generateMSDF`, or `generateMTSDF` to generate a distance field into a floating point + `Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, `saveTiff`, etc. + - You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit` + on the distance field beforehand to simulate the standard 8 bits/channel image format. + +Example: +```c++ +#include "msdfgen.h" +#include "msdfgen-ext.h" + +using namespace msdfgen; + +int main() { + FreetypeHandle *ft = initializeFreetype(); + if (ft) { + FontHandle *font = loadFont(ft, "C:\\Windows\\Fonts\\arialbd.ttf"); + if (font) { + Shape shape; + if (loadGlyph(shape, font, 'A')) { + shape.normalize(); + // max. angle + edgeColoringSimple(shape, 3.0); + // output width, height + Bitmap msdf(32, 32); + // scale, translation + SDFTransformation t(Projection(1.0, Vector2(4.0, 4.0)), Range(4.0)); + generateMSDF(msdf, shape, t); + savePng(msdf, "output.png"); + } + destroyFont(font); + } + deinitializeFreetype(ft); + } + return 0; +} + +``` + +## Using a multi-channel distance field + +Using a multi-channel distance field generated by this program is similarly simple to how a monochrome distance field is used. +The only additional operation is computing the **median** of the three channels inside the fragment shader, +right after sampling the distance field. This signed distance value can then be used the same way as usual. + +The following is an example GLSL fragment shader with anti-aliasing: + +```glsl +in vec2 texCoord; +out vec4 color; +uniform sampler2D msdf; +uniform vec4 bgColor; +uniform vec4 fgColor; + +float median(float r, float g, float b) { + return max(min(r, g), min(max(r, g), b)); +} + +void main() { + vec3 msd = texture(msdf, texCoord).rgb; + float sd = median(msd.r, msd.g, msd.b); + float screenPxDistance = screenPxRange()*(sd - 0.5); + float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); + color = mix(bgColor, fgColor, opacity); +} +``` + +Here, `screenPxRange()` represents the distance field range in output screen pixels. For example, if the pixel range was set to 2 +when generating a 32x32 distance field, and it is used to draw a quad that is 72x72 pixels on the screen, +it should return 4.5 (because 72/32 * 2 = 4.5). +**For 2D rendering, this can generally be replaced by a precomputed uniform value.** + +For rendering in a **3D perspective only**, where the texture scale varies across the screen, +you may want to implement this function with fragment derivatives in the following way. +I would suggest precomputing `unitRange` as a uniform variable instead of `pxRange` for better performance. + +```glsl +uniform float pxRange; // set to distance field's pixel range + +float screenPxRange() { + vec2 unitRange = vec2(pxRange)/vec2(textureSize(msdf, 0)); + vec2 screenTexSize = vec2(1.0)/fwidth(texCoord); + return max(0.5*dot(unitRange, screenTexSize), 1.0); +} +``` + +`screenPxRange()` must never be lower than 1. If it is lower than 2, there is a high probability that the anti-aliasing will fail +and you may want to re-generate your distance field with a wider range. + +## Shape description syntax + +The text shape description has the following syntax. + - Each closed contour is enclosed by braces: `{ } { }` + - Each point (and control point) is written as two real numbers separated by a comma. + - Points in a contour are separated with semicolons. + - The last point of each contour must be equal to the first, or the symbol `#` can be used, which represents the first point. + - There can be an edge segment specification between any two points, also separated by semicolons. + This can include the edge's color (`c`, `m`, `y` or `w`) and/or one or two Bézier curve control points inside parentheses. + +For example, +``` +{ -1, -1; m; -1, +1; y; +1, +1; m; +1, -1; y; # } +``` +would represent a square with magenta and yellow edges, +``` +{ 0, 1; (+1.6, -0.8; -1.6, -0.8); # } +``` +is a teardrop shape formed by a single cubic Bézier curve. diff --git a/Dependencies/msdfgen/msdfgen/build-release.bat b/Dependencies/msdfgen/msdfgen/build-release.bat new file mode 100644 index 00000000..855da802 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/build-release.bat @@ -0,0 +1,96 @@ +@echo off +setlocal +pushd "%~dp0" + +if "%VCVARSALL%"=="" set "VCVARSALL=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" +if "%VCTOOLSET%"=="" set "VCTOOLSET=VC143" + +if not exist "%VCVARSALL%" ( + echo vcvarsall.bat not found, set VCVARSALL to its path + exit /b 1 +) + +if "%1"=="" ( + echo No version specified, using current + set "version=current" +) else ( + set "version=%1" +) +set "builddir=%~dp0\build\release-%version%" + +if exist "%builddir%" ( + echo Deleting contents of %builddir% + rd /s /q "%builddir%" +) + +cmake --preset win32 -B "%builddir%\build-win32" +cmake --preset win32-omp -B "%builddir%\build-win32-omp" +cmake --preset win64 -B "%builddir%\build-win64" +cmake --preset win64-omp -B "%builddir%\build-win64-omp" + +cmake --build "%builddir%\build-win32" --config Release +cmake --build "%builddir%\build-win32-omp" --config Release +cmake --build "%builddir%\build-win64" --config Release +cmake --build "%builddir%\build-win64-omp" --config Release + +mkdir "%builddir%\rel-win32\msdfgen" +mkdir "%builddir%\rel-win32-omp\msdfgen" +mkdir "%builddir%\rel-win64\msdfgen" +mkdir "%builddir%\rel-win64-omp\msdfgen" + +copy "%builddir%\build-win32\Release\msdfgen.exe" "%builddir%\rel-win32\msdfgen" +copy "%builddir%\build-win32-omp\Release\msdfgen.exe" "%builddir%\rel-win32-omp\msdfgen" +copy "%builddir%\build-win64\Release\msdfgen.exe" "%builddir%\rel-win64\msdfgen" +copy "%builddir%\build-win64-omp\Release\msdfgen.exe" "%builddir%\rel-win64-omp\msdfgen" + +echo msdfgen.exe -defineshape "{ 1471,0; 1149,0; 1021,333; 435,333; 314,0; 0,0; 571,1466; 884,1466; # }{ 926,580; 724,1124; 526,580; # }" -size 16 16 -autoframe -testrender render.png 1024 1024 > "%builddir%\example.bat" + +copy "%builddir%\example.bat" "%builddir%\rel-win32\msdfgen" +copy "%builddir%\example.bat" "%builddir%\rel-win32-omp\msdfgen" +copy "%builddir%\example.bat" "%builddir%\rel-win64\msdfgen" +copy "%builddir%\example.bat" "%builddir%\rel-win64-omp\msdfgen" + +call "%VCVARSALL%" x64 + +set "omp32dll=%VCToolsRedistDir%\x86\Microsoft.%VCTOOLSET%.OPENMP\vcomp140.dll" +set "omp64dll=%VCToolsRedistDir%\x64\Microsoft.%VCTOOLSET%.OPENMP\vcomp140.dll" + +if not exist "%omp32dll%" ( + echo vcomp140.dll [x86] not found, make sure to set VCTOOLSET or update this script + exit /b 1 +) +if not exist "%omp64dll%" ( + echo vcomp140.dll [x64] not found, make sure to set VCTOOLSET or update this script + exit /b 1 +) + +copy "%omp32dll%" "%builddir%\rel-win32-omp\msdfgen" +copy "%omp64dll%" "%builddir%\rel-win64-omp\msdfgen" + +if not exist "C:\Program Files\7-Zip\7z.exe" ( + echo 7-Zip not found, you have to package it manually + exit /b 0 +) + +pushd "%builddir%\rel-win32" +"C:\Program Files\7-Zip\7z.exe" a "..\msdfgen-%version%-win32.zip" msdfgen +cd msdfgen +call example.bat +popd +pushd "%builddir%\rel-win32-omp" +"C:\Program Files\7-Zip\7z.exe" a "..\msdfgen-%version%-win32-openmp.zip" msdfgen +cd msdfgen +call example.bat +popd +pushd "%builddir%\rel-win64" +"C:\Program Files\7-Zip\7z.exe" a "..\msdfgen-%version%-win64.zip" msdfgen +cd msdfgen +call example.bat +popd +pushd "%builddir%\rel-win64-omp" +"C:\Program Files\7-Zip\7z.exe" a "..\msdfgen-%version%-win64-openmp.zip" msdfgen +cd msdfgen +call example.bat +popd + +popd diff --git a/Dependencies/msdfgen/msdfgen/cmake/CMakePresets.json b/Dependencies/msdfgen/msdfgen/cmake/CMakePresets.json new file mode 100644 index 00000000..e30f167a --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/cmake/CMakePresets.json @@ -0,0 +1,170 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "configurePresets": [ + { + "name": "release-only", + "displayName": "Release only configuration", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, { + "name": "debug-only", + "displayName": "Debug only configuration", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, { + "name": "win64-base", + "displayName": "Windows 64-bit base configuration", + "hidden": true, + "architecture": "x64", + "binaryDir": "${sourceDir}/build/win64", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { + "name": "win32-base", + "displayName": "Windows 32-bit base configuration", + "hidden": true, + "architecture": "Win32", + "binaryDir": "${sourceDir}/build/win32", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { + "name": "osx-base", + "displayName": "Mac OS base configuration", + "hidden": true, + "binaryDir": "${sourceDir}/build/osx", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, { + "name": "osx-rel-base", + "displayName": "Mac OS base release configuration", + "inherits": [ "osx-base", "release-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/osx-rel" + }, { + "name": "osx-dbg-base", + "displayName": "Mac OS base debug configuration", + "inherits": [ "osx-base", "debug-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/osx-dbg" + }, { + "name": "linux-base", + "displayName": "Linux base configuration", + "hidden": true, + "binaryDir": "${sourceDir}/build/linux", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, { + "name": "linux-rel-base", + "displayName": "Linux base release configuration", + "inherits": [ "linux-base", "release-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/linux-rel" + }, { + "name": "linux-dbg-base", + "displayName": "Linux base debug configuration", + "inherits": [ "linux-base", "debug-only" ], + "hidden": true, + "binaryDir": "${sourceDir}/build/linux-dbg" + }, { + "name": "core-only", + "displayName": "Configuration with extensions disabled", + "hidden": true, + "cacheVariables": { + "MSDFGEN_CORE_ONLY": "ON", + "MSDFGEN_USE_VCPKG": "OFF", + "MSDFGEN_USE_SKIA": "OFF" + } + }, { + "name": "vcpkg", + "displayName": "Configuration with vcpkg as dependency management system", + "hidden": true, + "cacheVariables": { + "MSDFGEN_USE_VCPKG": "ON" + } + }, { + "name": "no-vcpkg", + "displayName": "Configuration with dependencies not managed by vcpkg", + "hidden": true, + "cacheVariables": { + "MSDFGEN_USE_VCPKG": "OFF" + } + }, { + "name": "openmp", + "displayName": "Configuration with OpenMP enabled", + "hidden": true, + "cacheVariables": { + "MSDFGEN_USE_OPENMP": "ON" + } + }, { + "name": "skia", + "displayName": "Configuration with Skia geometry preprocessing", + "hidden": true, + "cacheVariables": { + "MSDFGEN_USE_SKIA": "ON" + } + }, { + "name": "no-skia", + "displayName": "Configuration without Skia geometry preprocessing", + "hidden": true, + "cacheVariables": { + "MSDFGEN_USE_SKIA": "OFF" + } + }, { + "name": "install", + "displayName": "Configuration with installation targets", + "hidden": true, + "cacheVariables": { + "MSDFGEN_INSTALL": "ON" + } + }, { + "name": "static-runtime", + "displayName": "Configuration that links against the static runtime", + "hidden": true, + "cacheVariables": { + "MSDFGEN_DYNAMIC_RUNTIME": "OFF" + } + }, { + "name": "dynamic-runtime", + "displayName": "Configuration that links against the dynamic runtime", + "hidden": true, + "cacheVariables": { + "MSDFGEN_DYNAMIC_RUNTIME": "ON" + } + }, { + "name": "static-lib", + "displayName": "Configuration that builds and links msdfgen statically", + "hidden": true, + "cacheVariables": { + "BUILD_SHARED_LIBS": "OFF" + } + }, { + "name": "dynamic-lib", + "displayName": "Configuration that builds and links msdfgen dynamically", + "hidden": true, + "cacheVariables": { + "BUILD_SHARED_LIBS": "ON" + } + } + ] +} diff --git a/Dependencies/msdfgen/msdfgen/cmake/msdfgen-config.h.in b/Dependencies/msdfgen/msdfgen/cmake/msdfgen-config.h.in new file mode 100644 index 00000000..4959f6b2 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/cmake/msdfgen-config.h.in @@ -0,0 +1,12 @@ + +#pragma once + +#define MSDFGEN_PUBLIC${MSDFGEN_PUBLIC_MACRO_VALUE} +#define MSDFGEN_EXT_PUBLIC${MSDFGEN_PUBLIC_MACRO_VALUE} + +#define MSDFGEN_VERSION ${MSDFGEN_VERSION} +#define MSDFGEN_VERSION_MAJOR ${MSDFGEN_VERSION_MAJOR} +#define MSDFGEN_VERSION_MINOR ${MSDFGEN_VERSION_MINOR} +#define MSDFGEN_VERSION_REVISION ${MSDFGEN_VERSION_REVISION} +#define MSDFGEN_COPYRIGHT_YEAR ${MSDFGEN_COPYRIGHT_YEAR} +${MSDFGEN_ADDITIONAL_DEFINES} diff --git a/Dependencies/msdfgen/msdfgen/cmake/msdfgenConfig.cmake.in b/Dependencies/msdfgen/msdfgen/cmake/msdfgenConfig.cmake.in new file mode 100644 index 00000000..df110577 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/cmake/msdfgenConfig.cmake.in @@ -0,0 +1,48 @@ + +include(CMakeFindDependencyMacro) + +set(MSDFGEN_CORE_ONLY @MSDFGEN_CORE_ONLY@) +set(MSDFGEN_USE_VCPKG @MSDFGEN_USE_VCPKG@) +set(MSDFGEN_USE_OPENMP @MSDFGEN_USE_OPENMP@) +set(MSDFGEN_USE_SKIA @MSDFGEN_USE_SKIA@) +set(MSDFGEN_STANDALONE_AVAILABLE @MSDFGEN_BUILD_STANDALONE@) + +if(NOT MSDFGEN_CORE_ONLY) + find_dependency(Freetype REQUIRED) + find_dependency(tinyxml2 REQUIRED) + find_dependency(PNG REQUIRED) +endif() +if(MSDFGEN_USE_SKIA) + find_dependency(Threads REQUIRED) + if(MSDFGEN_USE_VCPKG) + find_dependency(unofficial-skia REQUIRED) + else() + find_dependency(skia REQUIRED) + endif() +endif() +if(MSDFGEN_USE_OPENMP) + find_dependency(OpenMP REQUIRED COMPONENTS CXX) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/msdfgenTargets.cmake") + +if(MSDFGEN_CORE_ONLY) + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + set_target_properties(msdfgen::msdfgen-core PROPERTIES IMPORTED_GLOBAL TRUE) + endif() + add_library(msdfgen::msdfgen ALIAS msdfgen::msdfgen-core) +else() + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + set_target_properties(msdfgen::msdfgen-full PROPERTIES IMPORTED_GLOBAL TRUE) + endif() + add_library(msdfgen::msdfgen ALIAS msdfgen::msdfgen-full) +endif() + +if(MSDFGEN_STANDALONE_AVAILABLE) + include("${CMAKE_CURRENT_LIST_DIR}/msdfgenBinaryTargets.cmake") + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + set_target_properties(msdfgen-standalone::msdfgen PROPERTIES IMPORTED_GLOBAL TRUE) + endif() + add_executable(msdfgen::msdfgen-run ALIAS msdfgen-standalone::msdfgen) + set(MSDFGEN_EXECUTABLE "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/msdfgen@CMAKE_EXECUTABLE_SUFFIX@") +endif() diff --git a/Dependencies/msdfgen/msdfgen/cmake/version.cmake b/Dependencies/msdfgen/msdfgen/cmake/version.cmake new file mode 100644 index 00000000..279ace30 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/cmake/version.cmake @@ -0,0 +1,19 @@ + +# This script reads version from vcpkg.json and sets it to ${MSDFGEN_VERSION} etc. + +cmake_minimum_required(VERSION 3.15) + +file(STRINGS "${CMAKE_CURRENT_LIST_DIR}/../vcpkg.json" MSDFGEN_VCPKG_JSON) + +string(REGEX MATCH "\"version\"[ \t\n\r]*:[ \t\n\r]*\"[^\"]*\"" MSDFGEN_TMP_VERSION_PAIR ${MSDFGEN_VCPKG_JSON}) +string(REGEX REPLACE "\"version\"[ \t\n\r]*:[ \t\n\r]*\"([^\"]*)\"" "\\1" MSDFGEN_VERSION ${MSDFGEN_TMP_VERSION_PAIR}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\1" MSDFGEN_VERSION_MAJOR ${MSDFGEN_VERSION}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\2" MSDFGEN_VERSION_MINOR ${MSDFGEN_VERSION}) +string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)" "\\3" MSDFGEN_VERSION_REVISION ${MSDFGEN_VERSION}) +string(LENGTH ${MSDFGEN_VERSION} MSDFGEN_VERSION_LENGTH) +string(REPEAT "-" ${MSDFGEN_VERSION_LENGTH} MSDFGEN_VERSION_UNDERLINE) +string(TIMESTAMP MSDFGEN_COPYRIGHT_YEAR "%Y") + +unset(MSDFGEN_TMP_VERSION_PAIR) +unset(MSDFGEN_VERSION_LENGTH) +unset(MSDFGEN_VCPKG_JSON) diff --git a/Dependencies/msdfgen/msdfgen/core/Bitmap.h b/Dependencies/msdfgen/msdfgen/core/Bitmap.h new file mode 100644 index 00000000..9a08749f --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/Bitmap.h @@ -0,0 +1,50 @@ + +#pragma once + +#include "BitmapRef.hpp" + +namespace msdfgen { + +/// A 2D image bitmap with N channels of type T. Pixel memory is managed by the class. +template +class Bitmap { + +public: + Bitmap(); + Bitmap(int width, int height); + Bitmap(const BitmapConstRef &orig); + Bitmap(const Bitmap &orig); +#ifdef MSDFGEN_USE_CPP11 + Bitmap(Bitmap &&orig); +#endif + ~Bitmap(); + Bitmap &operator=(const BitmapConstRef &orig); + Bitmap &operator=(const Bitmap &orig); +#ifdef MSDFGEN_USE_CPP11 + Bitmap &operator=(Bitmap &&orig); +#endif + /// Bitmap width in pixels. + int width() const; + /// Bitmap height in pixels. + int height() const; + T *operator()(int x, int y); + const T *operator()(int x, int y) const; +#ifdef MSDFGEN_USE_CPP11 + explicit operator T *(); + explicit operator const T *() const; +#else + operator T *(); + operator const T *() const; +#endif + operator BitmapRef(); + operator BitmapConstRef() const; + +private: + T *pixels; + int w, h; + +}; + +} + +#include "Bitmap.hpp" diff --git a/Dependencies/msdfgen/msdfgen/core/Bitmap.hpp b/Dependencies/msdfgen/msdfgen/core/Bitmap.hpp new file mode 100644 index 00000000..94043577 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/Bitmap.hpp @@ -0,0 +1,117 @@ + +#include "Bitmap.h" + +#include +#include + +namespace msdfgen { + +template +Bitmap::Bitmap() : pixels(NULL), w(0), h(0) { } + +template +Bitmap::Bitmap(int width, int height) : w(width), h(height) { + pixels = new T[N*w*h]; +} + +template +Bitmap::Bitmap(const BitmapConstRef &orig) : w(orig.width), h(orig.height) { + pixels = new T[N*w*h]; + memcpy(pixels, orig.pixels, sizeof(T)*N*w*h); +} + +template +Bitmap::Bitmap(const Bitmap &orig) : w(orig.w), h(orig.h) { + pixels = new T[N*w*h]; + memcpy(pixels, orig.pixels, sizeof(T)*N*w*h); +} + +#ifdef MSDFGEN_USE_CPP11 +template +Bitmap::Bitmap(Bitmap &&orig) : pixels(orig.pixels), w(orig.w), h(orig.h) { + orig.pixels = NULL; + orig.w = 0, orig.h = 0; +} +#endif + +template +Bitmap::~Bitmap() { + delete [] pixels; +} + +template +Bitmap &Bitmap::operator=(const BitmapConstRef &orig) { + if (pixels != orig.pixels) { + delete [] pixels; + w = orig.width, h = orig.height; + pixels = new T[N*w*h]; + memcpy(pixels, orig.pixels, sizeof(T)*N*w*h); + } + return *this; +} + +template +Bitmap &Bitmap::operator=(const Bitmap &orig) { + if (this != &orig) { + delete [] pixels; + w = orig.w, h = orig.h; + pixels = new T[N*w*h]; + memcpy(pixels, orig.pixels, sizeof(T)*N*w*h); + } + return *this; +} + +#ifdef MSDFGEN_USE_CPP11 +template +Bitmap &Bitmap::operator=(Bitmap &&orig) { + if (this != &orig) { + delete [] pixels; + pixels = orig.pixels; + w = orig.w, h = orig.h; + orig.pixels = NULL; + } + return *this; +} +#endif + +template +int Bitmap::width() const { + return w; +} + +template +int Bitmap::height() const { + return h; +} + +template +T *Bitmap::operator()(int x, int y) { + return pixels+N*(w*y+x); +} + +template +const T *Bitmap::operator()(int x, int y) const { + return pixels+N*(w*y+x); +} + +template +Bitmap::operator T *() { + return pixels; +} + +template +Bitmap::operator const T *() const { + return pixels; +} + +template +Bitmap::operator BitmapRef() { + return BitmapRef(pixels, w, h); +} + +template +Bitmap::operator BitmapConstRef() const { + return BitmapConstRef(pixels, w, h); +} + +} diff --git a/Dependencies/msdfgen/msdfgen/core/BitmapRef.hpp b/Dependencies/msdfgen/msdfgen/core/BitmapRef.hpp new file mode 100644 index 00000000..cb17f95d --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/BitmapRef.hpp @@ -0,0 +1,41 @@ + +#pragma once + +#include "base.h" + +namespace msdfgen { + +/// Reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object. +template +struct BitmapRef { + + T *pixels; + int width, height; + + inline BitmapRef() : pixels(NULL), width(0), height(0) { } + inline BitmapRef(T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { } + + inline T *operator()(int x, int y) const { + return pixels+N*(width*y+x); + } + +}; + +/// Constant reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object. +template +struct BitmapConstRef { + + const T *pixels; + int width, height; + + inline BitmapConstRef() : pixels(NULL), width(0), height(0) { } + inline BitmapConstRef(const T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { } + inline BitmapConstRef(const BitmapRef &orig) : pixels(orig.pixels), width(orig.width), height(orig.height) { } + + inline const T *operator()(int x, int y) const { + return pixels+N*(width*y+x); + } + +}; + +} diff --git a/Dependencies/msdfgen/msdfgen/core/Contour.cpp b/Dependencies/msdfgen/msdfgen/core/Contour.cpp new file mode 100644 index 00000000..57293dc5 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/Contour.cpp @@ -0,0 +1,90 @@ + +#include "Contour.h" + +#include "arithmetics.hpp" + +namespace msdfgen { + +static double shoelace(const Point2 &a, const Point2 &b) { + return (b.x-a.x)*(a.y+b.y); +} + +void Contour::addEdge(const EdgeHolder &edge) { + edges.push_back(edge); +} + +#ifdef MSDFGEN_USE_CPP11 +void Contour::addEdge(EdgeHolder &&edge) { + edges.push_back((EdgeHolder &&) edge); +} +#endif + +EdgeHolder &Contour::addEdge() { + edges.resize(edges.size()+1); + return edges.back(); +} + +static void boundPoint(double &l, double &b, double &r, double &t, Point2 p) { + if (p.x < l) l = p.x; + if (p.y < b) b = p.y; + if (p.x > r) r = p.x; + if (p.y > t) t = p.y; +} + +void Contour::bound(double &l, double &b, double &r, double &t) const { + for (std::vector::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) + (*edge)->bound(l, b, r, t); +} + +void Contour::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const { + if (edges.empty()) + return; + Vector2 prevDir = edges.back()->direction(1).normalize(true); + for (std::vector::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) { + Vector2 dir = -(*edge)->direction(0).normalize(true); + if (polarity*crossProduct(prevDir, dir) >= 0) { + double miterLength = miterLimit; + double q = .5*(1-dotProduct(prevDir, dir)); + if (q > 0) + miterLength = min(1/sqrt(q), miterLimit); + Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true); + boundPoint(l, b, r, t, miter); + } + prevDir = (*edge)->direction(1).normalize(true); + } +} + +int Contour::winding() const { + if (edges.empty()) + return 0; + double total = 0; + if (edges.size() == 1) { + Point2 a = edges[0]->point(0), b = edges[0]->point(1/3.), c = edges[0]->point(2/3.); + total += shoelace(a, b); + total += shoelace(b, c); + total += shoelace(c, a); + } else if (edges.size() == 2) { + Point2 a = edges[0]->point(0), b = edges[0]->point(.5), c = edges[1]->point(0), d = edges[1]->point(.5); + total += shoelace(a, b); + total += shoelace(b, c); + total += shoelace(c, d); + total += shoelace(d, a); + } else { + Point2 prev = edges.back()->point(0); + for (std::vector::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) { + Point2 cur = (*edge)->point(0); + total += shoelace(prev, cur); + prev = cur; + } + } + return sign(total); +} + +void Contour::reverse() { + for (int i = (int) edges.size()/2; i > 0; --i) + EdgeHolder::swap(edges[i-1], edges[edges.size()-i]); + for (std::vector::iterator edge = edges.begin(); edge != edges.end(); ++edge) + (*edge)->reverse(); +} + +} diff --git a/Dependencies/msdfgen/msdfgen/core/Contour.h b/Dependencies/msdfgen/msdfgen/core/Contour.h new file mode 100644 index 00000000..4cae48fa --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/Contour.h @@ -0,0 +1,34 @@ + +#pragma once + +#include +#include "EdgeHolder.h" + +namespace msdfgen { + +/// A single closed contour of a shape. +class Contour { + +public: + /// The sequence of edges that make up the contour. + std::vector edges; + + /// Adds an edge to the contour. + void addEdge(const EdgeHolder &edge); +#ifdef MSDFGEN_USE_CPP11 + void addEdge(EdgeHolder &&edge); +#endif + /// Creates a new edge in the contour and returns its reference. + EdgeHolder &addEdge(); + /// Adjusts the bounding box to fit the contour. + void bound(double &l, double &b, double &r, double &t) const; + /// Adjusts the bounding box to fit the contour border's mitered corners. + void boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const; + /// Computes the winding of the contour. Returns 1 if positive, -1 if negative. + int winding() const; + /// Reverses the sequence of edges on the contour. + void reverse(); + +}; + +} diff --git a/Dependencies/msdfgen/msdfgen/core/DistanceMapping.cpp b/Dependencies/msdfgen/msdfgen/core/DistanceMapping.cpp new file mode 100644 index 00000000..526e1290 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/DistanceMapping.cpp @@ -0,0 +1,27 @@ + +#include "DistanceMapping.h" + +namespace msdfgen { + +DistanceMapping DistanceMapping::inverse(Range range) { + double rangeWidth = range.upper-range.lower; + return DistanceMapping(rangeWidth, range.lower/(rangeWidth ? rangeWidth : 1)); +} + +DistanceMapping::DistanceMapping() : scale(1), translate(0) { } + +DistanceMapping::DistanceMapping(Range range) : scale(1/(range.upper-range.lower)), translate(-range.lower) { } + +double DistanceMapping::operator()(double d) const { + return scale*(d+translate); +} + +double DistanceMapping::operator()(Delta d) const { + return scale*d.value; +} + +DistanceMapping DistanceMapping::inverse() const { + return DistanceMapping(1/scale, -scale*translate); +} + +} diff --git a/Dependencies/msdfgen/msdfgen/core/DistanceMapping.h b/Dependencies/msdfgen/msdfgen/core/DistanceMapping.h new file mode 100644 index 00000000..fadbefa5 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/DistanceMapping.h @@ -0,0 +1,36 @@ + +#pragma once + +#include "Range.hpp" + +namespace msdfgen { + +/// Linear transformation of signed distance values. +class DistanceMapping { + +public: + /// Explicitly designates value as distance delta rather than an absolute distance. + class Delta { + public: + double value; + inline explicit Delta(double distanceDelta) : value(distanceDelta) { } + inline operator double() const { return value; } + }; + + static DistanceMapping inverse(Range range); + + DistanceMapping(); + DistanceMapping(Range range); + double operator()(double d) const; + double operator()(Delta d) const; + DistanceMapping inverse() const; + +private: + double scale; + double translate; + + inline DistanceMapping(double scale, double translate) : scale(scale), translate(translate) { } + +}; + +} diff --git a/Dependencies/msdfgen/msdfgen/core/EdgeColor.h b/Dependencies/msdfgen/msdfgen/core/EdgeColor.h new file mode 100644 index 00000000..5d3730c9 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/EdgeColor.h @@ -0,0 +1,20 @@ + +#pragma once + +#include "base.h" + +namespace msdfgen { + +/// Edge color specifies which color channels an edge belongs to. +enum EdgeColor { + BLACK = 0, + RED = 1, + GREEN = 2, + YELLOW = 3, + BLUE = 4, + MAGENTA = 5, + CYAN = 6, + WHITE = 7 +}; + +} diff --git a/Dependencies/msdfgen/msdfgen/core/EdgeHolder.cpp b/Dependencies/msdfgen/msdfgen/core/EdgeHolder.cpp new file mode 100644 index 00000000..f552e98f --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/EdgeHolder.cpp @@ -0,0 +1,67 @@ + +#include "EdgeHolder.h" + +namespace msdfgen { + +void EdgeHolder::swap(EdgeHolder &a, EdgeHolder &b) { + EdgeSegment *tmp = a.edgeSegment; + a.edgeSegment = b.edgeSegment; + b.edgeSegment = tmp; +} + +EdgeHolder::EdgeHolder(const EdgeHolder &orig) : edgeSegment(orig.edgeSegment ? orig.edgeSegment->clone() : NULL) { } + +#ifdef MSDFGEN_USE_CPP11 +EdgeHolder::EdgeHolder(EdgeHolder &&orig) : edgeSegment(orig.edgeSegment) { + orig.edgeSegment = NULL; +} +#endif + +EdgeHolder::~EdgeHolder() { + delete edgeSegment; +} + +EdgeHolder &EdgeHolder::operator=(const EdgeHolder &orig) { + if (this != &orig) { + delete edgeSegment; + edgeSegment = orig.edgeSegment ? orig.edgeSegment->clone() : NULL; + } + return *this; +} + +#ifdef MSDFGEN_USE_CPP11 +EdgeHolder &EdgeHolder::operator=(EdgeHolder &&orig) { + if (this != &orig) { + delete edgeSegment; + edgeSegment = orig.edgeSegment; + orig.edgeSegment = NULL; + } + return *this; +} +#endif + +EdgeSegment &EdgeHolder::operator*() { + return *edgeSegment; +} + +const EdgeSegment &EdgeHolder::operator*() const { + return *edgeSegment; +} + +EdgeSegment *EdgeHolder::operator->() { + return edgeSegment; +} + +const EdgeSegment *EdgeHolder::operator->() const { + return edgeSegment; +} + +EdgeHolder::operator EdgeSegment *() { + return edgeSegment; +} + +EdgeHolder::operator const EdgeSegment *() const { + return edgeSegment; +} + +} diff --git a/Dependencies/msdfgen/msdfgen/core/EdgeHolder.h b/Dependencies/msdfgen/msdfgen/core/EdgeHolder.h new file mode 100644 index 00000000..5ae2dc23 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/EdgeHolder.h @@ -0,0 +1,41 @@ + +#pragma once + +#include "edge-segments.h" + +namespace msdfgen { + +/// Container for a single edge of dynamic type. +class EdgeHolder { + +public: + /// Swaps the edges held by a and b. + static void swap(EdgeHolder &a, EdgeHolder &b); + + inline EdgeHolder() : edgeSegment() { } + inline EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { } + inline EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, edgeColor)) { } + inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, edgeColor)) { } + inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, p3, edgeColor)) { } + EdgeHolder(const EdgeHolder &orig); +#ifdef MSDFGEN_USE_CPP11 + EdgeHolder(EdgeHolder &&orig); +#endif + ~EdgeHolder(); + EdgeHolder &operator=(const EdgeHolder &orig); +#ifdef MSDFGEN_USE_CPP11 + EdgeHolder &operator=(EdgeHolder &&orig); +#endif + EdgeSegment &operator*(); + const EdgeSegment &operator*() const; + EdgeSegment *operator->(); + const EdgeSegment *operator->() const; + operator EdgeSegment *(); + operator const EdgeSegment *() const; + +private: + EdgeSegment *edgeSegment; + +}; + +} diff --git a/Dependencies/msdfgen/msdfgen/core/MSDFErrorCorrection.cpp b/Dependencies/msdfgen/msdfgen/core/MSDFErrorCorrection.cpp new file mode 100644 index 00000000..7639dc68 --- /dev/null +++ b/Dependencies/msdfgen/msdfgen/core/MSDFErrorCorrection.cpp @@ -0,0 +1,494 @@ + +#include "MSDFErrorCorrection.h" + +#include +#include "arithmetics.hpp" +#include "equation-solver.h" +#include "EdgeColor.h" +#include "bitmap-interpolation.hpp" +#include "edge-selectors.h" +#include "contour-combiners.h" +#include "ShapeDistanceFinder.h" +#include "generator-config.h" + +namespace msdfgen { + +#define ARTIFACT_T_EPSILON .01 +#define PROTECTION_RADIUS_TOLERANCE 1.001 + +#define CLASSIFIER_FLAG_CANDIDATE 0x01 +#define CLASSIFIER_FLAG_ARTIFACT 0x02 + +MSDFGEN_PUBLIC const double ErrorCorrectionConfig::defaultMinDeviationRatio = 1.11111111111111111; +MSDFGEN_PUBLIC const double ErrorCorrectionConfig::defaultMinImproveRatio = 1.11111111111111111; + +/// The base artifact classifier recognizes artifacts based on the contents of the SDF alone. +class BaseArtifactClassifier { +public: + inline BaseArtifactClassifier(double span, bool protectedFlag) : span(span), protectedFlag(protectedFlag) { } + /// Evaluates if the median value xm interpolated at xt in the range between am at at and bm at bt indicates an artifact. + inline int rangeTest(double at, double bt, double xt, float am, float bm, float xm) const { + // For protected texels, only consider inversion artifacts (interpolated median has different sign than boundaries). For the rest, it is sufficient that the interpolated median is outside its boundaries. + if ((am > .5f && bm > .5f && xm <= .5f) || (am < .5f && bm < .5f && xm >= .5f) || (!protectedFlag && median(am, bm, xm) != xm)) { + double axSpan = (xt-at)*span, bxSpan = (bt-xt)*span; + // Check if the interpolated median's value is in the expected range based on its distance (span) from boundaries a, b. + if (!(xm >= am-axSpan && xm <= am+axSpan && xm >= bm-bxSpan && xm <= bm+bxSpan)) + return CLASSIFIER_FLAG_CANDIDATE|CLASSIFIER_FLAG_ARTIFACT; + return CLASSIFIER_FLAG_CANDIDATE; + } + return 0; + } + /// Returns true if the combined results of the tests performed on the median value m interpolated at t indicate an artifact. + inline bool evaluate(double t, float m, int flags) const { + return (flags&2) != 0; + } +private: + double span; + bool protectedFlag; +}; + +/// The shape distance checker evaluates the exact shape distance to find additional artifacts at a significant performance cost. +template